2009-09-13 20 views
10

Ich schreibe einen LLVM Code Generator für die Sprache Timber, der aktuelle Compiler gibt C-Code aus. Mein Problem ist, dass ich C-Funktionen von den generierten LLVM-Dateien aufrufen muss, zum Beispiel hat der Compiler einen Echtzeit-Garbage-Collector und ich muss Funktionen aufrufen, die benachrichtigt werden, wenn neue Objekte auf dem Heap zugewiesen werden. Ich habe keine Ahnung, wie diese Funktionen mit meinen generierten LLVM-Dateien verknüpft werden können.LLVM - Verbindungsproblem

Die Codegenerierung wird durch Generieren von .ll-Dateien erstellt und anschließend manuell kompiliert.

Ich versuche, eine externe Funktion von LLVM aufrufen, aber ich habe kein Glück. In den Beispielen, die ich gefunden habe, werden nur C-Standardfunktionen wie "puts" und "printf" aufgerufen, aber ich möchte eine> hausgemachte Funktion aufrufen. Ich stecke fest.

+0

Meinst du, dass Sie versuchen, Code direkt in LLVM IR zu schreiben und Sie sind nicht in der Lage, einen Anruf zu tätigen, oder dass Sie Code mit LLVM kompilieren und Probleme haben? –

Antwort

5

Stellen Sie sich Ihren LLVM Baugruppendateien normalerweise mit llvm-as:

llvm-as *.ll 

die Bitcode Dateien kompilieren Assembler-Sprache-Dateien .s:

llc *.bc 

GCC sie mit der Laufzeitbibliothek in:

gcc *.s runtime.c -o executable 

Ersatz in echten Makefiles, gemeinsam genutzten Bibliotheken, etc., falls erforderlich. Du hast die Idee.

12

Ich gehe davon aus, dass Sie eine LLVM-Transformation schreiben, und Sie möchten Aufrufe an externe Funktionen in transformierten Code hinzufügen. Wenn dies nicht der Fall ist, bearbeiten Sie Ihre Frage und fügen Sie weitere Informationen hinzu.

Bevor Sie eine externe Funktion vom LLVM-Code aufrufen können, müssen Sie eine Deklaration dafür einfügen. Zum Beispiel:

virtual bool runOnModule(Module &m) { 
    Constant *log_func = m.getOrInsertFunction("log_func", 
               Type::VoidTy, 
               PointerType::getUnqual(Type::Int8Ty), 
               Type::Int32Ty, 
               Type::Int32Ty, 
               NULL); 
    ... 
} 

Der Code deklariert über eine Funktion log_func, die void zurückgibt und hat drei Argumente: ein Byte-Zeiger (string) und zwei 32-Bit-Integer. getOrInsertFunction ist eine Methode von Module.

Um die Funktion tatsächlich aufzurufen, müssen Sie eine CallInst einfügen. Hierfür gibt es mehrere statische Methoden Create.

+0

Das ist genau das, was ich gerade versucht habe, mit llvm zu tun, danke! – Dan

3

Ich interpretiere Ihre Frage als "Wie implementiere ich eine Laufzeitbibliothek in C oder C++ für meine Sprache, die nach LLVM kompiliert wird?"

Ein Ansatz ist, wie von Jonathan Tang beschrieben, um die Ausgabe Ihres Compilers von LLVM IR zu Bitcode zu Assembly zu transformieren, und gcc Vanille die Assembly gegen die Laufzeitquelle (oder Objektdateien) verknüpfen.

Ein alternativer, möglicherweise flexiblerer Ansatz ist, llvm-gcc zu verwenden, um die Laufzeit selbst in LLVM-Bitcode zu kompilieren, und dann llvm-ld zu verwenden, um den Bitcode von Ihrem Compiler mit dem Bitcode Ihrer Laufzeit zu verknüpfen. Dieser Bitcode kann dann mit opt erneut optimiert werden, mit llvm-dis zurück in IR konvertiert werden, direkt interpretiert mit lli (dies funktioniert, afaik, funktioniert nur, wenn LLVM gegen libffi erstellt wurde), oder kompiliert zu Assembly mit llc (und dann zu einem nativen binär mit Vanille gcc).