问题
I'm working on some code that uses the LLVM C API. How do I use intrinsics, such as llvm.cos.f64
or llvm.sadd.with.overflow.i32
? Whenever I try to do it by generating a global with LLVMAddGlobal
(with the correct type signature), I just get this error message during the JIT linking stage:
LLVM ERROR: Could not resolve external global address: llvm.cos.f64
I'm not using the LLVM C++ interface, so the advice in LLVM insert intrinsic function Cos does not seem to apply.
I presume I need something like Intrinsic::getDeclaration
, but I can't seem to find it. Am I missing something obvious?
回答1:
No need to leave the C API. Pass the intrinsic name to LLVMAddFunction
:
LLVMTypeRef param_types[] = {LLVMDoubleType()};
LLVMTypeRef fn_type = LLVMFunctionType(LLVMDoubleType(), param_types, 1, false);
LLVMValueRef fn = LLVMAddFunction(module, "llvm.cos.f64", fn_type);
Then you can generate a call to fn
with LLVMBuildCall
.
回答2:
I've now resolved this by writing a short piece of C++ code that calls the API I referenced in the other question, llvm::Intrinsic::getDeclaration
, and I use a little magic to get the list of legal intrinsics. I'd have rather done this with a pure C API, but my need for making things work is stronger than my need for strict language purity.
To get the list of names of intrinsics, I do this:
static const char *const intrinsicNames[] = {
#define GET_INTRINSIC_NAME_TABLE
#include "llvm/IR/Intrinsics.gen"
#undef GET_INTRINSIC_NAME_TABLE
};
This produces a sorted table, so I can use bsearch
to find the ID that I want.
static int search(const void *p1, const void *p2) {
const char *s1 = (const char *) p1;
const char *s2 = *(const char **) p2;
return strcmp(s1, s2);
}
int GetLLVMIntrinsicIDFromString(const char* str, llvm::Intrinsic::ID& id) {
void *ptr = bsearch(str, (const void *) intrinsicNames,
sizeof(intrinsicNames)/sizeof(const char *),
sizeof(const char *), search);
if (ptr == NULL)
return 0;
id = (llvm::Intrinsic::ID)((((const char**) ptr) - intrinsicNames) + 1);
return 1;
}
To get the actual intrinsic that I can then call, I do this (which requires a module reference and an argument type reference):
// Omitting exactly how I obtain these values but the types are mostly LLVM C API types.
// The only one that was awkward was the ID which was cast from an offset into that table above.
LLVMModuleRef mod = ...;
llvm::Intrinsic::ID = ...;
LLVMTypeRef ty = ...;
std::vector<llvm::Type *> arg_types;
arg_types.push_back(llvm::unwrap(ty));
LLVMValueRef rt = llvm::wrap(llvm::Intrinsic::getDeclaration(llvm::unwrap(mod), id, arg_types));
That LLVMValueRef
is suitable for use with the rest of the LLVM C API. The key is that I'm using llvm::unwrap
and llvm::wrap
.
来源:https://stackoverflow.com/questions/27681500/generate-call-to-intrinsic-using-llvm-c-api