From d06d3863b26d6682844af7393ce234947888c1ae Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 30 Oct 2015 03:20:21 +0000 Subject: [PATCH] [Orc] Expose the compile callback API through the C bindings. llvm-svn: 251683 --- include/llvm-c/OrcBindings.h | 24 +++++++ lib/ExecutionEngine/Orc/OrcCBindings.cpp | 25 ++++++- lib/ExecutionEngine/Orc/OrcCBindingsStack.h | 46 ++++++++++--- unittests/ExecutionEngine/Orc/OrcCAPITest.cpp | 68 ++++++++++++++++--- unittests/ExecutionEngine/Orc/OrcTestCommon.h | 27 ++++---- 5 files changed, 154 insertions(+), 36 deletions(-) diff --git a/include/llvm-c/OrcBindings.h b/include/llvm-c/OrcBindings.h index 6b7284adb31..78a7bc146ee 100644 --- a/include/llvm-c/OrcBindings.h +++ b/include/llvm-c/OrcBindings.h @@ -35,6 +35,8 @@ typedef uint32_t LLVMOrcModuleHandle; typedef uint64_t LLVMOrcTargetAddress; typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name, void *LookupCtx); +typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack, + void *CallbackCtx); /** * Create an ORC JIT stack. @@ -61,6 +63,28 @@ void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledSymbol, void LLVMOrcDisposeMangledSymbol(char *MangledSymbol); +/** + * Create a lazy compile callback. + */ +LLVMOrcTargetAddress +LLVMOrcCreateLazyCompileCallback(LLVMOrcJITStackRef JITStack, + LLVMOrcLazyCompileCallbackFn Callback, + void *CallbackCtx); + +/** + * Create a named indirect call stub. + */ +void LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack, + const char *StubName, + LLVMOrcTargetAddress InitAddr); + +/** + * Set the pointer for the given indirect stub. + */ +void LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack, + const char *StubName, + LLVMOrcTargetAddress NewAddr); + /** * Add module to be eagerly compiled. */ diff --git a/lib/ExecutionEngine/Orc/OrcCBindings.cpp b/lib/ExecutionEngine/Orc/OrcCBindings.cpp index 055636f2a6f..d3effeec97e 100644 --- a/lib/ExecutionEngine/Orc/OrcCBindings.cpp +++ b/lib/ExecutionEngine/Orc/OrcCBindings.cpp @@ -12,9 +12,6 @@ using namespace llvm; -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcCBindingsStack, LLVMOrcJITStackRef) -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) - LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM, LLVMContextRef Context) { TargetMachine *TM2(unwrap(TM)); @@ -45,6 +42,28 @@ void LLVMOrcDisposeMangledSymbol(char *MangledName) { delete[] MangledName; } +LLVMOrcTargetAddress +LLVMOrcCreateLazyCompileCallback(LLVMOrcJITStackRef JITStack, + LLVMOrcLazyCompileCallbackFn Callback, + void *CallbackCtx) { + OrcCBindingsStack &J = *unwrap(JITStack); + return J.createLazyCompileCallback(Callback, CallbackCtx); +} + +void LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack, + const char *StubName, + LLVMOrcTargetAddress InitAddr) { + OrcCBindingsStack &J = *unwrap(JITStack); + J.createIndirectStub(StubName, InitAddr); +} + +void LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack, + const char *StubName, + LLVMOrcTargetAddress NewAddr) { + OrcCBindingsStack &J = *unwrap(JITStack); + J.setIndirectStubPointer(StubName, NewAddr); +} + LLVMOrcModuleHandle LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod, LLVMOrcSymbolResolverFn SymbolResolver, diff --git a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h index dbedf00d08e..6188b29befc 100644 --- a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h +++ b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h @@ -17,17 +17,18 @@ #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/IR/LLVMContext.h" +#include "llvm-c/OrcBindings.h" namespace llvm { +class OrcCBindingsStack; + +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcCBindingsStack, LLVMOrcJITStackRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) + class OrcCBindingsStack { -private: - public: - typedef orc::TargetAddress (*CExternalSymbolResolverFn)(const char *Name, - void *Ctx); - typedef orc::JITCompileCallbackManagerBase CompileCallbackMgr; typedef orc::ObjectLinkingLayer<> ObjLayerT; typedef orc::IRCompileLayer CompileLayerT; @@ -91,13 +92,14 @@ public: OrcCBindingsStack(TargetMachine &TM, LLVMContext &Context, CallbackManagerBuilder &BuildCallbackMgr, IndirectStubsManagerBuilder IndirectStubsMgrBuilder) - : DL(TM.createDataLayout()), + : Context(Context), DL(TM.createDataLayout()), ObjectLayer(), CompileLayer(ObjectLayer, orc::SimpleCompiler(TM)), CCMgr(BuildCallbackMgr(CompileLayer, CCMgrMemMgr, Context)), CODLayer(CompileLayer, [](Function &F) { std::set S; S.insert(&F); return S; }, *CCMgr, std::move(IndirectStubsMgrBuilder), false), + IndirectStubsMgr(IndirectStubsMgrBuilder()), CXXRuntimeOverrides([this](const std::string &S) { return mangle(S); }) {} ~OrcCBindingsStack() { @@ -122,8 +124,27 @@ public: return reinterpret_cast(static_cast(Addr)); } + orc::TargetAddress + createLazyCompileCallback(LLVMOrcLazyCompileCallbackFn Callback, + void *CallbackCtx) { + auto CCInfo = CCMgr->getCompileCallback(Context); + CCInfo.setCompileAction( + [=]() -> orc::TargetAddress { + return Callback(wrap(this), CallbackCtx); + }); + return CCInfo.getAddress(); + } + + void createIndirectStub(StringRef StubName, orc::TargetAddress Addr) { + IndirectStubsMgr->createStub(StubName, Addr, JITSymbolFlags::Exported); + } + + void setIndirectStubPointer(StringRef Name, orc::TargetAddress Addr) { + IndirectStubsMgr->updatePointer(Name, Addr); + } + std::shared_ptr - createResolver(CExternalSymbolResolverFn ExternalResolver, + createResolver(LLVMOrcSymbolResolverFn ExternalResolver, void *ExternalResolverCtx) { auto Resolver = orc::createLambdaResolver( [this, ExternalResolver, ExternalResolverCtx](const std::string &Name) { @@ -157,7 +178,7 @@ public: ModuleHandleT addIRModule(LayerT &Layer, Module *M, std::unique_ptr MemMgr, - CExternalSymbolResolverFn ExternalResolver, + LLVMOrcSymbolResolverFn ExternalResolver, void *ExternalResolverCtx) { // Attach a data-layout if one isn't already present. @@ -194,7 +215,7 @@ public: } ModuleHandleT addIRModuleEager(Module* M, - CExternalSymbolResolverFn ExternalResolver, + LLVMOrcSymbolResolverFn ExternalResolver, void *ExternalResolverCtx) { return addIRModule(CompileLayer, std::move(M), llvm::make_unique(), @@ -202,7 +223,7 @@ public: } ModuleHandleT addIRModuleLazy(Module* M, - CExternalSymbolResolverFn ExternalResolver, + LLVMOrcSymbolResolverFn ExternalResolver, void *ExternalResolverCtx) { return addIRModule(CODLayer, std::move(M), nullptr, std::move(ExternalResolver), ExternalResolverCtx); @@ -215,6 +236,8 @@ public: } orc::JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { + if (auto Sym = IndirectStubsMgr->findStub(Name, ExportedSymbolsOnly)) + return Sym; return CODLayer.findSymbol(mangle(Name), ExportedSymbolsOnly); } @@ -241,6 +264,7 @@ private: return NewHandle; } + LLVMContext &Context; DataLayout DL; SectionMemoryManager CCMgrMemMgr; @@ -249,6 +273,8 @@ private: std::unique_ptr CCMgr; CODLayerT CODLayer; + std::unique_ptr IndirectStubsMgr; + std::vector> GenericHandles; std::vector FreeHandleIndexes; diff --git a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp index bddb6a76bbf..095d42599bf 100644 --- a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp +++ b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp @@ -51,21 +51,41 @@ protected: return 0; } + struct CompileContext { + CompileContext() : Compiled(false) { } + + OrcCAPIExecutionTest* APIExecTest; + std::unique_ptr M; + LLVMOrcModuleHandle H; + bool Compiled; + }; + + static LLVMOrcTargetAddress myCompileCallback(LLVMOrcJITStackRef JITStack, + void *Ctx) { + CompileContext *CCtx = static_cast(Ctx); + auto *ET = CCtx->APIExecTest; + CCtx->M = ET->createTestModule(ET->TM->getTargetTriple()); + CCtx->H = LLVMOrcAddEagerlyCompiledIR(JITStack, wrap(CCtx->M.get()), + myResolver, 0); + CCtx->Compiled = true; + LLVMOrcTargetAddress MainAddr = LLVMOrcGetSymbolAddress(JITStack, "main"); + LLVMOrcSetIndirectStubPointer(JITStack, "foo", MainAddr); + return MainAddr; + } + }; char *OrcCAPIExecutionTest::testFuncName = 0; TEST_F(OrcCAPIExecutionTest, TestEagerIRCompilation) { - auto TM = getHostTargetMachineIfSupported(); - if (!TM) return; - std::unique_ptr M = createTestModule(TM->getTargetTriple()); - LLVMOrcJITStackRef JIT = LLVMOrcCreateInstance(wrap(TM.get()), LLVMGetGlobalContext()); + std::unique_ptr M = createTestModule(TM->getTargetTriple()); + LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc"); LLVMOrcModuleHandle H = @@ -82,17 +102,16 @@ TEST_F(OrcCAPIExecutionTest, TestEagerIRCompilation) { } TEST_F(OrcCAPIExecutionTest, TestLazyIRCompilation) { - auto TM = getHostTargetMachineIfSupported(); - if (!TM) return; - std::unique_ptr M = createTestModule(TM->getTargetTriple()); - LLVMOrcJITStackRef JIT = LLVMOrcCreateInstance(wrap(TM.get()), LLVMGetGlobalContext()); + std::unique_ptr M = createTestModule(TM->getTargetTriple()); + LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc"); + LLVMOrcModuleHandle H = LLVMOrcAddLazilyCompiledIR(JIT, wrap(M.get()), myResolver, 0); MainFnTy MainFn = (MainFnTy)LLVMOrcGetSymbolAddress(JIT, "main"); @@ -106,4 +125,37 @@ TEST_F(OrcCAPIExecutionTest, TestLazyIRCompilation) { LLVMOrcDisposeInstance(JIT); } +TEST_F(OrcCAPIExecutionTest, TestDirectCallbacksAPI) { + if (!TM) + return; + + LLVMOrcJITStackRef JIT = + LLVMOrcCreateInstance(wrap(TM.get()), LLVMGetGlobalContext()); + + LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc"); + + CompileContext C; + C.APIExecTest = this; + LLVMOrcCreateIndirectStub(JIT, "foo", + LLVMOrcCreateLazyCompileCallback(JIT, + myCompileCallback, + &C)); + MainFnTy FooFn = (MainFnTy)LLVMOrcGetSymbolAddress(JIT, "foo"); + int Result = FooFn(); + EXPECT_TRUE(C.Compiled) + << "Function wasn't lazily compiled"; + EXPECT_EQ(Result, 42) + << "Direct-callback JIT'd code did not return expected result"; + + C.Compiled = false; + FooFn(); + EXPECT_FALSE(C.Compiled) + << "Direct-callback JIT'd code was JIT'd twice"; + + LLVMOrcRemoveModule(JIT, C.H); + + LLVMOrcDisposeMangledSymbol(testFuncName); + LLVMOrcDisposeInstance(JIT); +} + } diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/unittests/ExecutionEngine/Orc/OrcTestCommon.h index bfdaced05b1..15d9f54a37f 100644 --- a/unittests/ExecutionEngine/Orc/OrcTestCommon.h +++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.h @@ -38,23 +38,20 @@ public: InitializeNativeTargetAsmPrinter(); NativeTargetInitialized = true; } + + // Try to select a TargetMachine for the host. + TM.reset(EngineBuilder().selectTarget()); + + if (TM) { + // If we found a TargetMachine, check that it's one that Orc supports. + const Triple& TT = TM->getTargetTriple(); + if (TT.getArch() != Triple::x86_64 || !TT.isOSDarwin()) + TM = nullptr; + } }; - // Get a target machine for the host if it supports JIT execution. - std::unique_ptr getHostTargetMachineIfSupported() { - std::unique_ptr TM(EngineBuilder().selectTarget()); - - if (!TM) - return nullptr; - - const Triple& TT = TM->getTargetTriple(); - - if (TT.getArch() != Triple::x86_64 || !TT.isOSDarwin()) - return nullptr; - - return TM; - } - +protected: + std::unique_ptr TM; private: static bool NativeTargetInitialized; };