Есть ли атрибут, который я могу использовать, чтобы сообщить компилятору, что метод всегда должен быть оптимизирован, даже если глобальный переключатель компилятора /o+
не установлен?Могу ли я заставить компилятор оптимизировать определенный метод?
Причина, по которой я прошу, состоит в том, что я играю с идеей динамического создания метода на основе кода IL существующего метода; манипуляция, которую я хочу сделать, достаточно прост, когда код оптимизирован, но становится значительно сложнее в неоптимизированном коде из-за дополнительных инструкций, сгенерированных компилятором.
EDIT: более подробно о не-оптимизаций, которые беспокоят меня ...
Рассмотрим следующую реализацию функции факториала:
static long FactorialRec(int n, long acc)
{
if (n == 0)
return acc;
return FactorialRec(n - 1, acc * n);
}
(Примечание: Я знаю, являются лучшими способами вычисления факториала, это просто пример)
ИЛ, сгенерированный с включенными оптимизациями i S довольно проста:
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, нет - это невозможно –
Компилятор JIT всегда будет оптимизировать каждый метод. – Steven
@Steven, если вы не указали это (например, с флагом 'NoOptimization' в' MethodImplAttribute'). Но в любом случае, мой вопрос касается оптимизации компилятора, а не оптимизации JIT, поскольку меня интересует генерируемый IL-код. –