¿Hay algún atributo que pueda usar para decirle al compilador que siempre se debe optimizar un método, incluso si el interruptor del compilador global /o+
no está configurado?¿Puedo forzar al compilador a optimizar un método específico?
La razón que pido es porque estoy jugando con la idea de crear dinámicamente un método basado en el código IL de un método existente; la manipulación que quiero hacer es razonablemente fácil cuando el código está optimizado, pero se vuelve significativamente más difícil en el código no optimizado, debido a las instrucciones adicionales generadas por el compilador.
EDIT: más detalles sobre los no optimizaciones que me molestan ...
Vamos a considerar la siguiente implementación de la función factorial:
static long FactorialRec(int n, long acc)
{
if (n == 0)
return acc;
return FactorialRec(n - 1, acc * n);
}
(Nota: Sé que hay son mejores formas de calcular el factorial, esto es solo un ejemplo)
IL generado con optimizaciones habilitadas i Es bastante sencillo:
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
Pero la versión no optimizada es muy diferente
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
Está diseñado para tener un solo punto de salida, al final. El valor a devolver se almacena en una variable local.
¿Por qué es esto un problema? Quiero generar dinámicamente un método que incluya la optimización de la cola de llamadas. El método optimizado se puede modificar fácilmente agregando el prefijo tail.
antes de la llamada recursiva, ya que no hay nada después de la llamada, excepto ret
. Pero con la versión no optimizada, no estoy tan seguro ... el resultado de la llamada recursiva se almacena en una variable local, luego hay una rama inútil que simplemente salta a la siguiente instrucción, la variable local se carga y se devuelve. Así que no tengo una manera fácil de verificar que la llamada recursiva realmente sea la última instrucción, por lo que no puedo estar seguro de que se pueda aplicar la optimización de la llamada final.
AFAIK, no - eso no es posible –
El compilador JIT siempre optimizará todos los métodos. – Steven
@Steven, no si le dices que no lo haga (por ejemplo, con el indicador 'NoOptimization' en' MethodImplAttribute'). Pero de todos modos, mi pregunta es acerca de las optimizaciones del compilador, no la optimización JIT, ya que estoy interesado en el código IL que se genera. –