Compilatore JIT per C, C ++ e simili


33

Esiste un compilatore just-in-time disponibile per linguaggi compilati, come C e C ++? (I primi nomi che vengono in mente sono Clang e LLVM! Ma non credo che al momento lo supportino.)

Spiegazione:

Penso che il software potrebbe trarre vantaggio dal feedback sulla profilazione del runtime e dalla ricompilazione aggressivamente ottimizzata degli hotspot in fase di runtime, anche per linguaggi compilati su macchina come C e C ++.

L'ottimizzazione guidata dal profilo fa un lavoro simile, ma con la differenza una JIT sarebbe più flessibile in ambienti diversi. In PGO esegui il tuo binario prima di rilasciarlo. Dopo averlo rilasciato, non utilizzava feedback sull'ambiente / input raccolti in fase di esecuzione. Quindi, se il modello di input viene modificato, viene analizzata la penalità delle prestazioni. Ma JIT funziona bene anche in quelle condizioni.

Tuttavia, penso che sia controverso se il vantaggio in termini di prestazioni di compilazione JIT superi le proprie spese generali.


1
Risorsa off-site-off-site.
DeadMG

1
Non sono sicuro che si adatti alla domanda, ma per una prospettiva di usabilità trovo utile il pacchetto Cxx nel linguaggio Julia .. ti dà un prompt interattivo C ++ simile a quelli descritti nella risposta @ PhilippClaßen.
Antonello

Risposte:


33

[Vedi la cronologia delle modifiche per una risposta abbastanza diversa che ora è sostanzialmente obsoleta.]

Sì, ci sono un paio di compilatori JIT per C e / o C ++.

CLing (come puoi immaginare dal gioco) si basa su Clang / LLVM. Si comporta come un interprete. Cioè, gli dai un po 'di codice sorgente, gli dai un comando per l'esecuzione, e viene eseguito. L'enfasi qui è principalmente sulla convenienza e sulla compilazione veloce, non sulla massima ottimizzazione. In quanto tale, sebbene tecnicamente una risposta alla domanda stessa, ciò non soddisfa molto bene l'intento del PO.

Un'altra possibilità è NativeJIT . Questo si adatta alla domanda in modo leggermente diverso. In particolare, non accetta il codice sorgente C o C ++, lo compila e lo esegue. Piuttosto, è un piccolo compilatore che puoi compilare nel tuo programma C ++. Accetta un'espressione che è sostanzialmente espressa come EDSL all'interno del tuo programma C ++ e genera il codice macchina effettivo da quello, che puoi quindi eseguire. Questo si adatta molto meglio a un framework in cui è possibile compilare la maggior parte del programma con un normale compilatore, ma avere alcune espressioni che non si conosceranno fino al runtime, che si desidera eseguire con qualcosa che si avvicina alla velocità di esecuzione ottimale.

Per quanto riguarda l'intento apparente della domanda originale, penso che il punto fondamentale della mia risposta originale sia ancora valido: mentre un compilatore JIT può adattarsi a cose come i dati che variano da un'esecuzione alla successiva, o anche variare dinamicamente durante una singola esecuzione, la realtà è che questo fa relativamente poca differenza almeno come regola generale. Nella maggior parte dei casi, eseguire un compilatore in fase di esecuzione significa che è necessario rinunciare a un bel po 'di ottimizzazione, quindi il meglio che si spera di solito è che sia vicino alla velocità che un compilatore convenzionale produrrebbe.

Sebbene sia possibile postulare situazioni in cui le informazioni disponibili per un compilatore JIT potrebbero consentire di generare un codice sostanzialmente migliore rispetto a un compilatore convenzionale, i casi in cui ciò accade nella pratica sembrano piuttosto insoliti (e nella maggior parte dei casi in cui sono stato in grado di verificare sta accadendo, era davvero a causa di un problema nel codice sorgente, non con il modello di compilazione statica).


1
Perché i JIT non salvano un file simile a una cache in modo che possano saltare da zero il re-apprendimento?
JohnMudd,

3
@JohnMudd: sospetto che il ragionamento sia la sicurezza. Ad esempio, modificare il codice memorizzato nella cache, quindi al successivo avvio della VM, esegue il codice che ho inserito lì invece di quello che ha scritto lì.
Jerry Coffin,

4
OTOH, se è possibile modificare le cache, è anche possibile modificare i file di origine.
user3125367

1
@ user3125367: Sì, ma in molti casi il compilatore esegue vari tipi di controllo e ciò potrebbe essere ignorato se si carica il codice compilato direttamente dalla cache. Dipende dalla JIT, ovviamente: Java fa molto lavoro di imposizione durante il caricamento di un file .class (compilato), ma molti altri fanno molto meno (quasi nessuno, in molti casi).
Jerry Coffin,

11

Sì, ci sono compilatori JIT per C ++. Dal punto di vista della prestazione pura, penso che l'ottimizzazione guidata profilo (PGO) sia ancora superiore.

Tuttavia, ciò non significa che la compilazione JIT non sia ancora utilizzata nella pratica. Ad esempio, Apple utilizza LLVM come JIT per la propria pipeline OpenGL. Questo è un dominio in cui hai molte più informazioni in fase di runtime, che possono essere usate per rimuovere molti codici morti.

Un'altra interessante applicazione di JIT è Cling, un interprete C ++ interattivo basato su LLVM e Clang: https://root.cern.ch/cling

Ecco una sessione di esempio:

[cling]$ #include <iostream>
[cling]$ std::cout << "Hallo, world!" << std::endl;
Hallo, world!
[cling]$ 3 + 5
(int const) 8
[cling]$ int x = 3; x++
(int) 3
(int const) 3
[cling]$ x
(int) 4

Non è un progetto giocattolo, ma in realtà viene utilizzato nel CERN, ad esempio, per sviluppare il codice per Large Hadron Collider.


7

C ++ / CLI è jeds. Certo, C ++ / CLI non è C ++ ma è abbastanza vicino. Detto questo, JIT di Microsoft non esegue i tipi super intelligenti / carini di ottimizzazioni basate sul comportamento di runtime di cui ti stai chiedendo, almeno non per quanto ne so. Quindi questo non aiuta davvero.

http://nestedvm.ibex.org/ trasforma MIPS in codice bytecode Java che verrebbe quindi eliminato. Il problema con questo approccio dalla tua domanda è che butti via molte informazioni utili quando arrivano alla JIT.


2

In primo luogo, suppongo che vorresti un jit di traccia piuttosto che un metodo jit.

L'approccio migliore da adottare sarebbe la compilazione del codice per llvm IR, quindi l'aggiunta del codice di traccia, prima di produrre un eseguibile nativo. Una volta che un blocco di codice diventa sufficientemente ben utilizzato e una volta sufficienti informazioni sui valori sono state raccolte (non sui tipi come nei linguaggi dinamici) delle variabili, il codice può essere ricompilato (dall'IR) con protezioni basate sui valori delle variabili.

Mi sembra di ricordare che ci sono stati dei progressi nel rendere ac / c ++ jit in clang sotto il nome di libclang.


1
AFAIK, libclang è la maggior parte della funzionalità clang fattorizzata come libreria. quindi, puoi usarlo per analizzare il codice sorgente per creare sofisticati colori della sintassi, lint, esplorazione del codice, ecc.
Javier,

@Javier, sembra giusto. Penso che ci fosse una funzione nella libreria che prendesse un carattere costante * di codice sorgente e producesse llvm ir, ma pensando ora, probabilmente è meglio jit basato sull'ir piuttosto che sulla sorgente.
dan_waterworth,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.