common subexpression elimination や loop invariant code motion を行うと, getelementptr が,本来含まれていた基本ブロックの外へと移動することがある.
一見問題なさそうだが,場合によっては生成される命令数が増える.(これは自作コンパイラ基盤の実装上の問題)
次のコードは,
A:
a = gep ...
b = load a
次のように解釈されるから,
A:
b = load (gep ...)
最終的に combine されて
A:
b = mov [...]
みたいな感じになる.
でも次のコードは,
A:
a = gep ...
br B
B:
b = load a
ブロックBからブロックA内のaを参照するから,どうしてもgep ...
の結果がaに代入されてしまう.(liveoutする値は,仮想レジスタ(ここではa)に代入されることになっている)
だから,最終的にこうなる.
A:
a = lea ...
br B
B:
b = mov [a]
さっきは mov 一個で済んでいたのに,今回は lea と mov を使ってしまっている.
gep を移動させない,liveoutする値の挙動を変えるなど. これ以外に思いつかないので,何か良い方法があれば教えていただきたい.
こんにちは。LLVMではCodgGenのlib/CodeGen/CodeGenPrepare.cppで
a = gep ...
の部分をb = load ..
の直前に戻す操作を(速くなりそうなら)LLVM IRレベルで行っています(LICMした後に戻しています)。例えば以下のIRで
これを-print-after-allすると
になり
%addr.ptr
がsunkされることが分かります。CodeGenPrepareで実際にsunkしたほうがいいか判定しているのはこの辺り(たぶん)だと思っていて(実際I->hasOneUse()
を消したらsunkされませんでした)、同じようにUseが1つなら直前に持ってくと上手く行きそうな気がします(isProfitableToFoldIntoAddressingMode
辺りも参考になりそうです)