2016年1月6日水曜日

[gcc, spu] spu版gcc最適化問題(3)

2004年作成

インライン展開時のスタックポインタ処理


-O2でコンパイルするとinline定義されたものはinline展開します。
展開するにもかかわらずスタックポインタ操作の処理がそのまま残っています。
inline の場合は元になる関数の部分で全てを済ませればいいのですから、全て無駄なコードになっています。

     1 _start:
     2 ila $7,66051
     3 stqd $17,-48($sp)
     4 lqa $4,Test1In+16
:
    39 stqd $lr,16($sp) # リターンレジスタも積む必要無し
    38 a $7,$5,$4
    39 stqd $sp,-112($sp) # スタックポインタのセーブ処理
    40 sfh $6,$11,$6
    41 lnop
    42 ah $2,$2,$14
    43 lqd $15,0($7)
    44 ila $4,q4x4+16
    45 lnop
    46 sfi $8,$8,-15
    47 shufb $10,$2,$6,$10
    48 ai $sp,$sp,-112 # スタック拡張
    49 shufb $2,$2,$6,$17
    50 lqx $16,$5,$4
    51 ila $4,66051
    52 ai $sp,$sp,112 # スタック戻し
    53 shufb $8,$8,$8,$4
    54 sfh $4,$10,$2
:

レジスタ割り当て


callerレジスタの使用方法で無駄な箇所があります。

:
     3 stqd $17,-48($sp) # $17 store
     4 lqa $4,Test1In+16
     5 lqa $17,.LC0 # $17 def
     6 lqa $2,Test1In
:
    13 lqa $5,mod_six+20
    14 shufb $6,$2,$4,$17 # $17 use
    15 shufb $2,$2,$4,$10
:
    22 ah $6,$6,$2
    23 stqd $16,-32($sp) # $16 store
    24 stqd $15,-16($sp)
:
    49 shufb $2,$2,$6,$17 #
    50 lqx $16,$5,$4 # $16 def
    51 ila $4,66051
    52 ai $sp,$sp,112
    53 shufb $8,$8,$8,$4
    54 sfh $4,$10,$2
    55 lqd $17,-48($sp) # $17 reload
    56 ah $2,$2,$10
:
    74 mpya $5,$9,$15,$5
    75 mpya $6,$2,$16,$6 # $16 use
    76 mpyhha $4,$9,$15
    77 lqd $15,-16($sp)
    78 mpyhha $7,$2,$16 # $16 use
    79 lqd $16,-32($sp) # $16 reload
:

$16と$17が実際は一つのレジスタにまとめることができます。
$17 は 3-55, $16 は 23-79 でライブレンジが重なっているように見えますが、store-reload の部分が重なっているので、これは同一レジスタに割り当てることが可能です。

定数


同じ定数を別のレジスタに割り当てている部分があります。
同じレジスタを使用することによって、レジスタのスピル処理を減らすことができます。

下記の例はMEのものです。定数515に関して一つのレジスタにまとめることが出来ます。

     1 SubSampleFi4x4:
     2 nop $127
     3 stqd $42,-448($sp)
     4 il $42,-1152
     5 stqd $15,-16($sp)
     6 stqd $16,-32($sp)
     7 stqd $17,-48($sp)
     8 stqd $18,-64($sp)
     9 stqd $19,-80($sp)
    10 stqd $20,-96($sp)
    11 stqd $21,-112($sp)
    12 stqd $22,-128($sp)
    13 stqd $23,-144($sp)
    14 stqd $24,-160($sp)
    15 stqd $25,-176($sp)
    16 ilh $25,515
    17 stqd $26,-192($sp)
    18 # iprefetch
    19 lnop
    20 stqd $27,-208($sp)
    21 stqd $28,-224($sp)
    22 stqd $29,-240($sp)
    23 ilh $29,515
    24 stqd $30,-256($sp)
    25 stqd $31,-272($sp)
    26 stqd $32,-288($sp)
    27 nop $127
    28 stqd $33,-304($sp)
    29 ilh $33,515

無駄なレジスタを使用してしまうのは上記の2と同じ問題です。
inline展開を多用しますと、どうしても使用するレジスタ数が増えます。
無駄なレジスタ使用が 1 つあるとスタックへのロード・セーブでパイプラインの P1 が二つ埋まってしまいます。

無駄なnop


下記のトレース結果はme実行時のものです。
85,86にnopがありますが、これは無駄ではないでしょうか。
ただ、nop を削るとスケジュールが崩れる場合があるので、どういう準拠によってnop が挿入されるかわかりません。
89-92 で処理が空いているのは 87 で $26 の準備をしているのが間に合っていないためです。
80 で $10 の設定処理をしている部分と交換すれば、この無駄なサイクルを削ることが出来ます。

D Cycle     80: PC:00178 [P0:il $9,0x0000] PC:0017c [P1:lqa $10,0x015c0]
S Cycle     81: PC:00180 [P1:stqd $0,0x001($1)]
S Cycle     82: PC:00184 [P1:stqd $1,0x3f2($1)]
S Cycle     83: PC:00188 [P0:ai $1,$1,0x320] PC:0018c [P1:lnop ]
S Cycle     84: PC:00190 [P0:il $8,0x0000] PC:00194 [P1:hbra 0x01c,0x0068]
N Cycle     85: PC:00198 [P1:lnop ]
N Cycle     86: PC:0019c [P0:nopi ,0x00007f]
D Cycle     87: PC:001a0 [P0:ila $20,0x01600] PC:001a4 [P1:lqa $26,0x02000]
S Cycle     88: PC:001a8 [P1:lqa $25,0x02010]
R Cycle     89:
R Cycle     90:
R Cycle     91:
R Cycle     92:
S Cycle     93: PC:001ac [P0:mpyh $24,$9,$26] 

0 件のコメント:

コメントを投稿