Ich finde, dass es einige intrinsische Funktionen in LLVM gibt, wie zum Beispiel llvm.memcpy
, llvm.va_start
.
Aber ich habe keine Ahnung, warum sie existieren und warum andere nicht. Wenn zum Beispiel der Prototyp von memcpy
innerhalb von string.h
liegt, warum werden andere Funktionen wie strcpy
nicht als intrinsisch behandelt?
Ich habe festgestellt, dass das Frontend in einigen Fällen spezielle intrinsische Funktionsaufrufe generieren kann. Für einen einfachen Fall:
%Vor% Die llvm IR für foo
, die von clang generiert wird, ist:
llvm.memcpy
wird in IR aufgerufen, aber nicht im Quellcode. Aber kann das Frontend LLVM IR ohne dieses intrinsische erzeugen?
Ich stieß auch auf ein Dokument über eine viel frühere Version der llvm Sprachreferenz und fand es dass einige spezielle Funktionen wie malloc
, free
in LLVM-Anweisungen enthalten waren (offensichtlich gibt es sie nicht mehr).
Also, was ist die Erkenntnis, dass die llvm-Anweisung so konzipiert ist?
Natürlich können Sie tun, was Ihr Beispiel ohne memcpy zeigt - nur ein bisschen härter (naja, vielleicht nicht mit nur 4 Bytes, was in vier Einzelbyte-Bewegungen gemacht werden könnte, nicht viel schwieriger als memcpy - auf der anderen Seite Wenn Ihre Zeichenfolge, mit der Sie str initialisieren, 128 Bytes [und str
lang genug ist, um sie zu halten], wäre eine Folge von 128 Einzelbyte-Bewegungen ziemlich umständlich und das Erzeugen einer Schleife ist auch ein bisschen schwerfällig).
Der Hauptpunkt intrinsischer Funktionen besteht jedoch darin, dem Compiler (Backend) zu ermöglichen, "zu verstehen, was vor sich geht", weil er in der Lage sein wird, [zumindest für Konstanten] zu bestimmen, welche Größe die Kopie hat , erzeuge zwei 32-Bit-Züge, um den Wert "str"
in der Variablen str
zu speichern. Oder, wenn der Betrag groß ist, rufen Sie real memcpy
auf oder erstellen Sie eine Schleife für Zwischengrößen.
Am Ende lautet die einfache Antwort "weil der Compiler besseren Code als die alternativen Lösungen generieren kann".
Der Grund dafür, dass ich strcpy
NICHT habe, ist, dass strcpy
(für effizientere Zwecke) durch memcpy
für konstante Zeichenketten ersetzt werden kann. Wenn die Zeichenkette nicht konstant ist, ist strcpy
a etwas komplizierter als memcpy
auf jeden Fall, also nicht so vorteilhaft, um Inline-Optimierungen für.
Theoretisch könnten alle Arten von Funktionen intrinsisch gemacht werden, aber es ist eine "Kosten / Nutzen" -Analyse, die durchgeführt werden muss - wie viel gewinnen Sie und wie lange dauert es, um den Code dafür zu schreiben? / p>
[Natürlich kann ich das nur aus meiner Erfahrung mit LLVM ableiten, ich weiß das nicht von jemandem, der intrinsische Funktionen in LLVM implementiert hat]
Mit intrinsischen Funktionen ist es einfacher, LLVM zu erweitern, um die Fähigkeiten der Hardware zu nutzen, spezialisierte Operationen durchzuführen, die sonst in der Software codiert werden müssten.
Einige Operationen, wie z. B. das Kopieren von Daten von einem Ort zu einem anderen, können in einigen CPU-Typen vollständig von der Hardware ausgeführt werden, in anderen müssen sie jedoch als normale Funktion codiert sein.
Mit diesen intrinsischen Funktionen kann LLVM einen Aufruf an ein intrinsisches Element ausgeben, das später (vom Codierer) in die effizienteste Form für den Zielprozessor konvertiert wird - entweder spezielle Maschinenbefehle oder Aufrufe von tatsächlichen Funktionen.
Theoretisch könnten Sie spezielle IR-Anweisungen haben, die alle diese Fälle abdecken, aber das wäre nicht sehr erweiterbar. Die Anzahl der Anweisungen, die erstellt werden müssten, würde im Laufe der Zeit erheblich erweitert.
In der LLVM-Dokumentation heißt es:
Fast alle Erweiterungen von LLVM sollten als intrinsische Funktion beginnen und dann in eine Anweisung umgewandelt werden, falls dies gerechtfertigt ist.