[llvm-dev] External function resolution: MCJIT vs ORC JIT
David Blaikie via llvm-dev
llvm-dev at lists.llvm.org
Tue May 17 13:05:47 PDT 2016
+Lang for all your ORC related inquiries
On Tue, May 17, 2016 at 12:13 PM, Larry Gritz via llvm-dev <
llvm-dev at lists.llvm.org> wrote:
> When using ORC JIT, I'm having trouble with external function resolution
> (that is, of a function defined in the app, with C linkage).
>
> I add a declaration for the function to my IR, and when I use MCJIT, it
> finds it and all is well, But when I use ORC JIT (I *think* correctly, at
> least it closely matches what I see in the tutorial), I get an LLVM error,
> "Program used external function 'sqr' which could not be resolved."
>
> (Excuse my coming to the ORC party late, I've been stuck on an older LLVM
> for my DSL, and am only now jumping forward several versions at once, with
> some growing pains.)
>
> I've boiled it down to the minimal example below. When I build with orc=0,
> thus using MCJIT, it works fine and I get the expected output. When I build
> with orc=1, it fails as I described.
>
> I'm having this trouble with LLVM 3.7 and 3.8, on both Linux and OSX.
>
> I figure I'm probably just getting some part of the magic incantation
> wrong. Can anybody help a poor guy out and spot the error of my ways?
>
> -----
>
> #include <llvm/ADT/STLExtras.h>
> #include <llvm/Bitcode/ReaderWriter.h>
> #include <llvm/ExecutionEngine/ExecutionEngine.h>
> #include <llvm/ExecutionEngine/Orc/CompileUtils.h>
> #include <llvm/ExecutionEngine/RuntimeDyld.h>
> #include <llvm/ExecutionEngine/Orc/IRCompileLayer.h>
> #include <llvm/ExecutionEngine/Orc/LambdaResolver.h>
> #include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
> #include <llvm/IR/DataLayout.h>
> #include <llvm/IR/IRBuilder.h>
> #include <llvm/IR/LegacyPassManager.h>
> #include <llvm/IR/LLVMContext.h>
> #include <llvm/IR/Mangler.h>
> #include <llvm/IR/Module.h>
> #include <llvm/IR/Verifier.h>
> #include <llvm/Support/TargetSelect.h>
> #include <llvm/Target/TargetMachine.h>
> #include <llvm/Transforms/IPO.h>
> #include <llvm/Transforms/IPO/PassManagerBuilder.h>
> #include <llvm/Transforms/Scalar.h>
> #include <llvm/Transforms/Utils/UnifyFunctionExitNodes.h>
>
> template <typename T>
> inline std::vector<T> singletonSet (T t)
> {
> std::vector<T> Vec;
> Vec.push_back(std::move(t));
> return Vec;
> }
>
>
> ///
> /// THIS is the function I want my IR to call
> ///
> extern "C" {
> float sqr (float x) { return x*x; }
> }
>
>
> void
> simple ()
> {
> llvm::InitializeAllTargets();
> llvm::InitializeAllTargetMCs();
> llvm::InitializeAllAsmPrinters();
> llvm::InitializeAllAsmParsers();
> llvm::LLVMContext Context;
> std::unique_ptr<llvm::TargetMachine> TM
> (llvm::EngineBuilder().selectTarget());
> std::unique_ptr<llvm::DataLayout> DL;
> DL.reset (new llvm::DataLayout (TM->createDataLayout()));
> std::unique_ptr<llvm::ExecutionEngine> EE;
> typedef llvm::orc::ObjectLinkingLayer<> ObjLayerT;
> typedef llvm::orc::IRCompileLayer<ObjLayerT> CompileLayerT;
> typedef CompileLayerT::ModuleSetHandleT ModuleHandleT;
> ObjLayerT Objlayer;
> CompileLayerT Compilelayer (Objlayer, llvm::orc::SimpleCompiler(*TM));
> std::unique_ptr<llvm::Module> M (new llvm::Module("module", Context));
> M->setDataLayout (*DL);
>
> // Declare stub for external function sqr
> auto type_float = llvm::Type::getFloatTy (Context);
> llvm::Type* one_float[] = { type_float };
> llvm::FunctionType *functype_ff = llvm::FunctionType::get (type_float,
> one_float, false);
> llvm::Function::Create (functype_ff, llvm::Function::ExternalLinkage,
> "sqr", M.get());
>
> // Create myfunc and generate its IR, which just calls sqr on its
> argument
> llvm::Function *myfunc = llvm::Function::Create (functype_ff,
>
> llvm::Function::ExternalLinkage,
> "myfunc", M.get());
> llvm::IRBuilder<> builder (Context);
> auto block = llvm::BasicBlock::Create (Context, "", myfunc);
> builder.SetInsertPoint (block);
> llvm::Value *a = llvm::cast<llvm::Value>(myfunc->arg_begin());
> llvm::Value *asq = builder.CreateCall (M->getFunction ("sqr"), a);
> builder.CreateRet (asq);
>
> // Set up compilation
> if (orc) {
> auto Resolver = llvm::orc::createLambdaResolver(
> // External lookup functor
> [&](const std::string &name) {
> if (auto Sym = Compilelayer.findSymbol(name, true))
> return llvm::RuntimeDyld::SymbolInfo(Sym.getAddress(),
> Sym.getFlags());
> // If not found as a symbol, look up in current process.
> // Why doesn't this work?
> if (auto Addr =
> llvm::RTDyldMemoryManager::getSymbolAddressInProcess(name))
> return llvm::RuntimeDyld::SymbolInfo(Addr,
> llvm::JITSymbolFlags::Exported);
> return llvm::RuntimeDyld::SymbolInfo(nullptr);
> },
> // Dylib lookup functor
> [&](const std::string &name) { return nullptr; }
> );
> Compilelayer.addModuleSet (singletonSet(std::move(M)),
>
> llvm::make_unique<llvm::SectionMemoryManager>(),
> std::move(Resolver));
> } else {
> // MCJIT
> std::string engine_errors;
> llvm::EngineBuilder engine_builder (std::move(M));
> engine_builder.setEngineKind (llvm::EngineKind::JIT)
> .setOptLevel (llvm::CodeGenOpt::Default) //
> Aggressive?
> .setErrorStr (&engine_errors);
> EE.reset (engine_builder.create());
> EE->finalizeObject ();
> }
>
> // Ask for a callable function
> typedef float (*FuncFloatFloat)(float);
> FuncFloatFloat my_executable_function = NULL;
> if (orc) {
> auto ExprSymbol = Compilelayer.findSymbol ("myfunc", true);
> my_executable_function = (FuncFloatFloat) ExprSymbol.getAddress ();
> } else {
> my_executable_function = (FuncFloatFloat) EE->getFunctionAddress
> ("myfunc");
> }
>
> assert (my_executable_function);
> printf ("myfunc(42.0f) = %g\n", (*my_executable_function)(42.0f));
> }
>
>
>
> --
> Larry Gritz
> lg at larrygritz.com
>
>
> _______________________________________________
> 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/20160517/95df4cf9/attachment.html>
More information about the llvm-dev
mailing list