簡體   English   中英

使用 LLVM 傳遞添加內部函數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM