JIT-Compiler für C, C ++ und dergleichen

33

Gibt es einen Just-in-Time-Compiler für kompilierte Sprachen wie C und C ++? (Die ersten Namen, die mir in den Sinn kommen, sind Clang und LLVM! Aber ich glaube nicht, dass sie es derzeit unterstützen.)

Erläuterung:

Ich denke, die Software könnte von Feedback zur Laufzeitprofilerstellung und einer aggressiv optimierten Neukompilierung von Hotspots zur Laufzeit profitieren, selbst für Sprachen, die auf Maschinen kompiliert wurden, wie C und C ++.

Die profilgesteuerte Optimierung erledigt eine ähnliche Aufgabe, mit dem Unterschied, dass eine JIT in verschiedenen Umgebungen flexibler ist. In PGO führen Sie Ihre Binärdatei aus, bevor Sie sie freigeben. Nachdem Sie es freigegeben haben, werden keine zur Laufzeit erfassten Umgebungs- / Eingabefeedbacks verwendet. Wenn also das Eingabemuster geändert wird, ist dies eine Beeinträchtigung der Leistung. Aber JIT funktioniert auch unter diesen Bedingungen gut.

Ich halte es jedoch für umstritten, ob der JIT-Kompilierungsleistungsvorteil den eigenen Aufwand übersteigt.

Ebrahim Mohammadi
quelle
1
Off-Topic-Off-Site-Ressource.
DeadMG
1
Ich bin mir nicht sicher, ob es zu der Frage passt, aber für einen Usability-Interessenten finde ich das Cxx-Paket in der Sprache Julia nützlich . Es gibt Ihnen eine interaktive C ++ - Eingabeaufforderung, die der in der Antwort von @ PhilippClaßen beschriebenen ähnelt.
Antonello
GCC 9 hat jetzt einen JIT-Compiler gcc.gnu.org/onlinedocs/jit/intro/index.html
user3071643 vor

Antworten:

33

[Siehe Bearbeitungsverlauf für eine ganz andere Antwort, die jetzt im Grunde genommen veraltet ist.]

Ja, es gibt einige JIT-Compiler für C und / oder C ++.

CLing basiert auf Clang / LLVM. Es wirkt wie ein Dolmetscher. Das heißt, Sie geben ihm einen Quellcode, geben einen Befehl, damit er ausgeführt wird, und er wird ausgeführt. Der Schwerpunkt liegt dabei in erster Linie auf Komfort und schneller Kompilierung, nicht auf maximaler Optimierung. Obwohl dies technisch gesehen eine Antwort auf die eigentliche Frage ist, entspricht dies nicht wirklich den Absichten des OP.

Eine andere Möglichkeit ist NativeJIT . Das passt etwas anders zur Frage. Insbesondere akzeptiert es keinen C- oder C ++ - Quellcode und kompiliert ihn und führt ihn aus. Es ist vielmehr ein kleiner Compiler, den Sie in Ihr C ++ - Programm kompilieren können. Es akzeptiert einen Ausdruck, der im Grunde genommen als EDSL in Ihrem C ++ - Programm ausgedrückt wird, und generiert daraus tatsächlichen Maschinencode, den Sie dann ausführen können. Dies passt viel besser zu einem Framework, in dem Sie den größten Teil Ihres Programms mit einem normalen Compiler kompilieren können, aber einige Ausdrücke haben, die Sie erst zur Laufzeit kennen und die Sie mit einer Geschwindigkeit ausführen möchten, die sich der optimalen Ausführungsgeschwindigkeit nähert.

Was die offensichtliche Absicht der ursprünglichen Frage angeht, so bleibt meiner Meinung nach der Grundgedanke meiner ursprünglichen Antwort bestehen: Während sich ein JIT-Compiler an Daten anpassen kann , die von einer Ausführung zur nächsten variieren oder sogar dynamisch während einer einzelnen Ausführung variieren, Die Realität ist, dass dies zumindest in der Regel einen relativ geringen Unterschied macht. In den meisten Fällen bedeutet das Ausführen eines Compilers zur Laufzeit, dass Sie auf einiges an Optimierung verzichten müssen. Das Beste, auf das Sie normalerweise hoffen, ist, dass es fast so schnell ist, wie ein herkömmlicher Compiler es produzieren würde.

Obwohl es möglich ist, Situationen zu postulieren, in denen Informationen, die einem JIT-Compiler zur Verfügung stehen, es ermöglichen könnten , wesentlich besseren Code zu generieren als ein herkömmlicher Compiler, scheint dies in der Praxis ziemlich ungewöhnlich zu sein (und in den meisten Fällen, in denen ich dies überprüfen konnte) Dies geschah tatsächlich aufgrund eines Problems im Quellcode (nicht beim statischen Kompilierungsmodell).

Jerry Sarg
quelle
1
Warum speichern JITs keine cacheartige Datei, damit sie das Neulernen von Grund auf überspringen können?
JohnMudd
3
@ JohnMudd: Ich vermute, die Argumentation ist Sicherheit. Ändern Sie z. B. den zwischengespeicherten Code und führen Sie beim nächsten Start der VM den von mir dort eingegebenen Code aus, anstatt den dort geschriebenen.
Jerry Coffin
4
OTOH, wenn Sie Caches ändern können, können Sie auch Quelldateien ändern.
user3125367
1
@ user3125367: Ja, aber in vielen Fällen führt der Compiler verschiedene Typprüfungen durch, die möglicherweise umgangen werden, wenn Sie kompilierten Code direkt aus dem Cache laden. Das hängt natürlich von der JIT ab - Java erledigt beim Laden einer (kompilierten) .class-Datei eine Menge Durchsetzungsarbeit, aber viele andere tun viel weniger (in vielen Fällen fast keine).
Jerry Coffin
11

Ja, es gibt JIT-Compiler für C ++. Aus reiner Leistungsperspektive halte ich Profile Guided Optimization (PGO) immer noch für überlegen.

Dies bedeutet jedoch nicht, dass die JIT-Kompilierung in der Praxis noch nicht verwendet wird. Beispielsweise verwendet Apple LLVM als JIT für seine OpenGL-Pipeline. Dies ist eine Domäne, in der Sie zur Laufzeit erheblich mehr Informationen haben, mit denen Sie eine Menge toten Codes entfernen können.

Eine weitere interessante Anwendung von JIT ist Cling, ein interaktiver C ++ - Interpreter, der auf LLVM und Clang basiert: https://root.cern.ch/cling

Hier ist eine Beispielsitzung:

[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

Es ist kein Spielzeugprojekt, wird aber tatsächlich in CERN verwendet, um beispielsweise den Code für den Large Hadron Collider zu entwickeln.

Philipp Claßen
quelle
7

C ++ / CLI ist fehlerhaft. Zugegeben, C ++ / CLI ist nicht C ++, aber es ist ziemlich nah. Das heißt, Microsofts JIT macht nicht die super cleveren / niedlichen Arten von Optimierungen, die auf dem Laufzeitverhalten basieren, nach denen Sie fragen, zumindest nicht nach meinem Wissen. Das hilft also wirklich nicht.

http://nestedvm.ibex.org/ wandelt MIPS in Java-Bytecode um, der dann ausgelassen wird. Das Problem bei diesem Ansatz aus Ihrer Frage besteht darin, dass Sie viele nützliche Informationen wegwerfen, bis sie beim JIT eingehen.

Logan Capaldo
quelle
2

Erstens nehme ich an, Sie möchten ein Tracing-Jit anstelle eines Methoden-Jits.

Am besten kompilieren Sie den Code in llvm IR und fügen Sie dann Tracing-Code hinzu, bevor Sie eine native ausführbare Datei erstellen. Sobald ein Codeblock ausreichend gut genutzt wird und genügend Informationen über die Werte (nicht die Typen wie in dynamischen Sprachen) von Variablen gesammelt wurden, kann der Code mit Guards basierend auf den Werten der Variablen neu kompiliert werden (aus dem IR).

Ich scheine mich zu erinnern, dass es einige Fortschritte bei der Erstellung von ac / c ++ jit in clang unter dem Namen libclang gab.

dan_waterworth
quelle
1
AFAIK, libclang ist der größte Teil der Clang-Funktionalität, die als Bibliothek herausgerechnet wird. Sie können es also verwenden, um den Quellcode zu analysieren, um anspruchsvolle Syntaxfarben, Lints, Code-Browsing usw. zu erstellen.
Javier
@Javier, das klingt ungefähr richtig. Ich denke, es gab eine Funktion in der Bibliothek, die ein const char * des Quellcodes verwendet und llvm ir erzeugt hat, aber jetzt denkt, es ist wahrscheinlich besser, basierend auf der ir als der Quelle zu jiten.
Dan_waterworth