我正在处理一些使用 LLVM C API 的代码。我如何使用内在函数,例如llvm.cos.f64或llvm.sadd.with.overflow.i32?每当我尝试通过生成全局 with LLVMAddGlobal(具有正确的类型签名)来执行此操作时,我只会在 JIT 链接阶段收到此错误消息:
LLVM 错误:无法解析外部全局地址:llvm.cos.f64
我没有使用 LLVM C++ interface,因此LLVM 插入内在函数 Cos中的建议似乎并不适用。
我想我需要类似的东西Intrinsic::getDeclaration,但我似乎找不到它。我错过了一些明显的东西吗?
无需离开 C API。将内部名称传递给  LLVMAddFunction:
LLVMTypeRef param_types[] = {LLVMDoubleType()};
LLVMTypeRef fn_type = LLVMFunctionType(LLVMDoubleType(), param_types, 1, false);
LLVMValueRef fn = LLVMAddFunction(module, "llvm.cos.f64", fn_type);
然后您可以生成对fnwith的调用LLVMBuildCall。
我现在通过编写一小段 C++ 代码来解决这个问题,该代码调用我在另一个问题 中引用的 API llvm::Intrinsic::getDeclaration,并且我使用了一点魔法来获取合法内在函数的列表。我宁愿使用纯 C API 来完成此操作,但我对使事情正常工作的需求比对严格语言纯度的需求更强烈。
要获取内在函数名称列表,我这样做:
static const char *const intrinsicNames[] = {
#define GET_INTRINSIC_NAME_TABLE
#include "llvm/IR/Intrinsics.gen"
#undef GET_INTRINSIC_NAME_TABLE
};
这会生成一个排序表,因此我可以用来bsearch查找所需的 ID。
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;
}
为了获得可以调用的实际内在函数,我这样做(这需要模块引用和参数类型引用):
// 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));
这LLVMValueRef适合与 LLVM C API 的其余部分一起使用。关键是我正在使用llvm::unwrap和llvm::wrap。