2017-02-02 1 views
7

Ich verwende Clang als Bibliothek einige Templat-Code zu kompilieren:Wie werden Template-Instanziierungen von Clang kompiliert?

template<typename T> 
T getSevenTemplated() { 
    return 7; 
} 

int getSeven() { 
    return getSevenTemplated<int>(); 
} 

Leider ist die kompilierte LLVM IR enthält nicht tatsächlich die Umsetzung von getSevenTemplated<int>:

; ModuleID = './test.cpp' 
source_filename = "./test.cpp" 
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" 
target triple = "x86_64-apple-macosx10.12.0" 

; Function Attrs: ssp uwtable 
define i32 @_Z8getSevenv() #0 { 
entry: 
    %call = call i32 @_Z17getSevenTemplatedIiET_v() 
    ret i32 %call 
} 

declare i32 @_Z17getSevenTemplatedIiET_v() #1 

attributes #0 = { ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 

!llvm.module.flags = !{!0} 
!llvm.ident = !{!1} 

!0 = !{i32 1, !"PIC Level", i32 2} 
!1 = !{!"clang version 5.0.0 (trunk 292778)"} 

Hier ist der Code Ich benutze, um das LLVM Modul zu erzeugen:

auto* context = new llvm::LLVMContext(); // TODO: Fix leak 

auto codeGenerator = 
    std::shared_ptr<clang::CodeGenerator>(
    clang::CreateLLVMCodeGen(
     compilerInstance.getDiagnostics(), 
     filePath, 
     compilerInstance.getHeaderSearchOpts(), 
     preprocessor.getPreprocessorOpts(), 
     compilerInstance.getCodeGenOpts(), 
     *context, 
     nullptr)); 

codeGenerator->Initialize(compilerInstance.getASTContext()); 

// declGroups are found by calling ParseAST with a special ASTConsumer earlier 
for (auto declGroup : declGroups) { 
    codeGenerator->HandleTopLevelDecl(declGroup); 
} 

codeGenerator->HandleTranslationUnit(compilerInstance.getASTContext()); 

T o untersuchen, warum, ich sah durch the source-code und ich fand, dass die CodeGenerator spezifische Logik für die Handhabung von Vorlagen hat: Es scheint zu überspringen, Funktion Vorlage Instanziierungen! Ich nehme an, dass es stattdessen die generierten Funktionen behandelt, aber ich weiß nicht, wie es wirklich funktioniert.

Meine Fragen sind:

  1. Auf einem hohen Niveau, wie funktioniert Clang gehen zu Vorlagen instanziieren und sie an den ASTConsumer für die Codegenerierung vorbei?
  2. Gibt es spezielle Tricks, um die Erstellung von Funktionskörpern für instanziierte Vorlagen zu ermöglichen? Was fehlt mir im obigen Code?
+0

Sie scheinen zu versuchen, eine Funktion zu instanziieren und es zugleich nennen. Versuchen Sie, die Zahl 7 oder die Funktion zurückzugeben, die int zurückgibt? – stark

+0

@stark Ich möchte die LLVM IR für das obige Programm generieren – sdgfsdh

Antwort

3

Das Problem war, dass ich inkrementelles Parsing eingeschaltet hatte. Wenn diese Einstellung aktiviert ist, ruft die Funktion ParseAST nicht clang::Sema::ActOnEndOfTranslationUnit auf, wodurch die Instanziierung von Vorlagen ausgelöst wird.

Der Trick ist, diesen Anruf hinzuzufügen, nachdem Ihr decls Verarbeitung:

// This triggers the instantiation of templated functions 
sema.ActOnEndOfTranslationUnit(); 
Verwandte Themen