CoreSourcery G++ 4.5.1 (GCC 4.3.2ベース)で、64bit int値を使うとどんなコードが出るのか見てみた。CPUはSTM32(Cortex-M3)。
; volatile uint64_t a,b;
push {r4, r5, r6, lr}
ldr r6, .L5+8
; a = 0;
movs r0, #0
movs r1, #0
strd r0, [r6]
; a++;
movs r0, #1
ldrd r2, [r6]
movs r1, #0
adds r2, r2, r0
adc r3, r3, r1
strd r2, [r6]
; a = a + 2;
movs r4, #2
ldrd r2, [r6]
movs r5, #0
adds r2, r2, r4
adc r3, r3, r5
strd r2, [r6]
こんなふうにLDRD/STRD命令を使って、割とコンパクトなコードになってるし、なにより、ロード/ストアが atomic だ(だよね・・・? →後述。アトミックじゃなかった)。
(某社オリジナルコア32bitCPU用のGCCでは、64bit値使ったら、いちいちライブラリをコールしてやがったので、不安になって、チェックしたのです…)
しかし、LDRD/STRD命令は、8バイト境界でないところに使ってしまうと、ARMコアがFAULTするので注意が必要だ。
Cortex-M3(ARM v7-Mアーキテクチャ)は、奇数アドレスからの16bit/32bitデータアクセスが出来る(サイクルは余計にかかるが。なお、ARM7は出来ない)ので、油断していた・・・すこし、ハマった・・・。
注:アンアラインドデータアクセスは単一ロード/ストア命令(LDR/STR)でしか利用できない。コンパイラによっては単純なポインタアクセスでLDM/STM命令を使ってくれたりしてFAULTするので(KEIL…)、この機構に期待しない方が安全だ・・・。
・・・Cortex-M3でも、LDRD/STRD命令は、アトミックってことでいいんだろうか?
マニュアルには、LDM/STMは割り込み中断・再開できるのでレイテンシが改善してると書いてあるけど、LDRD/STRDは割り込まれないんだろうか?
・・・マニュアルに書いてあるのはLDM/STM, PUSH/POPについてだけだから、LDRD/STRDは大丈夫なんじゃないかと思うんだけど・・・。
→うーんでも http://www.yokogawa-digital.com/arm/support/faq/index.php?VER-B-09 に 「ARM v7M 及び v7EM のコアに於いて、LDRD/STRD 命令はシングルコピーの最小単位(atomic)ではありません」[SDCOMP-14812]って書かれててるなあ…アトミックじゃないのかなあ。
→Cortex-M3 テクニカルマニュアルの ETMの項に、 ETMCANCEL ポートの説明として、
現在実行されているオペコードがキャンセルされました。割り込みされたオペコードは、この実行コンテキストに復帰したときに再始動または続行されます。これには、次のオペコードが含まれます。
LDR/STR
LDRD/STRD
LDM/STM
U/SMULL
MLA
U/SDIV
MSR
CPSID
とあるな…。じゃあ、LDRD/STRDもアトミックじゃないのか…。がっかり。