2010-07-31 9 views
6

Mi piacerebbe sapere: il .NET JITter incorpora in modo ricorsivo piccole funzioni chiamate da altre piccole funzioni?Il JIT .NET incorpora una piccola funzione che chiama un'altra piccola funzione?

solo per esempio:

public static float Square(float value) 
{ 
    return value * value; 
} 

public static float Cube(float value) 
{ 
    return Square(value) * value; 
} 

Se chiamo Cube da qualche parte, lo farà in linea tutta la strada, o dovrò finire con una chiamata di funzione per Square?

E, in caso affermativo, quanto sarà profondo recitare per eseguire l'inlining? (Dire che ero abbastanza pazzo da implementare una funzione Quartic o Quintic allo stesso modo.)

risposta

10

Purtroppo hai scelto un cattivo esempio. Il compilatore JIT x86 non ha metodi inline che restituiscono float. Non sono sicuro al 100% perché, penso di evitare problemi consistenti quando il float viene convertito in un valore in virgola mobile a 80-bit nella FPU. La precisione interna è di 80 bit, ma quei bit aggiuntivi vengono eliminati quando il valore di 80 bit viene troncato su un valore a 32 bit quando viene risucchiato in memoria. Mantenere troppo a lungo il valore nella FPU impedisce che questo troncamento si verifichi e cambia il risultato del calcolo.

se si sostituisce float con un doppio e compilare il codice:

static void Main(string[] args) { 
    Console.WriteLine(Cube(2.0)); 
} 

Poi viene generato il codice macchina quando l'ottimizzatore JIT è abilitato:

00000000 push  ebp        ; setup stack frame 
00000001 mov   ebp,esp 
00000003 call  6DA2BEF0      ; Console.get_Out() 
00000008 fld   qword ptr ds:[010914B0h]  ; ST0 = 8.0 
0000000e sub   esp,8       ; setup argument for WriteLine 
00000011 fstp  qword ptr [esp] 
00000014 mov   ecx,eax       ; call Console.Out.WriteLine 
00000016 mov   eax,dword ptr [ecx] 
00000018 call  dword ptr [eax+000000D0h] 
0000001e pop   ebp        ; done 
0000001f ret 

Non solo inline le funzioni, è stato in grado di valutare le espressioni al momento della compilazione. E passa direttamente il risultato chiamando Console.WriteLine (8.0). Abbastanza bene eh?

Utilizzare doppio, non galleggiante.

+1

Interessante ... perché sto lavorando in XNA dove * tutto * è un float! Leggermente preoccupante ... –

+0

* "Il compilatore JIT x86 non ha metodi inline che restituiscono float." * - Ne sei assolutamente sicuro? Ho cercato in alto e in basso e non riesco a trovare riferimenti per eseguire il backup. Il meglio che ho trovato è stata questa pagina su Connect: https://connect.microsoft.com/VisualStudio/feedback/details/536781/unexpected-jit-inlining-behavior che sembra implicare che le funzioni restituiscono float * do *, infatti, in linea. E questo (vecchio) articolo implica che le regole di coercizione (quindi forse diverse nella pratica) sono le stesse per i float e i doppi: http://blogs.msdn.com/b/davidnotario/archive/2005/08/08/449092. aspx –

+1

@Andrew: le regole di allineamento non sono documentate, solo suggerite in alcuni post del blog. Importante, perché devono essere in grado di modificarlo per migliorare il jitter senza interrompere le ipotesi formulate dal comportamento documentato. Posso solo documentare quello che vedo fare il jitter x86. E sicuramente non incorpora la versione flottante di questi metodi. Vedi un comportamento diverso? –