私はさまざまなコンパイラの機能について調べていて、多くのコンパイラが実行すると報告されている「積極的な最適化」という用語に出くわしました。たとえば、LLVM は、次のコンパイル時の最適化機能を挙げています。
- メモリ/ポインタ固有
- ループ変換
- データフロー
- 算術
- デッドコードの排除
- インライン化
これは具体的にどういう意味ですか?次のコード スニペットがあるとします。生成されたバイト コードを最適化して、コンパイラが生成したものよりも速く実行するにはどうすればよいでしょうか? 特に、C#、Java、Flash などの JIT を利用したランタイムのバイトコードの最適化に関心があります。JIT はプロセッサが通常実行するオペコードのサブセットのみをサポートし、実行できる最適化の量が制限されるため、これは注意が必要です。それでも、私は何が可能で、正確にどのような変換が VM の限界を押し上げることができるかを知りたいと思っています。
架空のコード ブロック:
for (i = 0; i < 100; i++){
in = dataIn[i];
if ((in % 5) == 0){
out = ((in / 2) >> 16) - 10;
}else{
out = ((in << 5) / 2) * 50 + 10;
}
dataOut[i] = out;
}
Flash Player などのスタックベースの JIT VM 用に、コンパイラによって生成されたおおよその疑似コード: (間違いがあった場合はご容赦ください。これは完全に手書きです!)
// i = 0
label: "forInit"
push 0
writeTo "i"
// while i < 100
label: "forStart"
push "i"
push 100
jumpIfMoreThan "forEnd"
// in = dataIn[i];
push "i"
push "dataIn"
readProp
saveTo "in"
// if ((in % 5) == 0)
push "in"
push 5
mod
push 0
jumpIfNotEquals "ifPart2"
label: ifPart1
// out = ((in / 2) >> 16) - 10;
push "in"
push 2
divide
push 16
rightshift
push 10
minus
writeTo "out"
goto "ifEnd"
// else
label: ifPart2
// out = ((in << 5) / 2) * 50 + 10;
push "in"
push 5
leftshift
push 2
divide
push 50
multiply
push 10
add
writeTo "out"
// dataOut[i] = out;
label: ifEnd
push "out"
push "i"
push "dataOut"
writeProp
// i++
push "i"
increment
writeTo "i"
// while i < 100
goto "forStart"
label: "forEnd"