[英]Adding intrinsics using an LLVM pass
我已經使用 LLVM 傳遞向輸入代碼添加了一個內在函數。 我能夠看到內部調用,但我不知道如何將代碼編譯到我的目標架構 (x86_64)。 我正在運行以下命令:
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'
盡管使用了 llvm-config 中的 ldflags,但編譯不會繼續。 關於正確編譯代碼應該做什么的任何想法?
為了生成匯編代碼,我完成了以下操作:
# 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 版本 3.4.2 (tags/RELEASE_34/dot2-final); gcc 版本 4.9.2 (GCC); 和 Linux 3.17.2-1-ARCH x86_64。
編輯:添加具有內在特性的 IR:
文件 ~/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 }
...
並調用(來自文件 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
...
編輯 2:這是我在 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);
編輯:我目前正在編寫一個 LLVM 通行證,它基本上是在做你在這個問題中試圖做的事情。 您的代碼的問題如下:
std::vector<Type *> types(2, Type::getInt32Ty(getGlobalContext()));
Function *mwait = Intrinsic::getDeclaration(m, Intrinsic::x86_sse3_mwait, types);
您正在嘗試獲取名為 llvm.x86.sse3.mwait.i32.i32 的 Intrinsic 函數的減速,但此 Intrinsic 不存在。 但是, 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 內在函數沒有像您的版本中那樣的類型重載。
在生成的文件上使用 llc 為我提供:
.Ltmp2:
.cfi_def_cfa_register %rbp
movl $4, %ecx
movl $2, %eax
mwait
xorl %eax, %eax
popq %rbp
retq
正確的裝配體已創建。
因此,我假設您在 opt pass 中將內在函數引入函數的方式是錯誤的。
獲取內部函數並調用它:
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 */);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.