continue 文の次に実行されるのは? [PSoC]
Twitterで、お題をいただきました。 これは、いっちょ試してみなくては。 題材に取り上げたのは、 Cortex-M0 搭載の PSoC 4 M-Series です。
GCC の場合
まず、 PSoC Creator のデフォルトツールチェインである GCC で試しました。 使用したコードは以下の通りです。
int main(void) { CyGlobalIntEnable; /* Enable global interrupts. */ for (;;) { int i; for (i = 0; i < 10; ++i) { if (i == 0) continue; } } }
for 行の中に変数宣言が入れられないので、外で宣言しています。 あれ、もしかしたら、これは C のお題じゃなかったのかな? 気にせず、 LST ファイルを見てみます。
30 0000 62B6 CPSIE i 33 .L4: 37 0002 0023 mov r3, #0 38 0004 00E0 b .L2 40 .L3: 42 0006 0133 add r3, r3, #1 44 .L2: 46 0008 092B cmp r3, #9 47 000a FCDD ble .L3 48 000c F9E7 b .L4
変数 i は、 r3 に割り当てられています。 i を 0 と比較する部分は、存在しません。 すでに最適化されてしまっているようです。
continue 文の次に実行されるものは、そもそも if 文さえ存在しないので、問い自体が無意味である。
最適化しない GCC の場合
この結論じゃ面白くないので、最適化されないように -O0 オプションを付けました。
28 0000 80B5 push {r7, lr} 32 0002 82B0 sub sp, sp, #8 34 0004 00AF add r7, sp, #0 38 0006 62B6 CPSIE i 41 .L5: 44 0008 0023 mov r3, #0 45 000a 7B60 str r3, [r7, #4] 46 000c 06E0 b .L2 47 .L4: 49 000e 7B68 ldr r3, [r7, #4] 50 0010 002B cmp r3, #0 51 0012 00D1 bne .L3 52 0014 C046 mov r8, r8 53 .L3: 55 0016 7B68 ldr r3, [r7, #4] 56 0018 0133 add r3, r3, #1 57 001a 7B60 str r3, [r7, #4] 58 .L2: 60 001c 7B68 ldr r3, [r7, #4] 61 001e 092B cmp r3, #9 62 0020 F5DD ble .L4 65 0022 F1E7 b .L5
すると、変数をレジスタに割り当てる事もしないコンパイル結果となりました。 i を 0 と比較する部分は、50行目にあります。 その後、51行目の "bne" で条件分岐を行います。 continue 文に相当するのは、52行目の "mov r8, r8" です。 その後は、55行目から始まる ++i が実行されます。 つまり、 continue 文の次に実行されるのは、 "++i" であるという事がわかりました。
continue 文の次に実行されるものは、 ++i である。
MDK-ARM の場合
同じプロジェクトを MDK-ARM でコンパイルしてみました。
0x000006E4 BF00 NOP 0x000006E6 B662 CPSIE I 0x000006E8 BF00 NOP 0x000006EA BF00 NOP 0x000006EC 2000 MOVS r0,#0x00 0x000006EE E004 B 0x000006FA 0x000006F0 2800 CMP r0,#0x00 0x000006F2 D100 BNE 0x000006F6 0x000006F4 E000 B 0x000006F8 0x000006F6 BF00 NOP 0x000006F8 1C40 ADDS r0,r0,#1 0x000006FA 280A CMP r0,#0x0A 0x000006FC DBF8 BLT 0x000006F0 0x000006FE E7F5 B 0x000006EC
機能制限版では、 LST ファイルが出力されないようなので、デバッガの "Disassembly" ウィンドウから取ってきました。 変数 i は、 r0 に割り当てられています。
if 文は 0x000006F0 番地にあります。 continue 文に相当するのは、 0x000006F4 番地の "B 0x000006F8" です。 分岐先の 0x000006F8 番地には、 ++i があります。
continue 文の次に実行されるものは、 ++i である。
IAR Embedded Workbench の場合
IAR のコンパイラでも、同じようにコンパイルしてみました。
\ main: (+1) \ 00000000 0xB500 PUSH {LR} \ 00000002 0xB662 CPSIE i \ ??main_0: (+1) \ 00000004 0x2000 MOVS R0,#+0 \ ??main_1: (+1) \ 00000006 0x280A CMP R0,#+10 \ 00000008 0xDAFC BGE ??main_0 \ 0000000A 0x2800 CMP R0,#+0 \ ??main_2: (+1) \ 0000000C 0x1C40 ADDS R0,R0,#+1 \ 0000000E 0xE7FA B ??main_1
変数 i は、 R0 レジスタに割り当てられています。 変数 i と 0 を比較する部分は、 0000000A 番地の "CMP R0,#+0" です。 しかし、比較をしているだけで後に続く条件分岐が見当たりません。 次に実行されるのは、 0000000C 番地の ++i です。
continue 文に相当する部分が存在しないが、結果的に次に実行されるものは、 ++i である。
最適化をがんばったら
これまでは、 "-O0" オプションで最適化を抑制していました。 普通は、多少の最適化を行わせますので、ためしに GCC の再弱最適化オプションである "-O1" を使ってコンパイルさせてみました。
30 0000 62B6 CPSIE i 33 .L2: 35 0002 FEE7 b .L2
すると、最適化の結果、何も残りませんでした。 後にあるのは、一番外側の無限ループのみです。
最適化されると、 for 文がまるごと省略される。
関連商品
PSoC 4200M CY8CKIT-043 Prototyping Kit
- 出版社/メーカー: スイッチサイエンス
- メディア: エレクトロニクス
コメント 0