C'è un attributo che posso usare per dire al compilatore che un metodo deve essere sempre ottimizzato, anche se lo switch del compilatore globale /o+
non è impostato?Posso forzare il compilatore a ottimizzare un metodo specifico?
Il motivo per cui lo chiedo è perché sto giocando con l'idea di creare dinamicamente un metodo basato sul codice IL di un metodo esistente; la manipolazione che voglio fare è ragionevolmente facile quando il codice è ottimizzato, ma diventa significativamente più difficile nel codice non ottimizzato, a causa delle istruzioni extra generate dal compilatore.
EDIT: ulteriori dettagli sulle non-ottimizzazioni che mi preoccupano ...
Consideriamo la seguente implementazione della funzione fattoriale:
static long FactorialRec(int n, long acc)
{
if (n == 0)
return acc;
return FactorialRec(n - 1, acc * n);
}
(Nota: So che ci sono modi migliori per calcolare il fattoriale, questo è solo un esempio)
Il IL generato con ottimizzazioni abilitate i s molto semplice:
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
Ma la versione non ottimizzata è molto diversa
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
È stato progettato per avere un solo punto di uscita, alla fine. Il valore da restituire è memorizzato in una variabile locale.
Perché questo è un problema? Voglio generare dinamicamente un metodo che include l'ottimizzazione delle chiamate tail. Il metodo ottimizzato può essere facilmente modificato aggiungendo il prefisso tail.
prima della chiamata ricorsiva, poiché non vi è nulla dopo la chiamata tranne ret
. Ma con la versione non ottimizzata, non ne sono così sicuro ... il risultato della chiamata ricorsiva è memorizzato in una variabile locale, quindi c'è un ramo inutile che salta all'istruzione successiva, la variabile locale viene caricata e restituita. Quindi non ho un modo semplice per verificare che la chiamata ricorsiva sia davvero l'ultima istruzione, quindi non posso essere sicuro che l'ottimizzazione della chiamata di coda possa essere applicata.
AFAIK, no, questo non è possibile –
Il compilatore JIT ottimizzerà sempre ogni metodo. – Steven
@Steven, non se lo dici a non (ad esempio con il flag 'NoOptimization' nel' MethodImplAttribute'). Comunque, la mia domanda riguarda le ottimizzazioni del compilatore, non l'ottimizzazione JIT, dal momento che sono interessato al codice IL che viene generato. –