2014-12-19 26 views
6

Dodałem nieodłączne dla kodu wejściowego przy użyciu przepustki LLVM. Mogę zobaczyć wewnętrzne wywołanie, ale nie mogę wymyślić, jak skompilować kod do mojej architektury docelowej (x86_64). Używam następujące polecenia:Dodawanie intrinsics za pomocą LLVM pass

clang++ $(llvm-config --ldflags --libs all) ff.s -o foo 

Ale łącznik narzeka odniesień niezdefiniowanych:

/tmp/ff-2ada42.o: In function `fact(unsigned int)': 
/home/rubens/Desktop/ff.cpp:9: undefined reference to `llvm.x86.sse3.mwait.i32.i32' 
/tmp/ff-2ada42.o: In function `fib(unsigned int)': 
/home/rubens/Desktop/ff.cpp:16: undefined reference to `llvm.x86.sse3.mwait.i32.i32' 
/home/rubens/Desktop/ff.cpp:16: undefined reference to `llvm.x86.sse3.mwait.i32.i32' 
/home/rubens/Desktop/ff.cpp:16: undefined reference to `llvm.x86.sse3.mwait.i32.i32' 

Pomimo zastosowania LDFLAGS z LLVM-config, kompilacja nie kontynuować. Jakieś pomysły dotyczące tego, co należy zrobić, aby kod mógł się poprawnie skompilować?

Aby wygenerować kod montażową, Robiłem co następuje:

# Generating optimized code 
clang++ $(llvm-config --cxxflags) -emit-llvm -c ff.cpp -o ff.bc 
opt ff.bc -load path/to/mypass.so -mypass > opt_ff.bc 

# Generating assembly 
llc opt_ff.bc -o ff.s 

obecnie używam wersji 3.4.2 LLVM; clang version 3.4.2 (tags/RELEASE_34/dot2-final); wersja gcc 4.9.2 (GCC); i Linux 3.17.2-1-ARCH x86_64.


Edit: dodawanie IR ze swoistych:

pliku ~/LLVM/include/LLVM/IR/IntrinsicsX86.td:

... 
589 // Thread synchronization ops.           
590 let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". 
591  def int_x86_sse3_monitor : GCCBuiltin<"__builtin_ia32_monitor">,  
592    Intrinsic<[], [llvm_ptr_ty,        
593       llvm_i32_ty, llvm_i32_ty], []>;     
594  def int_x86_sse3_mwait : GCCBuiltin<"__builtin_ia32_mwait">,   
595    Intrinsic<[], [llvm_i32_ty,        
596       llvm_i32_ty], []>;        
597 }                  
... 

i wzywa (od ff.s plików):

... 
.Ltmp2:          
    callq llvm.x86.sse3.mwait.i32.i32 
    movl $_ZStL8__ioinit, %edi   
    callq _ZNSt8ios_base4InitC1Ev  
    movl $_ZNSt8ios_base4InitD1Ev, %edi 
    movl $_ZStL8__ioinit, %esi   
    movl $__dso_handle, %edx   
    callq __cxa_atexit     
    popq %rax       
    ret         
... 

Edit 2: Oto jak Dodaję wewnętrzna podczas przełęczy opt:

Function *f(bb->getParent()); 
Module *m(f->getParent()); 

std::vector<Type *> types(2, Type::getInt32Ty(getGlobalContext())); 
Function *mwait = Intrinsic::getDeclaration(m, Intrinsic::x86_sse3_mwait, types); 

std::vector<Value *> args; 
IRBuilder<> builder(&bb->front()); 
for (uint32_t i : {1, 2}) args.push_back(builder.getInt32(i)); 

ArrayRef<Value *> args_ref(args); 
builder.CreateCall(mwait, args_ref); 
+0

można udostępnić LLVM IR z wewnętrzną z obu: wezwanie do wewnętrznej i tam deklaracji? –

+0

@MichaelHaidl Dodałem informacje o żądaniu. Oczekiwano, że wywołania instrinetyczne zostaną rozszerzone na wbudowane wbudowane, ale wywołanie pozostaje w pliku złożenia po kompilacji. – Rubens

+0

Mówiłem o LLVM IR. Możesz użyć llvm-dis, aby pliki .bc były czytelne lub przekazać -S do wyboru. Byłoby również interesujące, jak dodać wewnętrzne i wywołanie w swoim podaniu opt. obecnie wygląda na to, że wywoływana funkcja nie jest wewnętrzną funkcją o tej samej nazwie, co nazwa wewnętrzna llvm. –

Odpowiedz

5

EDIT: Jestem obecnie pisania LLVM przekazać, że jest basicaly robić to, co próbował zrobić w tej kwestii. Problem z kodem jest następujący:

std::vector<Type *> types(2, Type::getInt32Ty(getGlobalContext())); 
Function *mwait = Intrinsic::getDeclaration(m, Intrinsic::x86_sse3_mwait, types); 

Próbujesz uzyskać opóźnienie dla nieodłącznym funkcji o nazwie llvm.x86.sse3.mwait.i32.i32 i to samoistne nie istnieje. Jednak llvm.x86.sse3.mwait istnieje i do nich trzeba napisać to:

Function *mwait = Intrinsic::getDeclaration(m, Intrinsic::x86_sse3_mwait); 

Zawiadomienie brakującym typu argument wywołania. Dzieje się tak, ponieważ plik llvm.x86.sse3.mwait nie ma przeciążenia.

Mam nadzieję, że wymyśliłeś to w międzyczasie.


Ok, ponieważ chcę być w stanie odpowiedzieć na ciebie przez chwilę tutaj jest dzikie odgadnąć odpowiedź.

Problem polega na tym, że dodajesz samoistne przez przepustkę optymalizatora. Wygląda na to, że właśnie tworzysz funkcję o tej samej nazwie, co samo wewnętrzne, a nie samoistne.

Oto mały kod w C++, który po prostu używa wbudowanego klanga, aby uzyskać wewnętrzną wartość wewnątrz IR (używam clang 3.5, ale to nie powinno mieć żadnego wpływu).

int main() 
{ 
    __builtin_ia32_mwait(4,2); 
} 

Kompilacja go clang -emit-llvm -S uzyskać:

; ModuleID = 'intrin.cpp' 
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 
target triple = "x86_64-unknown-linux-gnu" 

; Function Attrs: nounwind uwtable 
define i32 @main() #0 { 
    call void @llvm.x86.sse3.mwait(i32 4, i32 2) 
    ret i32 0 
} 

; Function Attrs: nounwind 
declare void @llvm.x86.sse3.mwait(i32, i32) #1 

attributes #0 = { nounwind uwtable "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" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } 
attributes #1 = { nounwind } 

!llvm.ident = !{!0} 

!0 = metadata !{metadata !"clang version 3.5.0 "} 

nie proszę, że nieodłącznym SSE3 ma przeciążeń typu jak w swojej wersji.

Korzystanie LLC na wygenerowanym pliku zapewnia mnie:

.Ltmp2: 
     .cfi_def_cfa_register %rbp 
     movl $4, %ecx 
     movl $2, %eax 
     mwait 
     xorl %eax, %eax 
     popq %rbp 
     retq 

Właściwa Zespół został utworzony.

Zakładam, że sposób, w jaki wprowadzasz samoistnie do funkcji, jest nieprawidłowy w twoim podaniu opt.

Get wewnętrzną funkcję i wywołać ją:

vector<Type*> types; 
types.push_back(IntegerType::get(/*LLVM context*/, 32)); 
types.push_back(IntegerType::get(/*LLVM context*/, 32)); 

Function* func = Intrinsic::getDeclaration(/* module */, Intrinsic::x86_sse3_mwait, types); 
CallInst* call = CallInst::Create(func, /* arguments */); 

+0

Dzięki za odpowiedź. Używam prawie tej samej metody, którą wskazałeś, aby wstawić wewnętrzną funkcję. Czy widzisz jakąś pułapkę w moim kodzie, która może przeszkadzać mi w uzyskaniu wewnętrznego rozszerzenia w ostatecznym montażu? Czuję, że brakuje mi jakiejś flagi lub argumentu podczas uruchamiania 'llc', ponieważ funkcja' llvm.x86.sse3.mwait.i32.i32' pojawia się w moim zespole. – Rubens

+0

Cóż, to jest dziwne, spróbuj uzyskać wewnętrzną deklaminację bez czegoś w wektorach typów. Być może problemem jest przeciążenie typu. Jeśli nie, możesz spojrzeć na flagi linii poleceń -mcpu lub -mattr z języka llc. –

+0

Czy mógłbyś dodać, które flagi użyłeś do wygenerowania kodu złożenia za pomocą 'llc'? To może rzucić trochę światła na to, dlaczego nie rozszerzam funkcji ciała. – Rubens