[llvm-dev] External function resolution: MCJIT vs ORC JIT

Lang Hames via llvm-dev llvm-dev at lists.llvm.org
Mon May 23 14:05:30 PDT 2016


Hi Alex, Larry,

As for documentation: I will (hopefully soon) start another thread to
> discuss how to describe parts of ORC better.


Yep. ORC could definitely use better documentation, and the interface is
more mature now (and less of a moving target) so it's a good time to do
this.

At a high level I think we want two documents: An "ORC Overview/Manual"
describing the design and components, and a tutorial series showing how to
use them for a simple-but-real use case. I started work on the tutorial
series over the weekend, and committed my work-in-progress first chapter
today as r270487.

Any help (feedback, patches, etc.) will be most welcome, especially because
some of the hurdles and gotchas will be more fresh in your mind than they
are mine.

Thanks to both of you for asking about this - it's a good motivator to
start working on it. :)

Cheers,
Lang.

On Sun, May 22, 2016 at 12:23 PM, Alex Denisov <1101.debian at gmail.com>
wrote:

> >> llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr)
>
> This is one is a bit tricky and hard to find.
> I spent quiet some time digging into MC and ORC JIT execution engines
> trying to find what makes them work.
> The problem is that this trick (LoadLibraryPermanently) happens inside of
> EngineBuilder, despite that the functionality belongs to a JIT engine
> itself, not to the builder.
>
> I think this part can be improved by moving the method call into an engine
> itself, or by documenting the steps required to create custom engine on top
> of ORC.
>
> As for documentation: I will (hopefully soon) start another thread to
> discuss how to describe parts of ORC better.
>
> > On 20 May 2016, at 19:30, Lang Hames via llvm-dev <
> llvm-dev at lists.llvm.org> wrote:
> >
> > Hi Larry,
> >
> > Thanks so much! This seems to do the trick. I would have spun my wheels
> for a long time before discovering all of this, wow.
> >
> > No worries. :)
> > I'll try to keep this in mind and make sure I address it in future
> Kaleidoscope tutorial chapters - these issues tripped me up the first time
> I encountered them too.
> >
> > Do I even want to know what additional chickens need to be sacrificed to
> get this to work on Windows?
> >
> > I don't build on Windows myself, so I'm not certain. I know there are
> people using ORC on Windows though, and evidently at least simple code
> works. I only know of one big gotcha, which is that COFF files don't
> properly handle the SF_Exported symbol flag, so whenever you go searching
> for a symbol in the JIT on windows you have to call findSymbol with
> ExportedSymbolsOnly=false. Other than that I don't think usage should
> differ too much between platforms.
> >
> > On the feature support side: the JIT linker for Windows
> (RuntimeDyldCOFF) is less mature, so you may run into unimplemented
> features there. While I don't have much time to work on Windows support
> myself, we definitely want to improve support for it so patches, bug
> reports and feature requests are all very welcome.
> >
> > In case it's useful too, here's a link to the LLILC JIT file, which uses
> a simple ORC setup on Windows:
> https://github.com/dotnet/llilc/blob/dd12743f9cdb5418f1c39b2cd756da1e8396a922/lib/Jit/LLILCJit.cpp#L299
> >
> > Cheers,
> > Lang.
> >
> > On Thu, May 19, 2016 at 11:57 AM, Larry Gritz <lg at larrygritz.com> wrote:
> > Thanks so much! This seems to do the trick. I would have spun my wheels
> for a long time before discovering all of this, wow.
> >
> > Do I even want to know what additional chickens need to be sacrificed to
> get this to work on Windows?
> >
> >       -- lg
> >
> >> On May 18, 2016, at 1:52 PM, Lang Hames <lhames at gmail.com> wrote:
> >>
> >> Hi Larry,
> >>
> >> You're basically there, but you're hitting a couple of subtle issues:
> >>
> >> (1) On both platforms you'll want to call
> llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr) at program
> startup. This makes exported symbols in the main program searchable by
> RTDyldMemoryManager::getSymbolAddressInProcess (important for making 'sqr'
> findable on any platform).
> >>
> >> (2) On Linux (if I understand correctly) symbols aren't exported from
> the main process by default, so even if you've called
> DynamicLibrary::LoadLibraryPermanently, sqr won't show up. To fix this you
> can add -Wl,export-dynamic to your link line. This will flip the default
> and export symbols from the main binary, allowing getSymbolAddressInProcess
> to find sqr. On MacOS this isn't necessary.
> >>
> >> (3) On MacOS, C names are mangled by prepending an '_'. To maintain
> consistency with statically linked programs, the JIT uses these mangled
> names so you need to search for '_myfunc', rather than 'myfunc'. I usually
> add a 'mangle' function that uses the DataLayout, then search for
> 'mangle(<name>)', which does the right thing on all platforms.
> >>
> >> I've attached a new version of your code with these changes included.
> Hope this helps!
> >>
> >> - Lang.
> >>
> >>
> >> 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
> >>
> >> <larrys_jit.cpp>
> >
> > --
> > 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/20160523/4f094dc7/attachment.html>


More information about the llvm-dev mailing list