我一直在阅读各种编译器的功能,并且我遇到了许多编译器据报道要执行的“积极优化”这个术语。例如,LLVM引用了以下编译时优化功能:
具体是什么意思?假设您有以下代码片段,如何优化生成的字节代码以比编译器生成的更快地运行?我特别感兴趣的是优化JIT驱动的运行时的字节码,例如C#,Java和Flash。这很棘手,因为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;
}
编译器为基于堆栈的JIT VM(如Flash Player)生成的近似伪代码:(原谅我有任何错误,这完全是手写的!)
// 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"
答案 0 :(得分:4)
我也一直致力于这个,transformations that LLVM performs的完整列表,在标题下组织:
答案 1 :(得分:2)
虽然这没有回答你的问题,但我遇到了C ++编译器为优化生成的机器代码而执行的以下转换:
答案 2 :(得分:1)
以下是编译器可以进行的两个简单优化:
out = ((i / 2) >> 16) - 10;
可以缩减为
out = (i >> 17) - 10;
和
out = ((i << 5) / 2) * 50 + 10;
可以缩减为
out = (i << 4) * 50 + 10;
回答你的问题“如何优化生成的字节代码以比编译器生成的更快的速度运行?”这是字节码的另一个版本,它有一些优化。
// 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
// optimization: remove unnecessary /2
// out = ((in / 2) >> 16) - 10;
push "in"
push 17
rightshift
push 10
minus
// optimization: don't need out var since value on stack
// dataOut[i] = out;
push "i"
push "dataOut"
writeProp
// optimization: avoid branch to common loop end
// i++
push "i"
increment
writeTo "i"
goto "forStart"
// else
label: ifPart2
// optimization: remove unnecessary /2
// out = ((in << 5) / 2) * 50 + 10;
push "in"
push 4
leftshift
push 50
multiply
push 10
add
// optimization: don't need out var since value on stack
// dataOut[i] = out;
push "i"
push "dataOut"
writeProp
// optimization: avoid branch to common loop end
// i++
push "i"
increment
writeTo "i"
goto "forStart"
label: "forEnd"