2015-06-18 19 views
13

Sto sviluppando un compilatore che emette il codice IL. È importante che l'IL risultante sia JIT per i codici macchina più veloci possibili da compilatori JIT Mono e Microsoft .NET.Ottimizzazione IL per compilatori JIT

Le mie domande sono:

  1. Ha senso per ottimizzare i modelli come:

    'stloc.0; ldloc.0; ret' => 'ret' 
    'ldc.i4.0; conv.r8' => 'ldc.r8.0' 
    

    e simili, o sono del JIT abbastanza intelligente per prendersi cura di questi?

  2. Esiste una specifica con l'elenco di ottimizzazioni eseguite dai compilatori JIT Microsoft/Mono?

  3. C'è qualche buona lettura con consigli pratici/best practice per ottimizzare IL in modo che i compilatori JIT possano a loro volta generare il codice macchina più ottimale (prestazioni-saggio)?

+1

Da quanto ho capito, la JIT è abbastanza buona nell'eliminare 'stloc.0; ldloc.0; '. Per IronScheme, ho provato a modificare l'output IL in modo che fosse molto simile a C# in base alla sensazione che il JIT probabilmente avrebbe cercato di ottimizzare i pattern conosciuti. Ma questa è solo una sensazione: D Potresti sempre creare dei microbenchmark per misurarlo. – leppie

+1

.NET JITters non sono particolarmente intelligenti (dopo tutto, non hanno molto tempo). Perché ti interessa "il più veloce possibile"? – Luaan

+1

@Luaan, mi interessa "il più veloce possibile" perché questo è il compilatore che ha bisogno di produrre codice per calcoli intensivi. Idealmente, dovrebbe produrre codice macchina nativo, ma sto considerando IL per una migliore portabilità e manutenibilità. Tuttavia, le prestazioni sono ancora una priorità assoluta. –

risposta

5
  1. I due modelli yo descritte sono le cose facili che il JIT in realtà ottiene di destra (tranne che per le strutture non primitive). Nella forma SSA la propagazione costante e l'eliminazione dei valori morti è molto semplice.
  2. No, devi testare cosa può fare il JIT. Guarda nella documentazione del compilatore per vedere quali ottimizzazioni standard aspettarti. Quindi, prova per loro. Le due JIT che abbiamo ora ottimizzano molto poco e a volte non ottengono le cose più elementari. Ad esempio, MyStruct s; s.x = 1; s.x = 1; non è ottimizzato da RyuJIT. s = s; non lo è neanche. s.x + s.x carica x due volte dalla memoria. Aspettatevi poco.
  3. È necessario comprendere a quali operazioni di base del codice macchina è associata. Questo non è troppo complicato. Prova alcune cose e guarda l'elenco di disassemblaggio. Avrai presto un'idea di come apparirà l'output.
+0

Perché l'SSA è pertinente? I compilatori JIT lo usano internamente? – svick

+0

@svick Sono abbastanza sicuro che lo facciano. Sembra molto essenziale. "ssabuilder.cpp" in CoreCLR sembra fare qualcosa del genere. https://en.wikipedia.org/wiki/Static_single_assignment_form#Compilers_using_SSA_form Guarda quanto è onnipresente. – usr

5

Conversioni ridondanti e carichi/depositi simili sono un effetto collaterale piuttosto inevitabile di un parser decente ricorsivo. Puoi tecnicamente sbarazzartene con uno spioncino. Ma non c'è nulla di cui preoccuparsi, i compilatori C# e VB.NET generano anche loro.

I jitter .NET/Mono esistenti sono molto bravi a ottimizzarli. Si concentrano sull'ottimizzazione del codice che in realtà è importante per la velocità di esecuzione, il codice macchina. Con il vantaggio molto bello che chiunque scriva un compilatore che genera IL beneficia automaticamente di queste ottimizzazioni senza dover fare nulla di speciale.

Le ottimizzazioni di jitter sono trattate in this post.