2013-12-21 10 views
5

ein einfaches Szenario Teilauswertung Angenommen:C++/LLVM: Laufzeitcode-Generierung und STL-Container

#include <vector> 

/* may be known at runtime */ 
int someConstant(); 

/* can be partially evaluated */ 
double foo(std::vector<double> args) { 
    return args[someConstant()] * someConstant(); 
} 

Lassen Sie sich sagen, dass someConstant() bekannt ist und zur Laufzeit nicht (zB durch den Benutzer einmal gegeben) ändern und seine ersetzt durch das entsprechende int literal. Wenn foo Teil des heißen Weges ist, erwarte ich eine deutliche Leistungssteigerung:

/* partially evaluated, someConstant() == 2 */ 
double foo(std::vector<double> args) { 
    return args[2] * 2; 
} 

Meine aktuellen nehmen auf diesem Problem wäre LLVM IR zur Laufzeit zu erzeugen, weil ich die Struktur des teilweise ausgewertete Code kennen (so Ich brauche keinen allgemeinen Teilbewerter. Also ich möchte eine Funktion foo_ir schreiben, die IR-Code erzeugt, der das gleiche tut wie foo, aber nicht someConstant() aufrufen, weil es zur Laufzeit bekannt ist. Einfach genug, oder? Doch wenn ich mir die erzeugte IR für den Code oben:

; Function Attrs: uwtable 
define double @_Z3fooSt6vectorIdSaIdEE(%"class.std::vector"* %args) #0 { 
    %1 = call i32 @_Z12someConstantv() 
    %2 = sext i32 %1 to i64 
    %3 = call double* @_ZNSt6vectorIdSaIdEEixEm(%"class.std::vector"* %args, i64 %2) 
    %4 = load double* %3 
    %5 = call i32 @_Z12someConstantv() 
    %6 = sitofp i32 %5 to double 
    %7 = fmul double %4, %6 
    ret double %7 
} 

; Function Attrs: nounwind uwtable 
define linkonce_odr double* @_ZNSt6vectorIdSaIdEEixEm(%"class.std::vector"* %this, i64 %__n) #1 align 2 { 
    %1 = alloca %"class.std::vector"*, align 8 
    %2 = alloca i64, align 8 
    store %"class.std::vector"* %this, %"class.std::vector"** %1, align 8 
    store i64 %__n, i64* %2, align 8 
    %3 = load %"class.std::vector"** %1 
    %4 = bitcast %"class.std::vector"* %3 to %"struct.std::_Vector_base"* 
    %5 = getelementptr inbounds %"struct.std::_Vector_base"* %4, i32 0, i32 0 
    %6 = getelementptr inbounds %"struct.std::_Vector_base<double, std::allocator<double> >::_Vector_impl"* %5, i32 0, i32 0 
    %7 = load double** %6, align 8 
    %8 = load i64* %2, align 8 
    %9 = getelementptr inbounds double* %7, i64 %8 
    ret double* %9 
} 

Ich sehe, dass die [] aus der STL Definition aufgenommen wurde (Funktion @_ZNSt6vectorIdSaIdEEixEm) - fair genug. Das Problem ist: Es könnte auch eine Member-Funktion oder sogar ein direkter Datenzugriff sein, ich kann einfach nicht davon ausgehen, dass das Datenlayout überall gleich ist, so dass ich zur Entwicklungszeit das konkrete Layout des Hosts nicht kenne Maschine.

Gibt es eine Möglichkeit, C++ - Metaprogrammierung zu verwenden, um die erforderlichen Informationen zur Kompilierzeit zu erhalten? d. h. gibt es eine Möglichkeit, llvm zu bitten, IR für std::vectors [] Methode zur Verfügung zu stellen?

Als Bonus: Ich würde es vorziehen, die Kompilierung der Bibliothek nicht mit Clang zu erzwingen, sondern LLVM sollte eine Laufzeitabhängigkeit sein, also nur zur Compilierzeit aufrufen (auch wenn ich nicht weiß, wie das geht)) ist eine zweitbeste Lösung.

+0

Vielleicht ist es nur ich, aber ich verstehe völlig nicht das grundlegende Problem, das Sie versuchen zu lösen. Könnten Sie vielleicht klären? Was meinen Sie konkret mit "teilweise evaluieren"? Warum meinst du damit eine Methode zu haben, die "zur Laufzeit bekannt ist" - während sie eine "Konstante" in ihrem Namen hat? Warum schreibst du, dass '[]' inline war, aber du 2 verschiedene Funktionen eingefügt hast, und die erste nicht die zweite? – Oak

+0

Ich benutze den Begriff Partial Evaluation in der klassischen Bedeutung der Reduktion eines Begriffs basierend auf einem (teilweise) festen Input. Ich habe versucht, das Problem ein wenig zu erläutern. Mein aktuelles Problem ist, dass die Definition von '[]' vom Host (kompilierenden) System meiner Lib abhängt, so dass ich zur Entwicklungszeit keine Annahmen treffen kann. Stattdessen muss ich irgendwie das 'std :: vector' Layout zur Kompilierzeit bekommen. – choeger

+0

Danke für die Klarstellung, upvoted die Frage. – Oak

Antwort

3

meine eigene Frage zu beantworten:

Nach the C++ standard gilt die folgende für das Mitglied:

Während ich noch keine Lösung für den allgemeinen Fall (zB std::map), gibt für std::vector eine einfache Lösung besteht data() Funktion

Gibt einen direkten Pointer auf das Array Speicher intern vom Vektor verwendet seinen Besitz befindlichen Elemente zu speichern.

Weil Elemente in dem Vektor in zusammenhängenden Speicherplatz in der gleichen Reihenfolge gespeichert werden, sind garantiert als die Anordnung in jedes Element zuzugreifen versetzt von dem Vektor, den Zeiger abgerufen werden kann, dargestellt.

In der Tat ist das Objekt-Level-Layout von std::vector durch den Standard festgelegt.

Verwandte Themen