I am working on a JIT like thing. I have the following code:
Obj doSomething(Obj o, Selector sel){
...
}
And I have a pointer to this function, my question is how can I wrap the pointer up into a LLVM:Value so that I can insert it into my IR, using IRBuilder.CreateCall, What do I need to do?
I was struggling with something similar. My toy program is equivalent to the following C program, but generating the function boo() at run time:
#include <stdio.h>
typedef int (*callback)(const char*);
static int boo(callback print, const char *str) { return print(str); }
int main() { return boo(puts, "hello world"); }
I believe that my solution should work at least with LLVM 9 through 14, based on testing with those two versions.
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
int main()
{
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
auto C = std::make_unique<llvm::LLVMContext>();
auto M = std::make_unique<llvm::Module>("boomodule", *C);
const auto ArgType = llvm::Type::getInt8Ty(*C)->getPointerTo();
std::vector<llvm::Type *> PutsArgs{ArgType};
llvm::FunctionType *PutsType =
llvm::FunctionType::get(llvm::Type::getInt32Ty(*C), PutsArgs, false);
llvm::FunctionType *FT =
llvm::FunctionType::get(llvm::Type::getInt32Ty(*C),
{PutsType->getPointerTo(), ArgType}, false);
{
llvm::Function *TheFunction =
llvm::Function::Create(FT, llvm::Function::ExternalLinkage,
"boo", M.get());
{
llvm::IRBuilder<> builder(llvm::BasicBlock::Create(*C, "entry",
TheFunction));
auto Arg = TheFunction->arg_begin();
llvm::FunctionCallee FC{PutsType, Arg++};
builder.CreateRet(builder.CreateCall(FC, Arg));
}
assert(!llvm::verifyFunction(*TheFunction, &llvm::errs()));
// TheFunction->dump();
}
llvm::ExitOnError ExitOnErr;
auto J = ExitOnErr(llvm::orc::LLJITBuilder().create());
ExitOnErr(J->addIRModule
(llvm::orc::ThreadSafeModule(std::move(M), std::move(C))));
auto BooAddr = ExitOnErr(J->lookup("boo"));
typedef int (*callback)(const char*);
auto boo =
reinterpret_cast<int(*)(callback, const char*)>(BooAddr.getAddress());
return boo(puts, "hello world");
}
// c++ lljit.cc $(llvm-config --cxxflags --ldflags --system-libs --libs core)
I found some other example where CreateAlloca() was used for storing and loading a function pointer. In my intended application, I will be passing an array of function pointers via a parameter to the generated function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With