忍者ブログ

なんだか

知らないほうが幸せかもしれない

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

rx-elf-gccで分岐の最適化を眺めてみる

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

v850-elf-gccでこんなことやってみました


volatile
unsigned char foo;
void
bit0_set(void)
{
foo |=1;
}

上のソースだと

0000 2A0600000000 mov hilo(_foo),r10
0006 0A5F0000     ld.b 0[r10],r11
000a 8B00         zxb r11
000c 8B5E0100     ori 1,r11,r11
0010 4A5F0000     st.b r11,0[r10]
0014 7F00         jmp [r31]

こうなるのを

0000 2A0600000000 mov hilo(_foo),r10
0006 CA070000     set1 0,0[r10]
000a 7F00         jmp [r31]

こうしてみました。

bitmemv850.patch 危険がいっぱい?

拍手[0回]

sh-elf-gccでこんなことできたらいいな

sh-elf-gccだと-m2aで-mbitopsオプションをbit操作命令を使ってくれるのですが

char foo;
void
bit0_set(void)
{
  foo |=1;
}


これだと

0000 D103 mov.l .L2,r1
0002 6010 mov.b @r1,r0
0004 600C extu.b r0,r0
0006 CB01 or #1,r0
0008 2100 mov.b r0,@r1
000a 000B rts
000c 0009 nop


こういうコードになります。
(遅延分岐がおかしいのはgccの4.8だと直っています。)

sh2a以外でもgbrがいつも0なら

0000 D001 mov.l .L2,r0
0002 000B rts
0004 CF01 or.b #1,@(r0,gbr)

こういうことが出来るんじゃないかと


bitmemgbr.patch 非常に危険?

拍手[0回]

rx-elfのgccをちょっと賢くする、続き


前のpatchだけでは、rx-elf-gccは、以下の場合にbit操作命令を使いません。

volatile char foo;
void
bit0_set(void)
{
  foo |=1;
}


gccの挙動がvolatile属性の時は、

メモリからロード
演算
メモリにストア

になるからです。この場合は、peephole2で

(set (mem/j/c:QI (reg/f:SI 24) [0+0 S1 A8])
(ior:QI (mem/j/c:QI (reg/f:SI 24) [0+0 S1 A8])
(const_int 1 [0x1])))

このパターンに変換するようにします。

bitmemvol.patch 危ないから見ないほうがよい

拍手[0回]

rx-elfのgccをちょっと賢くする

rxのマイコンにはメモリに対するbit操作命令があるのですが

char foo;
void
bit0_set(void)
{
  foo |=1;
}


こういうことをやろうとする、rx-elf-gccは

0000 FB E2 00 00 00 00 mov.L #_foo, r14
0006 CC E4             mov.B [r14], r4
0008 65 14             or #1, r4
000a C3 E4             mov.B r4, [r14]

なぜか、こういう上のコードを出力しています。

rx.mdにはbit操作命令を使うような記述はあるのですが、無視されています。

0000 FB E2 00 00 00 00 mov.L   #_foo, r14
0006 F0 E0             bset    #0, [r14].B

(set (mem/c:QI (reg/f:SI 26) [0 foo+0 S1 A8])
    (subreg:QI (ior:SI (subreg:SI (mem/c:QI (reg/f:SI 26) [0 foo+0 S1 A8]) 0)
            (const_int 1 [0x1])) 0))

これは、上の命令パターンを認識できていないために起こっています。

この命令パターン認識される記述は下のようになります。

(define_insn "*bitset_in_memory_little"
  [(set (match_operand:QI 0 "rx_restricted_mem_operand" "+Q")
       (subreg:QI (ior:SI (subreg:SI (match_dup 0) 0)
                          (match_operand:QI 1 "const_int_operand" "i")) 0))]
  "exact_log2 (INTVAL (operands[1]) & 0xff) >= 0
   && exact_log2 (INTVAL (operands[1]) & 0xff) <= 7"
  "*
{
  rtx xoperands[2];
  xoperands[0] = operands[0];
  xoperands[1] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff));
  output_asm_insn (\"bset\\t%1, %0.B\", xoperands);
  return \"\";
}
  "
  [(set_attr "length" "3")
   (set_attr "timings" "33")]
)

今度は、コンパイル時に-mbig-endian-dataをつけた場合を考えてみます。

(set (mem/c:QI (reg/f:SI 26) [0 foo+0 S1 A8])
    (subreg:QI (ior:SI (subreg:SI (mem/c:QI (reg/f:SI 26) [0 foo+0 S1 A8]) 0)
            (const_int 1 [0x1])) 3))

このパターンを認識される記述はこうなります。

(define_insn "*bitset_in_memory_big"
  [(set (match_operand:QI 0 "rx_restricted_mem_operand" "+Q")
       (subreg:QI (ior:SI (subreg:SI (match_dup 0) 0)
                          (match_operand:QI 1 "const_int_operand" "i")) 3))]
  "exact_log2 (INTVAL (operands[1]) & 0xff) >= 0
   && exact_log2 (INTVAL (operands[1]) & 0xff) <= 7"
  "*
{
  rtx xoperands[2];
  xoperands[0] = operands[0];
  xoperands[1] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff));
  output_asm_insn (\"bset\\t%1, %0.B\", xoperands);
  return \"\";
}
  "
  [(set_attr "length" "3")
   (set_attr "timings" "33")]
)


この記述方法は、v850.mdの記述を参考にしています。

次に、ビットフィールドの時の場合を考えてみます。

union
{
  unsigned char BYTE;
  struct
  {
#ifdef __RX_BIG_ENDIAN__
    unsigned char B7:1;
    unsigned char B6:1;
    unsigned char B5:1;
    unsigned char B4:1;
    unsigned char B3:1;
    unsigned char B2:1;
    unsigned char B1:1;
    unsigned char B0:1;
#else
    unsigned char B0:1;
    unsigned char B1:1;
    unsigned char B2:1;
    unsigned char B3:1;
    unsigned char B4:1;
    unsigned char B5:1;
    unsigned char B6:1;
    unsigned char B7:1;
#endif
  } BIT;

void
set_bit0(void)
{
  foo.BIT.B0 = 1;
}

0000 FB E2 00 00 00 00                     mov.L   #_foo, r14
0006 CC E4                                 mov.B   [r14], r4
0008 78 04                                 bset    #0, r4
000a C3 E4                                 mov.B   r4, [r14]

この時に、必要な記述は
(set (mem/j/c:QI (reg/f:SI 24) [0+0 S1 A8])
    (ior:QI (mem/j/c:QI (reg/f:SI 24) [0+0 S1 A8])
        (const_int 1 [0x1])))

こうなので

(define_insn "*bitset_in_memory_bitfiled"
  [(set (match_operand:QI 0 "rx_restricted_mem_operand" "+Q")
        (ior:QI (match_dup 0)
                (match_operand:QI 1 "const_int_operand" "i")))]
  "exact_log2 (INTVAL (operands[1]) & 0xff) >= 0
   && exact_log2 (INTVAL (operands[1]) & 0xff) <= 7"
  "*
{
  rtx xoperands[2];
  xoperands[0] = operands[0];
  xoperands[1] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff));
  output_asm_insn (\"bset\\t%1, %0.B\", xoperands);
  return \"\";
}
  "
  [(set_attr "length" "3")
   (set_attr "timings" "33")]
)

記述はこうなります。この場合、エンディアンは無視できます。

bitmem.patch

bclr,bnotを使えるようにしました。

拍手[0回]

カレンダー

10 2024/11 12
S M T W T F S
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

フリーエリア

最新CM

最新記事

(07/27)
(03/27)
(03/26)
(03/23)
(03/22)
(03/19)
(03/18)
(03/18)
(03/15)
(03/14)
(03/13)
(03/12)
(03/11)
(03/11)
(03/08)
(03/08)
(03/06)
(03/05)
(03/02)
(03/01)
(02/28)
(02/27)
(02/24)
(02/23)
(02/22)

プロフィール

HN:
kenrou
性別:
非公開

バーコード

ブログ内検索

最古記事

(12/15)
(12/16)
(12/17)
(12/18)
(12/19)
(12/20)
(12/21)
(12/22)
(12/23)
(12/24)
(12/25)
(12/26)
(12/27)
(12/28)
(12/29)
(12/30)
(12/31)
(01/01)
(01/02)
(01/21)
(01/22)
(01/23)
(01/24)
(01/24)
(01/28)

P R

忍者アナライズ

コガネモチ

忍者カウンター

カレンダー

10 2024/11 12
S M T W T F S
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30