How do I access definitions/instructions comprising llvm::Intrinsic operations?

Hello! First time posting, so I apologize if I am missing any conventions.

I am writing an IR pass (using the C++ API) that examines instruction mixes and I would like to learn more about interacting with LLVM’s intrinsic operations. I am trying to retrieve the instructions they translate to. In this particular case, I am looking at extracting the operations that llvm.memcpy.p0i8.p0i8.i64 corresponds to.

The function call that seems the most like what I need is llvm::Intrinsic::getDeclaration() which creates/inserts " an LLVM Function declaration for an intrinsic" and returns it. Ideally, what I would want from this function, then, is for it to return to me a Function object that corresponds to a series of IR instructions that match the behavior of the memcpy intrinsic. This may not be what the function does actually, but if it helps for context, that is what my goal is.

In my IR pass, I have successfully identified the IR call instruction and verified through getIntrinsicID() that it matches Intrinsic::memcpy. I then have a code snippet similar to below that I use to try and generate a function object for it:

//M is the module, intrinsicID is Intrinsic::memcpy
auto ptrType = Type::getInt8PtrTy(M->getContext());
auto int64Type = Type::getInt64Ty(M->getContext());
auto intrinsicFn = Intrinsic::getDeclaration(M, intrinsicID, {ptrType, ptrType, int64Type});

When I examine intrinsicFn after running this code, it appears that this function is an empty stub. It contains no basic blocks/instructions and has a size() of 0. I have tried running this as well without the types included, but this leads to a crash on an array comparison somewhere inside getType().

I have also tried this with llvm.fmuladd.f64 and I again have the issue of intrinsicFn being an empty function.

I have a few questions then:

  • Is my goal (retrieving intrinsic definitions in an IR pass) achievable? Or can these definitions not be known until later in the compiler pipeline?
  • Is getDeclaration() the proper method to be using in this case? If I can retrieve a Function that corresponds to the intrinsic, I should be able to work with that.
  • Am I missing some sort of import operation that needs to be done on my IR module? Maybe, because I have not imported the definition of llvm.memcpy, getDeclaration() cannot return it?

One last note, with the llvm.memcpy example, it may be that this operation lowers to the standard library call for memcpy, so I could take the source for that, compile it to IR and examine inside the module. Though for the sake of this pass, I would like for as much of this process to be automated as possible, as in, if these intrinsics were to all simply lower to standard library calls, I would like to be able to identify which functions they will lower to during the IR pass.

Please let me know if there is any more information I can provide, and thank you!

Hayden

Intrinsics, by definition, have no body. They may or may not later get expanded to something that involves making a real function call to a library routine, and where they get expanded can vary in the pipeline; some will be done in the IR, whilst some will be done during ISel.

1 Like

I gotcha, it looks like then from an instruction mix perspective intrinsics are a bit of a black box. So in this case it may be best for me to study individual intrinsics I am interested in instrumenting and create some form of model that estimates mix information based off of parameters to the intrinsic operation.

Thank you!