使用LLVM传递添加内在函数 [英] Adding intrinsics using an LLVM pass

查看:1415
本文介绍了使用LLVM传递添加内在函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用LLVM传递向输入代码添加了一个内在函数。我能看到固有的调用,但我不知道如何编译代码到我的目标架构(x86_64)。我运行以下命令:

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

但是链接器引用了未定义的引用:

  /tmp/ff-2ada42.o:在函数`fact(unsigned int)'中:
/home/rubens/Desktop/ff.cpp:9:undefined引用`llvm.x86.sse3.mwait.i32.i32'
/tmp/ff-2ada42.o:在函数`fib(unsigned int)'中:
/ home / rubens / Desktop / ff .cpp:16:未定义引用`llvm.x86.sse3.mwait.i32.i32'
/home/rubens/Desktop/ff.cpp:16:未定义对`llvm.x86.sse3.mwait的引用。 i32.i32'
/home/rubens/Desktop/ff.cpp:16:未定义引用`llvm.x86.sse3.mwait.i32.i32'

尽管使用llvm-config中的ldflags,编译不会继续。有关如何正确编译代码的任何想法?



要生成汇编代码,我已经做了以下工作:

 #生成优化代码
clang ++ $(llvm-config --cxxflags)-emit-llvm -c ff.cpp -o ff.bc
opt ff.bc -load path / to / mypass.so -mypass> opt_ff.bc

#生成程序集
llc opt_ff.bc -o ff.s

我目前使用llvm版本3.4.2; clang version 3.4.2(tags / RELEASE_34 / dot2-final); gcc version 4.9.2(GCC);和Linux 3.17.2-1-ARCH x86_64。






编辑:

文件〜/ llvm / include / llvm / IR / IntrinsicsX86.td:

  ... 
589 //线程同步操作。
590 let TargetPrefix =x86in {//所有内在函数以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}
...

):

  ... 
.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
...



< hr>

编辑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<>构建器(& bb-> front());
for(uint32_t i:{1,2})args.push_back(builder.getInt32(i));

ArrayRef< Value *> args_ref(args);
builder.CreateCall(mwait,args_ref);


解决方案

EDIT:
我目前正在写一个LLVM pass,这是根据你在这个问题中尝试做的。您的代码的问题如下:

  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不存在。然而,llvm.x86.sse3.mwait存在,因此你必须写这个:

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

注意调用的缺少类型参数。这是因为llvm.x86.sse3.mwait没有重载。



我希望你能在此期间想出来。






Ok,因为我想在这里回答你一段时间是一个疯狂的猜测答案。



问题是你通过优化器传递添加内在的方式。看起来你只是创建一个与内在函数同名的函数而不是内在本身。



这里是一个只使用clang内置函数的C ++代码得到内在的IR(我使用clang 3.5,但这不应该有任何影响)。

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

使用 clang -emit-llvm -S 我得到:

 ; ModuleID ='intrin.cpp'
target datalayout =em:e-i64:64-f80:128-n8:16:32:64-S128
target triple =x86_64-unknown-linux -gnu

;函数Attrs:nounwind uwtable
定义i32 @main()#0 {
call void @ llvm.x86.sse3.mwait(i32 4,i32 2)
ret i32 0
}

;函数Attrs:nounwind
declare void @ llvm.x86.sse3.mwait(i32,i32)#1

属性#0 = {nounwind uwtableless-precise-fpmad=false no-inf-fp-math=falseno-nans-fp-math=no-frame-pointer-elim-non-leaf falsestack-protector-buffer-size=8unsafe-fp-math=falseuse-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.push_back(IntegerType :: get(/ * LLVM context * /,32));
types.push_back(IntegerType :: get(/ * LLVM context * /,32));

函数* func = Intrinsic :: getDeclaration(/ * module * /,Intrinsic :: x86_sse3_mwait,types);
CallInst * call = CallInst :: Create(func,/ * arguments * /);


I've added an intrinsic to an input code using an LLVM pass. I'm able to see the intrinsic call, yet I can't figure out how to compile the code to my target architecture (x86_64). I'm running the following command:

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

But the linker complains about undefined references:

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

Despite using ldflags from llvm-config, the compilation does not proceed. Any ideas on what should be done for the code to compile properly?

To generate the assembly code, I've done the following:

# 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

I'm currently using llvm version 3.4.2; clang version 3.4.2 (tags/RELEASE_34/dot2-final); gcc version 4.9.2 (GCC); and Linux 3.17.2-1-ARCH x86_64.


Edit: adding the IR with the intrinsic:

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 }                                                                       
...

And calls (from file 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: Here's how I'm adding the intrinsic during the 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);

解决方案

EDIT: I am currently writing an LLVM pass that is basicaly doing what you tried to do in this question. The problem with your code is the following:

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

You are trying to get the deceleration for an Intrinsic function with the name llvm.x86.sse3.mwait.i32.i32 and this Intrinsic does not exist. However, llvm.x86.sse3.mwait exists and therefor you have to write this:

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

notice the missing type argument to the call. This is because llvm.x86.sse3.mwait has no overloadings.

I hope you figured it out in the meantime.


Ok since I want be able to answer you for a while here is a wild guess answer.

The problem is the way you add the intrinsic through your optimizer pass. It looks like you are just creating a function with the same name as the intrinsic not the intrinsic itself.

Here is a little C++ code that just uses the clang built-in to get the intrinsic inside the IR (I use clang 3.5 but this should not have any impact).

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

Compiling it with clang -emit-llvm -S I get:

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

Please not that the SSE3 intrinsic has no type overloads like in your version.

Using llc on the generated file provides me:

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

Proper assembly was created.

So I assume the way you are introducing the intrinsic into the function is wrong in your opt pass.

Get the intrinsic function and call it:

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 */);

这篇关于使用LLVM传递添加内在函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆