rx-elf-gccでvolatileつけた変数の参照、変更した時のコードを覗いてみました。
試したソースはこれです。
volatile
unsigned
char bar1;
volatile
unsigned
char bar;
void
tst_bar_bit0(void)
{
   if(bar1&1)
        bar &= ~1;
  else
        bar |= 1;
}
rx-elf-gccで-O2 -fomitframe-pointerでコンパイルすると
                                                            _tst_bar_bit0:
0000 FB E2 00 00 00 00        mov.L   #_bar1, r14
0006 CC EE                    mov.B   [r14], r14
0008 FD 74 CE 01              tst     #1, r14
000c FB E2 00 00 00 00        mov.L   #_bar, r14
0012 CC E4                    mov.B   [r14], r4
0014 1E                       bne     .L5
0015 65 14                    or      #1, r4
0017 C3 E4                    mov.B   r4, [r14]
0019 02                       rts
                                                            .L5:
001a 75 24 FE                 and     #-2, r4
001d C3 E4                    mov.B   r4, [r14]
001f 02                       rts
こうなります。
volatileつけた変数を参照、変更してるから、最適化は無効になってるのかと思いきや、最適化されてます。
で、巷でよく聞くメモリバリアというのをソースに埋め込んでみました。
void
tst_bar_bit0(void)
{
    if(bar1&1)
     {
       __asm volatile (";memory1":::"memory");
       bar &= ~1;
     }
      else
     {
       __asm volatile (";memory2":::"memory");
           bar |= 1;
     }
}
                           _tst_bar_bit0:
0000 FB E2 00 00 00 00                            mov.L   #_bar1, r14
0006 CC EE                                                    mov.B   [r14], r14
0008 FD 74 CE 01                                        tst     #1, r14
000c 1A                                                          bne     .L5
                          ; 32 "tst1b.c" 1
                          ;memory2
                          ; 0 "" 2
000d FB E2 00 00 00 00        mov.L   #_bar, r14
  0013 F0 E0                                                    bset    #0, [r14].B
  0015 02                                                          rts
                          .L5:
                         ; 27 "tst1b.c" 1
                         ;memory1
                         ; 0 "" 2
  0016 FB E2 00 00 00 00                            mov.L   #_bar, r14
  001c F0 E8                                                    bclr    #0, [r14].B
  001e 02                                                          rts
今度は期待した通りのコードになっています。
分岐を最適化するオプション-fcrossjumpingというのがあるので
それを無効にするように-fno-crossjumpingで元々のソースをコンパイルすると
0000 FB E2 00 00 00 00        mov.L   #_bar1, r14
0006 CC EE                    mov.B   [r14], r14
0008 FD 74 CE 01              tst     #1, r14
000c 1A                       bne     .L5
000d FB E2 00 00 00 00        mov.L   #_bar, r14
0013 F0 E0                    bset    #0, [r14].B
0015 02                       rts
                       .L5:
0016 FB E2 00 00 00 00        mov.L   #_bar, r14
001c F0 E8                    bclr    #0, [r14].B
001e 02                       rts
こうなりました。
(素のgccのソースでビルドしたgccではbset,bclrのコードは出ませんので)
volatile付けると最適化抑止になると思いきや、こういうことがあるんですね。
archによっては、-fcrossjumpingが無効になってるものもあるようです。
ちなみに、mips-elf-gccだとこうなりました。
 0000 93820000         lbu    $2,%gp_rel(bar1)($28)
0004 00000000         nop
0008 30420001         andi   $2,$2,0x1
000c 14400008         bne    $2,$0,$L5
0010 00000000         nop
0014 93820000         lbu    $2,%gp_rel(bar)($28)
0018 00000000         nop
001c 304200FF         andi   $2,$2,0x00ff
0020 34420001         ori    $2,$2,0x1
0024 A3820000         sb     $2,%gp_rel(bar)($28)
0028 03E00008         j      $31
002c 00000000         nop
                 $L5:
0030 93820000         lbu    $2,%gp_rel(bar)($28)
0034 00000000         nop
0038 304200FE         andi   $2,$2,0xfe
003c A3820000         sb     $2,%gp_rel(bar)($28)
0040 03E00008         j      $31
0044 00000000         nop
[0回]
PR