使用LLVM通过添加内在函数

问题描述 投票:6回答:2

我已经使用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 pass期间添加内在函数的方式:

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);
c++ linker llvm undefined-reference llvm-ir
2个回答
6
投票

编辑:我目前正在编写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的本征函数的减速度,并且该本征不存在。但是,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

已创建正确的程序集。

所以我认为您在选择过程中将内在函数引入函数的方式是错误的。

获取内部函数并调用它:

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
投票

“ Builder.CreateBinaryIntrinsic(Intrinsic :: expect,Trap_ICMP,Expect_Value);”

© www.soinside.com 2019 - 2024. All rights reserved.