Search code examples
llvminline-assemblyllvm-clangllvm-ir

How to convert function insertion module pass to intrinsic to inline


PROBLEM: I currently have a traditional module instrumentation pass that inserts new function calls into a given IR according to some logic (inserted functions are external from a small lib that is later linked to given program). Running experiments, my overhead is from the cost of executing a function call to the library function.

What I am trying to do: I would like to inline these function bodies into the IR of the given program to get rid of this bottleneck. I assume an intrinsic would be a clean way of doing this, since an intrinsic function would be expanded to its function body when being lowered to ASM (please correct me if my understanding is incorrect here, this is my first time working with intrinsics/LTO).

Current Status:

My original library call definition:

void register_my_mem(void *user_vaddr){
  ... C code ...
}

So far:

  • I have created a def in: llvm-project/llvm/include/llvm/IR/IntrinsicsX86.td

    let TargetPrefix = "x86" in { def int_x86_register_mem : GCCBuiltin<"__builtin_register_my_mem">, Intrinsic<[], [llvm_anyint_ty], []>; }

  • Added another def in: otwm/llvm-project/clang/include/clang/Basic/BuiltinsX86.def

    TARGET_BUILTIN(__builtin_register_my_mem, "vv*", "", "")

  • Added my library source (*.c, *.h) to the compiler-rt/lib/test_lib and added to CMakeLists.txt

  • Replaced the function insertion with trying to insert the intrinsic instead in: llvm/lib/Transforms/Instrumentation/myModulePass.cpp

WAS:

FunctionCallee sm_func =
curr_inst->getModule()->getOrInsertFunction("register_my_mem",
func_type);
ArrayRef<Value*> args = {
      builder.CreatePointerCast(sm_arg_val, currType->getPointerTo())
};
builder.CreateCall(sm_func, args);

NEW:

Intrinsic::ID aREGISTER(Intrinsic::x86_register_my_mem);
Function *sm_func = Intrinsic::getDeclaration(currFunc->getParent(),
aREGISTER, func_type);
ArrayRef<Value*> args = {
      builder.CreatePointerCast(sm_arg_val, currType->getPointerTo())
};
builder.CreateCall(sm_func, args);

Questions:

  1. If my logic for inserting the intrinsic functions shouldnt be a module pass, where do i put it?
  2. Am I confusing LTO with intrinsics?
  3. Do I put my library function definitions into the following files as mentioned in http://lists.llvm.org/pipermail/llvm-dev/2017-June/114322.html as for example EmitRegisterMyMem()?
    • clang/lib/CodeGen/CodeGenFunction.cpp - define llvm::Instrinsic::ID
    • clang/lib/CodeGen/CodeGenFunction.h - declare llvm::Intrinsic::ID

My LLVM compiles, so it is semantically correct, but currently when trying to insert this function call, LLVM segfaults saying "Not a valid type for function argument!"


Solution

  • I'm seeing multiple issues here.

    Indeed, you're confusing LTO with intrinsics. Intrinsics are special "functions" that are either expanded into special instructions by a backend or lowered to library function calls. This is certainly not something you're going to achieve. You don't need an intrinsic at all, you'd just need to inline the function call in question: either by hands (from your module pass) or via LTO, indeed.

    The particular error comes because you're declaring your intrinsic as receiving an integer argument (and this is how the declaration would look like), but:

    • asking the declaration of variadic intrinsic with invalid type (I'd assume your func_type is a non-integer type)
    • passing pointer argument

    Hope this makes an issue clear.


    See also: https://llvm.org/docs/LinkTimeOptimization.html