グローバル/o+
コンパイラスイッチが設定されていなくても、メソッドを常に最適化する必要があることをコンパイラに伝えるための属性はありますか?特定のメソッドを最適化するようにコンパイラを強制できますか?
私が尋ねる理由は、既存のメソッドのILコードに基づいてメソッドを動的に作成するというアイデアを思いついているからです。私がやりたい操作は、コードが最適化されるとかなり簡単ですが、コンパイラによって生成される余分な命令のために最適化されていないコードではかなり困難になります。
EDIT:私を気に非最適化についての詳細...
のは、以下の階乗関数の実装について考えてみましょう:
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
最後に、唯一の出口点を持つように設計されています。返される値は、ローカル変数に格納されます。
なぜこの問題が発生しますか?テールコールの最適化を含むメソッドを動的に生成したい。最適化されたメソッドは、ret
以外の呼び出しの後に何もないので、再帰呼び出しの前に接頭辞tail.
を追加することで簡単に変更できます。しかし、最適化されていないバージョンでは、再帰呼び出しの結果がローカル変数に格納され、次の命令にジャンプする無駄なブランチがあり、ローカル変数がロードされて返されます。だから、再帰呼び出しが実際に最後の命令であることを確認する簡単な方法はないので、テールコール最適化を適用できるかどうかは確かではありません。
AFAIK、いいえ - できません –
JITコンパイラは常にすべてのメソッドを最適化します。 – Steven
@Steven、そうでないと伝えないと(例えば、 'MethodImplAttribute'の' NoOptimization'フラグを使って)。しかし、とにかく、私の質問は、私は生成されるILコードに興味があるので、コンパイラの最適化ではなく、JITの最適化についてです。 –