忍者ブログ

なんだか

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

[PR]

×

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

rx-elf-gcc(4.7.2)でbtst命令を使うようにしてみようという試み、その3

試したのはこれです。shortでbit1です。

/*volatile*/
unsigned
short bar1;

/*volatile*/
unsigned
short bar;

void
tst_bar_bit1(void)
{
if(bar1&2)
bar &= ~2;
else
bar |= 2;
}


rx-elf-gccで-O2 -fomitframe-pointerでコンパイルすると

0000 FB E2 00 00 00 00     mov.L #_bar1, r14
0006 DC EE                 mov.W [r14], r14
0008 64 2E                 and #2, r14
000a 5F EE                 movu.W r14, r14
000c 61 0E                 cmp #0, r14
000e FB E2 00 00 00 00   mov.L #_bar, r14
0014 DC E4                 mov.W [r14], r4
0016 1E                    bne .L5
0017 65 24                 or #2, r4
0019 D3 E4                 mov.W r4, [r14]
001b 02                    rts
                       .L5:
001c 75 24 FD              and #-3, r4
001f D3 E4                 mov.W r4, [r14]
0021 02                    rts

色の付いたところをbtst命令を使うようにしてみます。

Failed to match this instruction:
(set (pc)
    (if_then_else (eq (if_then_else:SI (zero_extract:SI (subreg:SI (reg:HI 31 [ bar1 ]) 0)
                    (const_int 1 [0x1])
                    (const_int 1 [0x1]))
                (const_int 2 [0x2])
                (const_int 0 [0]))
            (const_int 0 [0]))
        (label_ref 20)
        (pc)))

このコンバインパターンを成功するように

(define_insn_and_split "*cbranchhi4_tst_ext"
  [(set (pc)
    (if_then_else
      (match_operator 4 "rx_z_comparison_operator"
        [ (if_then_else:SI
               (zero_extract:SI
           (subreg:SI
                  (match_operand:HI 0 "register_operand" "r")
                   0)
           (match_operand    1 "rx_constshift_operand" "")
           (match_operand    2 "rx_constshift_operand" ""))
               (match_operand 5 "const_int_operand" "")
               (const_int 0))
         (const_int 0)])
      (match_operand 3 "label_ref_operand" "")
      (pc)))]
  "INTVAL (operands[1]) == 1"
  "#"
  "reload_completed"
  [(const_int 0)]
{
  HOST_WIDE_INT mask;
  rtx x;

  mask = 1;
  mask <<= INTVAL (operands[1]);
  mask -= 1;
  mask <<= INTVAL (operands[2]);

  operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));

  x = gen_rtx_AND (SImode, operands[0], gen_int_mode (mask, SImode));

  rx_split_cbranch (CC_ZSmode, GET_CODE (operands[4]),
            x, const0_rtx, operands[3]);
  DONE;
})

これをrx.mdのその2の前あたりに追加します。

この変更を使ったgccでコンパイルすると

0000 FB E2 00 00 00 00     mov.L   #_bar1, r14
0006 DC EE                 mov.W   [r14], r14
0008 7C 1E                 btst    #1, r14
000a FB E2 00 00 00 00     mov.L   #_bar, r14
0010 DC E4                 mov.W   [r14], r4
0012 1E                    bne     .L5
0013 65 24                 or      #2, r4
0015 D3 E4                 mov.W   r4, [r14]
0017 02                    rts
                       .L5:
0018 75 24 FD              and     #-3, r4
001b D3 E4                 mov.W   r4, [r14]
001d 02                    rts

こうなります。

拍手[0回]

PR

rx-elf-gcc(4.7.2)でbtst命令を使うようにしてみようという試み、その2

試したのはこれです。今回はbit1です。

/*volatile*/
unsigned
char bar1;

/*volatile*/
unsigned
char bar;

void
tst_bar_bit1(void)
{
  if(bar1&2)
    bar &= ~2;
  else
    bar |= 2;
}


rx-elf-gccで-O2 -fomitframe-pointerでコンパイルすると

0000 FB E2 00 00 00 00    mov.L   #_bar1, r14
0006 CC EE                mov.B   [r14], r14
0008 64 2E                and     #2, r14
000a 5B EE                movu.B  r14, r14
000c 61 0E                cmp     #0, r14
000e FB E2 00 00 00 00    mov.L   #_bar, r14
0014 1C                   bne     .L5
0015 F0 E1                bset    #1, [r14].B
0017 02                   rts
                      .L5:
0018 F0 E9                bclr    #1, [r14].B
001a 02                   rts


こうなります。(注:改造したrx-elf-gccを使っているので出力コードが違うことがあります)
色の付いたところをbtst命令を使うようにしてみます。

Failed to match this instruction:
(set (pc)
    (if_then_else (eq (if_then_else:SI (zero_extract:SI (subreg:SI (reg:QI 31 [ bar1 ]) 0)
                    (const_int 1 [0x1])
                    (const_int 1 [0x1]))
                (const_int 2 [0x2])
                (const_int 0 [0]))
            (const_int 0 [0]))
        (label_ref 21)
        (pc)))


コンバインパターンを成功するように

(define_insn_and_split "*cbranchqi4_tst_ext"
  [(set (pc)
    (if_then_else
      (match_operator 4 "rx_z_comparison_operator"
        [ (if_then_else:SI
               (zero_extract:SI
           (subreg:SI
                  (match_operand:QI 0 "register_operand" "r")
                   0)
           (match_operand    1 "rx_constshift_operand" "")
           (match_operand    2 "rx_constshift_operand" ""))
               (match_operand 5 "const_int_operand" "")
               (const_int 0))
         (const_int 0)])
      (match_operand 3 "label_ref_operand" "")
      (pc)))]
  "INTVAL (operands[1]) == 1"
  "#"
  "reload_completed"
  [(const_int 0)]
{
  HOST_WIDE_INT mask;
  rtx x;

  mask = 1;
  mask <<= INTVAL (operands[1]);
  mask -= 1;
  mask <<= INTVAL (operands[2]);

  operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));

  x = gen_rtx_AND (SImode, operands[0], gen_int_mode (mask, SImode));

  rx_split_cbranch (CC_ZSmode, GET_CODE (operands[4]),
            x, const0_rtx, operands[3]);
  DONE;
})

これをrx.mdのその1の前あたりに追加します。

この変更を使ったgccでコンパイルすると

0000 FB E2 00 00 00 00    mov.L   #_bar1, r14
0006 CC EE                mov.B   [r14], r14
0008 7C 1E                btst    #1, r14
000a FB E2 00 00 00 00    mov.L   #_bar, r14
0010 1C                   bne     .L5
0011 F0 E1                bset    #1, [r14].B
0013 02                   rts
                      .L5:
0014 F0 E9                bclr    #1, [r14].B
0016 02                   rts

btstを使うようになります。



拍手[0回]

rx-elf-gcc(4.7.2)でbtst命令を使うようにしてみようという試み、その1

試したソースはこれです。

/*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でコンパイルすると

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


こうなります。(注:改造したrx-elf-gccを使っているので出力コードが違うことがあります)
色の付いたところをbtst命令を使うようにしてみます。

rx.mdのtstsiの前に以下を追加します。

(define_insn "*btstsi"
  [(set (reg:CC_ZS CC_REG)
        (compare:CC_ZS
          (and:SI (match_operand:SI 0 "register_operand"  "r")
                  (match_operand:SI 1 "const_int_operand" "i"))
          (const_int 0)))]
  "reload_completed
   && exact_log2 (INTVAL (operands[1]) & 0xff) >= 0
   && exact_log2 (INTVAL (operands[1]) & 0xff) <= 31"
  "*
{
  rtx xoperands[2];
  xoperands[0] = operands[0];
  xoperands[1] = GEN_INT (exact_log2 (INTVAL (operands[1])));
  output_asm_insn (\"btst\\t%1, %0\", xoperands);
  return \"\";
}
  "
  [(set_attr "timings" "11")
   (set_attr "length"  "3")]
)

ビルドしたgccでコンパイルすると

0000 FB E2 00 00 00 00      mov.L   #_bar1, r14
0006 CC EE                  mov.B   [r14], r14
0008 7C 0E                  btst    #0, r14
000a FB E2 00 00 00 00      mov.L   #_bar, r14
0010 1C                     bne     .L5
0011 F0 E0                  bset    #0, [r14].B
0013 02                     rts
                        .L5:
0014 F0 E8                  bclr    #0, [r14].B
0016 02                     rts

btst命令を使うようになりました。おまけにサイズも小さくなってます。

拍手[0回]

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

試したソースはこれです。

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回]

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回]

カレンダー

04 2024/05 06
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 31

フリーエリア

最新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

忍者アナライズ

コガネモチ

忍者カウンター

カレンダー

04 2024/05 06
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 31