2014-12-19 14 views
6

Ho aggiunto un valore intrinseco a un codice di input utilizzando un pass LLVM. Sono in grado di vedere la chiamata intrinseca, ma non riesco a capire come compilare il codice per la mia architettura di destinazione (x86_64). Sto eseguendo il comando seguente:Aggiunta di elementi intrinseci utilizzando un pass LLVM

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

Ma il linker si lamenta riferimenti indefiniti:

/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' 

Nonostante l'uso di ldflags da LLVM-config, la compilazione non procede. Qualche idea su cosa dovrebbe essere fatto per il codice da compilare correttamente?

Per generare il codice assembly, ho fatto quanto segue:

# 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 

Attualmente sto usando LLVM versione 3.4.2; clang versione 3.4.2 (tag/RELEASE_34/dot2-final); gcc versione 4.9.2 (GCC); e Linux 3.17.2-1-ARCH x86_64.


Edit: aggiungere il IR con le intrinseche:

file ~/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 }                  
... 

e chiamate (da ff.s di file):

... 
.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: Ecco come sto aggiungendo l'intrinseca durante il passaggio di 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

è possibile condividere la LLVM IR con l'intrinseca con entrambi: la chiamata alla dichiarazione intrinseca e là? –

+0

@MichaelHaidl Ho aggiunto le informazioni sulla richiesta. Mi aspettavo che le chiamate instrinsic fossero espanse nei builtin associati, ma la chiamata rimane nel file assembly dopo la compilazione. – Rubens

+0

Ho parlato dell'LLVM IR. Puoi usare llvm-dis per rendere leggibili i file .bc o passare -S per optare. sarebbe anche interessante come si aggiungono l'intrinseco e la chiamata nel proprio passaggio opt. al momento sembra che la funzione chiamata non sia intrinseca solo una funzione con lo stesso nome di llvm intrinsic. –

risposta

5

EDIT: Attualmente sto scrivendo un LLVM pass che sta basicaly facendo quello che si è tentato di fare in questa domanda. Il problema con il codice è il seguente:

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

Si sta cercando di ottenere la decelerazione per una funzione intrinseca con il nome llvm.x86.sse3.mwait.i32.i32 e questo intrinseca non esiste. Tuttavia, llvm.x86.sse3.mwait esiste e per questo si deve scrivere questo:

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

avviso il tipo di argomento mancante alla chiamata. Questo perché llvm.x86.sse3.mwait non ha sovraccarichi.

Spero che l'abbia capito nel frattempo.


Ok visto che voglio essere in grado di risponderti per un po 'ecco una risposta selvaggia.

Il problema è il modo in cui si aggiunge l'intrinseco attraverso il pass dell'ottimizzatore. Sembra che tu stia solo creando una funzione con lo stesso nome dell'intrinseca non della stessa intrinseca.

Ecco un piccolo codice C++ che utilizza solo il clang incorporato per ottenere l'intrinseco all'interno dell'IR (io uso clang 3.5 ma questo non dovrebbe avere alcun impatto).

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

compilazione con clang -emit-llvm -S ottengo:

; 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 "} 

prega di notare che l'intrinseca SSE3 non ha un tipo sovraccarichi come nella vostra versione.

Utilizzando llc sul file generato mi offre:

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

montaggio corretto è stato creato.

Quindi presumo che il modo in cui si introduce l'intrinseco nella funzione sia errato nel proprio passaggio opt.

Ottenere la funzione intrinseca e lo chiamano:

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

Grazie per la risposta. Sto usando più o meno lo stesso metodo che hai indicato per inserire la funzione intrinseca. Vedi qualche trappola nel mio codice che potrebbe impedirmi di ottenere l'espansione intrinseca nell'assemblaggio finale? Mi sembra di non avere alcun flag o argomento durante l'esecuzione di 'llc', perché la funzione' llvm.x86.sse3.mwait.i32.i32' viene visualizzata nel mio assieme. – Rubens

+0

Beh, questo è strano, cerca di ottenere la decodificazione intrinseca senza qualcosa nel vettore dei tipi. Forse il tipo di overload è il problema. Se non lo è, puoi guardare i flag della riga di comando -mcpu o -mattr da llc. –

+0

Ti dispiacerebbe aggiungere quali flag hai usato per generare il codice assembly con 'llc'? Ciò potrebbe far luce sul motivo per cui non sto espandendo il corpo della funzione. – Rubens