I have a set of lambdas that wrap a C++ method call and I want to call these with LLVM. My attempt seems to be missing something, even after declaring the type and adding a global mapping to the lambda, I get an LLVM error. The minimal code to reproduce what I tried is:
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/TargetSelect.h"
using namespace llvm;
int main() {
InitializeNativeTarget();
LLVMContext Context;
std::unique_ptr<Module> Owner = make_unique<Module>("SomeModule", Context);
Module *M = Owner.get();
FunctionType *lambdaFT = FunctionType::get(Type::getInt32Ty(Context), false);
Function *lambdaFN = Function::Create(lambdaFT, Function::ExternalLinkage, "lambda", Owner.get());
//this is what the original question had
//auto lambdaBody = []() { return 100; };
//this is an edit after Johannes Schaub's answer
int32_t ( *lambdaBody)() = +[]() { return 100; };
Function *mainF = cast<Function>(M->getOrInsertFunction("main", Type::getInt32Ty(Context), (Type *) 0));
BasicBlock *BB = BasicBlock::Create(Context, "EntryBlock", mainF);
IRBuilder<> builder(BB);
CallInst *lambdaRes = builder.CreateCall(lambdaFN, std::vector<Value *>(), "lambdaRetVar");
builder.CreateRet(lambdaRes);
ExecutionEngine *EE = EngineBuilder(std::move(Owner)).create();
EE->addGlobalMapping(lambdaFN, &lambdaBody);
outs() << "We just constructed this LLVM module:\n\n" << *M;
outs() << "\n\nRunning main: ";
std::vector<GenericValue> noargs;
GenericValue gv = EE->runFunction(mainF, noargs);
outs() << "Result: " << gv.IntVal << "\n";
llvm_shutdown();
delete EE;
return 0;
}
This results in the output:
We just constructed this LLVM module:
; ModuleID = 'SomeModule'
declare i32 @lambda()
define i32 @main() {
EntryBlock:
%lambdaRetVar = call i32 @lambda()
ret i32 %lambdaRetVar
}
Running main:
LLVM ERROR: Tried to execute an unknown external function: lambda
What am I doing wrong?
Using LLVM 3.7.0
(tag doesn't exist)
Your lambda body is a class. You must pass the address of its function call operator, which you can do by converting it to a function pointer: auto lambdaBody = +[]() { return 100; };
and passing it as a void*
: EE->addGlobalMapping(lambdaFN, reinterpret_cast<void*>(lambdaBody));
.