[llvm-dev] Add a mapping to a C++ lambda

David Blaikie via llvm-dev llvm-dev at lists.llvm.org
Wed Oct 28 21:31:59 PDT 2015


On Wed, Oct 28, 2015 at 9:23 PM, Lang Hames <lhames at gmail.com> wrote:

> Hi Courtney,
>
> There are at least two distinct issues here:
>
> (1) The error you're seeing from LLVM ("Tried to execute an unknown
> external function...") indicates that the mapping isn't working correctly,
> but your code for adding the global mapping looks good. There were some
> issues with the global mapping on older versions of LLVM, and that may be
> what you're running in to. What LLVM version and OS are you using?
>
> (2) As Ramkumar noted, the lambda has two distinct addresses associated
> with it: The closure (which I expect you get from &lambdaBody, though I'd
> have to check with a C++ expert), and the function (which I think of as
> "&<lambda>::operator()", but I don't know if that's really how C++ treats
> it). You may be able to get the lambda to execute by setting up the mapping
> to point to &<lambda>::operator() if you can figure out how to express it
> in C++, then passing the pointer to the closure as the sole argument to the
> function (you'll need to change lambdaFN's signature from int() to
> int(void*)). Whether this is guaranteed to work though I'm not sure.
>

Yep, pretty much everything there. Of course if you know the lambda is
stateless, you can convert it to a real function pointer (the common idiom
is to use unary '+' when you need to explicitly coerce a stateless lambda
into a function pointer):

  addGlobalMapping(lambdaFN, +lambdaBody);

& there's no guaranteed way to get a usable free function for a stateful
lambda. As you mentioned, you could try/cheat by taking the address of the
operator() member function, reinterpret casting that to a non-member
function with the extra first parameter then passing that when you want to
call it.


>
> Alternatively, if possible you can always wrap the lambda in a normal C
> function to make it easy to access:
>
> #include <...>
>
> auto MyLamba = []() { return 100; }
>
> int MyLambdaCaller() {
>   return MyLambda();
> }
>
> Now you can include all of your code from before, but map 'lambdaFN' to
> &MyLambdaCaller.
>
> Hope this helps!
>
> - Lang.
>
> On Tue, Oct 27, 2015 at 1:21 AM, Courtney Robinson via llvm-dev <
> llvm-dev at lists.llvm.org> wrote:
>
>> Apologies for the noop question in advance (just getting started with
>> LLVM), and I'm not entirely sure if this is the right list to post to. is
>> it?
>>
>> I have some lambda functions as member variables that I want to have my
>> LLVM language make calls to. I've added a mapping to them, but this doesn't
>> seem to enable LLVM to resolve the functions. I asked on stackoverflow but
>> the suggestion there didn't help. The minimal test case to reproduce what
>> I'm trying to do 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());
>>   auto 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;}
>>
>> The output is:
>>
>> 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
>>
>> The following suggestion was made on StackOveflow:
>> "
>> 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));.
>> "
>> However, after doing that, I get the same LLVM error message. How do I
>> get LLVM to call to a lambda? I am likely to have some C functions loaded
>> from a dynamic lib (I'll know the name and signatures), is it the same
>> process to call these as it is for lambdas?
>>
>> I know the Kaleidoscope example does std::sin so when it says it finds it
>> because it is within the same address space I thought this would work too...
>>
>> No suggestions or code samples welcome.
>>
>> Thanks in advance.
>> --
>> Courtney Robinson
>>
>>
>> _______________________________________________
>> LLVM Developers mailing list
>> llvm-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20151028/f0eb0f17/attachment.html>


More information about the llvm-dev mailing list