是否有一个属性可用于告诉编译器必须始终优化一个方法,即使全局/o+
编译器开关未设置?我可以强制编译器优化特定方法吗?
我问的原因是因为我正在根据现有方法的IL代码动态创建一个方法,当代码被优化时,我想要做的操作相当容易,但由于编译器生成的额外指令,在非优化代码中变得非常困难。
编辑:关于打扰我的非优化的详细信息...
让我们看看下面的实现阶乘函数:
static long FactorialRec(int n, long acc)
{
if (n == 0)
return acc;
return FactorialRec(n - 1, acc * n);
}
(注:我知道有是更好的方法来计算阶乘,这只是一个例子)
IL优化生成启用我个相当简单:
IL_0000: ldarg.0
IL_0001: brtrue.s IL_0005
IL_0003: ldarg.1
IL_0004: ret
IL_0005: ldarg.0
IL_0006: ldc.i4.1
IL_0007: sub
IL_0008: ldarg.1
IL_0009: ldarg.0
IL_000A: conv.i8
IL_000B: mul
IL_000C: call UserQuery.FactorialRec
IL_0011: ret
但没有优化的版本是完全不同的
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.0
IL_0003: ceq
IL_0005: ldc.i4.0
IL_0006: ceq
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000A: brtrue.s IL_0010
IL_000C: ldarg.1
IL_000D: stloc.0
IL_000E: br.s IL_001F
IL_0010: ldarg.0
IL_0011: ldc.i4.1
IL_0012: sub
IL_0013: ldarg.1
IL_0014: ldarg.0
IL_0015: conv.i8
IL_0016: mul
IL_0017: call UserQuery.FactorialRec
IL_001C: stloc.0
IL_001D: br.s IL_001F
IL_001F: ldloc.0
IL_0020: ret
它被设计成只有一个出口点,在最后。要返回的值存储在局部变量中。
为什么这是一个问题?我想动态生成一个包含尾部呼叫优化的方法。通过在递归调用之前添加tail.
前缀,可以很容易地修改优化的方法,因为在除ret
之外的通话之后没有任何内容。但是对于未优化的版本,我不太确定......递归调用的结果存储在本地变量中,然后有一个无用的分支跳转到下一条指令,本地变量被加载并返回。所以我没有简单的方法来检查递归调用是否是最后的指令,所以我不能确定是否可以应用尾部调用优化。
AFAIK,no - 这是不可能的 – 2012-03-13 10:56:01
JIT编译器将始终优化每个方法。 – Steven 2012-03-13 11:01:39
@Steven,如果你不告诉它(例如使用'MethodImplAttribute'中的'NoOptimization'标志)。但无论如何,我的问题是关于编译器优化,而不是JIT优化,因为我对生成的IL代码感兴趣。 – 2012-03-13 11:17:34