試したソースはこれです。
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
こうなります。
色の付いたところが2箇所あるから一箇所にするというのが
-fcrossjumpingの最適化のようです。
volatile付けてるから
mov.B   [r14], r4
は、共有されてほしくない。
しょうがないので、gccのソースを眺めてみました。
-fcrossjumpingの処理をしてるのは、cfgcleanup.cというのがわかりました。
色々試したみたところ、その中のold_insns_match_p関数でコードの比較をしています。
volatileなメモリの読み書きしている時の判定を追加します。
                        _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 1C                     bne    .L5
0013 F0 E0                  bset    #0, [r14].B
0015 02                     rts
                        .L5:
0016 F0 E8                  bclr    #0, [r14].B
0018 02                     rts
共有部分が一行になり、自前のpeephole2の処理が機能するようになりました。
 [0回]
[0回]
PR