Adding Built-in Functions Using LLVM Pass

I added inline input code using the LLVM pass. I can see the internal call, but I cannot figure out how to compile the code for my target architecture (x86_64). I execute the following command:

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

But the linker complains about undefined links:

 /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, compilation does not continue. Any ideas on what to do to properly compile the code?

To generate the assembly code, I did 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 am 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 IR with internal:

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 the calls (from the ff.s file):

 ... .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, as I add the internal value during opt transition:

 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); 
+6
source share
1 answer

EDIT: I am currently writing an LLVM pass that basically does what you tried to do in this question. The problem with your code is as follows:

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

You are trying to get braking for an Intrinsic function named llvm.x86.sse3.mwait.i32.i32, and this Intrinsic does not exist. However, llvm.x86.sse3.mwait exists, and so you need to write this:

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

Note the missing type argument to invoke. This is because llvm.x86.sse3.mwait does not have overloads.

I hope you figured this out.


Well, since I want to be able to answer you for a while, this is the answer to the question.

The problem is how you add inside information through your optimizer pass. It looks like you are just creating a function with the same name as the internal one, not the internal one.

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

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

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

 ; ModuleID = 'intrin.cpp' target datalayout = "em: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 built-in SSE3 does not have overload types like in your version.

Using llc in the generated file provides me with:

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

The corresponding assembly has been created.

So, I assume that the way you enter the internal value into the function is incorrect in your optional pass.

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

+5
source

Source: https://habr.com/ru/post/979934/


All Articles