我正在使用LLVM实现JIT编译器的前端。我开始遵循LLVM教程中的Kaleidoscope示例。我知道如何使用LLVM C ++ API生成和JIT LLVM IR。我也知道如何使用llvm :: ExecutionEngine的“getPointerToFunction”方法调用JITed函数。
getPointerToFunction返回一个void *,然后我必须将其转换为正确的函数类型。例如,在我的编译器中,我有单元测试,如下所示:
void* compiled_func = compiler.get_function("f");
auto f = reinterpret_cast<int32_t(*)(int32_t)>(compiled_func);
int32_t result = f(10);
问题是我必须事先知道函数签名。在上面的例子中,我有一个函数“f”,它取一个32位整数并返回一个32位整数。由于我自己创建“f”,我知道函数类型是什么,所以我可以调用JIT的函数。但是,一般来说,我不知道用户输入的函数签名是什么(或者结构类型是什么)。用户可以使用任意参数和返回类型创建任意函数,因此我不知道从LLVM的getPointerToFunction强制转换void *的函数指针类型。我的运行时需要能够调用这些函数(例如,对于Read-Evaluate-Print循环)。如何从JIT运行时处理这些任意函数?
由于
答案 0 :(得分:2)
你可以从compiled_func
获得的信息不多 - 正如你所写的,它只是void*
。但是当你写“一般来说,我不知道函数签名是什么”时,这是不准确的 - 你刚刚编译了那个函数,所以你应该可以访问LLVM Function
对象,可以查询关于它的类型。确实,它是LLVM IR类型而不是C ++类型,但您通常可以知道哪些转换为哪种类型。
例如,如果我们从tutorial's section on JITting Kaleidoscope借用代码:
if (Function *LF = F->Codegen()) {
LF->dump(); // Dump the function for exposition purposes.
// JIT the function, returning a function pointer.
void *FPtr = TheExecutionEngine->getPointerToFunction(LF);
// Cast it to the right type (takes no arguments, returns a double) so we
// can call it as a native function.
double (*FP)() = (double (*)())(intptr_t)FPtr;
fprintf(stderr, "Evaluated to %f\n", FP());
}
然后是的,FPtr
被“假设”为double ()
类型,但此处还有LF
Function*
类型,所以你可以做了类似的事情:
Type* RetTy = LF->getReturnType();
if (RetTy->isDoubleTy()) {
double (*FP)() = (double (*)())(intptr_t)FPtr;
fprintf(stderr, "Evaluated to %f\n", FP());
} else if (RetTy->isIntegerTy(32)) {
int (*FP)() = (int (*)())(intptr_t)FPtr;
fprintf(stderr, "Evaluated to %d\n", FP());
} else ...
以同样的方式,您可以查询有关其参数类型的函数。
有点累赘吗?您可以使用您的执行引擎通过其方便的runFunction
方法调用该函数,该方法接收GenericValue
s的向量并返回GenericValue
。您仍应查询Function
类型,以查找每个GenericValue
下的基础类型。