Search code examples
c++lambdallvmllvm-c++-api

add mapping to C++ lambda from LLVM


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)


Solution

  • 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));.