2014-12-19 4 views
6

Я добавил внутреннее значение коду ввода с использованием прохода LLVM. Я могу видеть внутренний вызов, но я не могу понять, как скомпилировать код для моей целевой архитектуры (x86_64). Я запускаю следующую команду:Добавление intrinsics с использованием пропусков LLVM

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

Но компоновщик жалуется на неопределенные ссылки:

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

Несмотря на использование LDFLAGS из LLVM-конфигурации, компиляция не проходит. Любые идеи о том, что следует делать для правильного компиляции кода?

Чтобы сгенерировать код сборки, я сделал следующее:

# 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 

Я в настоящее время использую LLVM версии 3.4.2; clang version 3.4.2 (теги/RELEASE_34/dot2-final); gcc версия 4.9.2 (GCC); и Linux 3.17.2-1-ARCH x86_64.


Edit: добавление IR с собственными:

Файл ~/LLVM/включать/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 }                  
... 

И звонки (из ff.s файлов):

... 
.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: Вот как я добавляю характеристическая во время отказа прохода:

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

вы можете поделиться LLVM IR с внутренней с обоими: призыв к внутренней и там декларации? –

+0

@MichaelHaidl Я добавил информацию о запросе. Я ожидал, что инкрементные вызовы будут расширены в ассоциированные встроенные, но вызов остается в файле сборки после компиляции. – Rubens

+0

Я говорил о LLVM IR. Вы можете использовать llvm-dis, чтобы сделать ваши .bc-файлы доступными для чтения или передать -S, чтобы выбрать. было бы также интересно, как вы добавляете внутренний и вызов в свой пропуск opt. в настоящее время выглядит так, что вызванная функция не является внутренней только функцией с тем же именем, что и внутренняя llvm. –

ответ

5

EDIT: Сейчас я пишу LLVM передать, что basicaly делать то, что вы пытались сделать в этом вопросе. Проблема с кодом заключается в следующем:

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

Вы пытаетесь получить замедление для встроенной функции с именем llvm.x86.sse3.mwait.i32.i32 и это искробезопасности не существует. Однако llvm.x86.sse3.mwait существует и для этого вы должны написать это:

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

уведомления недостающего типа аргумент в вызов. Это связано с тем, что llvm.x86.sse3.mwait не имеет перегрузок.

Надеюсь, вы разобрались в этом.

Хорошо, так как я хочу быть в состоянии ответить вам какое-то время, это ответ на дикий догадку.

Проблема заключается в том, как вы добавляете внутреннюю информацию через свой пропуск оптимизатора. Похоже, вы просто создаете функцию с тем же именем, что и внутреннее, а не внутреннее.

Вот небольшой код на C++, который просто использует встроенный clang для получения встроенного внутри IR (я использую clang 3.5, но это не должно иметь никакого влияния).

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

компиляция с clang -emit-llvm -S я получаю:

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

Пожалуйста, не то, что внутренняя SSE3 не имеют перегрузок типа, как и в вашей версии.

Использование ООО на созданный файл предоставляет мне:

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

Правильная сборка была создана.

Так что я предполагаю, что вы вводите внутреннюю функцию в неправильную в своем опционном проходе.

Получить внутреннюю функцию и называют его:

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

Спасибо за ответ. Я использую тот же самый метод, который вы указали, чтобы вставить внутреннюю функцию. Вы видите какую-то ошибку в моем коде, которая может отталкивать меня от того, чтобы получить внутреннее расширение в финальной сборке? Я чувствую, что пропускаю какой-либо флаг или аргумент при запуске 'llc', поскольку функция' llvm.x86.sse3.mwait.i32.i32' появляется в моей сборке. – Rubens

+0

Ну, это странно, попробуйте получить внутреннее провозглашение без чего-то в векторе типов. Возможно, проблема перегрузки типов. Если нет, вы можете посмотреть флаги командной строки -mcpu или -mattr из llc. –

+0

Не могли бы вы добавить, какие флаги вы использовали для генерации кода сборки с помощью 'llc'? Это может пролить свет на то, почему я не получаю расширение тела функции. – Rubens

Смежные вопросы