使用 LLVM C API 生成对内部函数的调用

Posted

技术标签:

【中文标题】使用 LLVM C API 生成对内部函数的调用【英文标题】:Generate call to intrinsic using LLVM C API 【发布时间】:2014-12-28 23:01:53 【问题描述】:

我正在编写一些使用 LLVM C API 的代码。如何使用内部函数,例如 llvm.cos.f64llvm.sadd.with.overflow.i32?每当我尝试通过使用LLVMAddGlobal(具有正确的类型签名)生成全局来执行此操作时,我只会在 JIT 链接阶段收到此错误消息:

LLVM 错误:无法解析外部全局地址:llvm.cos.f64

我没有使用 LLVM C++ 接口,所以LLVM insert intrinsic function Cos 中的建议似乎不适用。

我想我需要Intrinsic::getDeclaration 之类的东西,但我似乎找不到它。我错过了什么明显的东西吗?

【问题讨论】:

【参考方案1】:

无需离开 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);

然后您可以使用LLVMBuildCall 生成对fn 的调用。

【讨论】:

这是我遇到同样问题时发现的堆栈溢出问题 :)【参考方案2】:

我现在已经通过编写一小段 C++ 代码来解决这个问题,该代码调用我在另一个问题llvm::Intrinsic::getDeclaration 中引用的 API,并且我使用了一点魔法来获取合法内在函数的列表。我宁愿使用纯 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::unwrapllvm::wrap

【讨论】:

以上是关于使用 LLVM C API 生成对内部函数的调用的主要内容,如果未能解决你的问题,请参考以下文章

要做一个根据C代码自动生成函数调用关系图的小程序

在 LLVM-C API 中确定和设置主机目标三元组和指令扩展

使用 LLVM c++ API 创建“类”定义

LLVM 对函数参数的位码错误检测

Impala中 LLVM 的交叉编译、调用过程

如何使用 Clang 在 C 程序中嵌入 LLVM 程序集或内在函数?