[Orc] Add experimental C bindings for Orc.
authorLang Hames <lhames@gmail.com>
Wed, 28 Oct 2015 00:28:26 +0000 (00:28 +0000)
committerLang Hames <lhames@gmail.com>
Wed, 28 Oct 2015 00:28:26 +0000 (00:28 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251472 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm-c/OrcBindings.h [new file with mode: 0644]
lib/ExecutionEngine/Orc/CMakeLists.txt
lib/ExecutionEngine/Orc/OrcCBindings.cpp [new file with mode: 0644]
lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp [new file with mode: 0644]
lib/ExecutionEngine/Orc/OrcCBindingsStack.h [new file with mode: 0644]
unittests/ExecutionEngine/Orc/CMakeLists.txt
unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp
unittests/ExecutionEngine/Orc/OrcCAPITest.cpp [new file with mode: 0644]
unittests/ExecutionEngine/Orc/OrcTestCommon.cpp
unittests/ExecutionEngine/Orc/OrcTestCommon.h

diff --git a/include/llvm-c/OrcBindings.h b/include/llvm-c/OrcBindings.h
new file mode 100644 (file)
index 0000000..6b7284a
--- /dev/null
@@ -0,0 +1,111 @@
+/*===----------- llvm-c/OrcBindings.h - Orc Lib C Iface ---------*- C++ -*-===*\
+|*                                                                            *|
+|*                     The LLVM Compiler Infrastructure                       *|
+|*                                                                            *|
+|* This file is distributed under the University of Illinois Open Source      *|
+|* License. See LICENSE.TXT for details.                                      *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* This header declares the C interface to libLLVMOrcJIT.a, which implements  *|
+|* JIT compilation of LLVM IR.                                                *|
+|*                                                                            *|
+|* Many exotic languages can interoperate with C code but have a harder time  *|
+|* with C++ due to name mangling. So in addition to C, this interface enables *|
+|* tools written in such languages.                                           *|
+|*                                                                            *|
+|* Note: This interface is experimental. It is *NOT* stable, and may be       *|
+|*       changed without warning.                                             *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_C_ORCBINDINGS_H
+#define LLVM_C_ORCBINDINGS_H
+
+#include "llvm-c/Object.h"
+#include "llvm-c/Support.h"
+#include "llvm-c/TargetMachine.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct LLVMOrcOpaqueJITStack *LLVMOrcJITStackRef;
+typedef uint32_t LLVMOrcModuleHandle;
+typedef uint64_t LLVMOrcTargetAddress;
+typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name,
+                                            void *LookupCtx);
+
+/**
+ * Create an ORC JIT stack.
+ *
+ * The client owns the resulting stack, and must call OrcDisposeInstance(...)
+ * to destroy it and free its memory. The JIT stack will take ownership of the
+ * TargetMachine, which will be destroyed when the stack is destroyed. The
+ * client should not attempt to dispose of the Target Machine, or it will result
+ * in a double-free.
+ */
+LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM,
+                                         LLVMContextRef Context);
+
+/**
+ * Mangle the given symbol.
+ * Memory will be allocated for MangledSymbol to hold the result. The client
+ */
+void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledSymbol,
+                             const char *Symbol);
+
+/**
+ * Dispose of a mangled symbol.
+ */
+
+void LLVMOrcDisposeMangledSymbol(char *MangledSymbol);
+
+/**
+ * Add module to be eagerly compiled.
+ */
+LLVMOrcModuleHandle
+LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod,
+                            LLVMOrcSymbolResolverFn SymbolResolver,
+                            void *SymbolResolverCtx);
+
+/**
+ * Add module to be lazily compiled one function at a time.
+ */
+LLVMOrcModuleHandle
+LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod,
+                           LLVMOrcSymbolResolverFn SymbolResolver,
+                           void *SymbolResolverCtx);
+
+/**
+ * Add an object file.
+ */
+LLVMOrcModuleHandle
+LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack, LLVMObjectFileRef Obj,
+                     LLVMOrcSymbolResolverFn SymbolResolver,
+                     void *SymbolResolverCtx);
+
+/**
+ * Remove a module set from the JIT.
+ *
+ * This works for all modules that can be added via OrcAdd*, including object
+ * files.
+ */
+void LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack, LLVMOrcModuleHandle H);
+
+/**
+ * Get symbol address from JIT instance.
+ */
+LLVMOrcTargetAddress LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack,
+                                             const char *SymbolName);
+
+/**
+ * Dispose of an ORC JIT stack.
+ */
+void LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack);
+
+#ifdef __cplusplus
+}
+#endif /* extern "C" */
+
+#endif /* LLVM_C_ORCBINDINGS_H */
index 99fe22c..a17f52e 100644 (file)
@@ -2,6 +2,8 @@ add_llvm_library(LLVMOrcJIT
   ExecutionUtils.cpp
   IndirectionUtils.cpp
   NullResolver.cpp
+  OrcCBindings.cpp
+  OrcCBindingsStack.cpp
   OrcMCJITReplacement.cpp
   OrcTargetSupport.cpp
 
diff --git a/lib/ExecutionEngine/Orc/OrcCBindings.cpp b/lib/ExecutionEngine/Orc/OrcCBindings.cpp
new file mode 100644 (file)
index 0000000..9643f46
--- /dev/null
@@ -0,0 +1,80 @@
+//===----------- OrcCBindings.cpp - C bindings for the Orc APIs -----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OrcCBindingsStack.h"
+#include "llvm-c/OrcBindings.h"
+
+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));
+  LLVMContext &Ctx = *unwrap(Context);
+
+  Triple T(TM2->getTargetTriple());
+
+  auto CallbackMgrBuilder = OrcCBindingsStack::createCallbackManagerBuilder(T);
+  auto IndirectStubsMgrBuilder =
+    OrcCBindingsStack::createIndirectStubsMgrBuilder(T);
+
+  OrcCBindingsStack *JITStack =
+    new OrcCBindingsStack(*TM2, Ctx, CallbackMgrBuilder,
+                          IndirectStubsMgrBuilder);
+
+  return wrap(JITStack);
+}
+
+void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledName,
+                             const char *SymbolName) {
+  OrcCBindingsStack &J = *unwrap(JITStack);
+  std::string Mangled = J.mangle(SymbolName);
+  *MangledName = new char[Mangled.size() + 1];
+  strcpy(*MangledName, Mangled.c_str());
+}
+
+void LLVMOrcDisposeMangledSymbol(char *MangledName) {
+  delete[] MangledName;
+}
+
+LLVMOrcModuleHandle
+LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod,
+                            LLVMOrcSymbolResolverFn SymbolResolver,
+                            void *SymbolResolverCtx) {
+  OrcCBindingsStack &J = *unwrap(JITStack);
+  Module *M(unwrap(Mod));
+  return J.addIRModuleEager(M, SymbolResolver, SymbolResolverCtx);
+}
+
+LLVMOrcModuleHandle
+LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod,
+                           LLVMOrcSymbolResolverFn SymbolResolver,
+                           void *SymbolResolverCtx) {
+  OrcCBindingsStack &J = *unwrap(JITStack);
+  Module *M(unwrap(Mod));
+  return J.addIRModuleLazy(M, SymbolResolver, SymbolResolverCtx);
+}
+
+void LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack, LLVMOrcModuleHandle H) {
+  OrcCBindingsStack &J = *unwrap(JITStack);
+  J.removeModule(H);
+}
+
+LLVMOrcTargetAddress LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack,
+                                             const char *SymbolName) {
+  OrcCBindingsStack &J = *unwrap(JITStack);
+  auto Sym = J.findSymbol(SymbolName, true);
+  return Sym.getAddress();
+}
+
+void LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack) {
+  delete unwrap(JITStack);
+}
diff --git a/lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp b/lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp
new file mode 100644 (file)
index 0000000..93c698d
--- /dev/null
@@ -0,0 +1,47 @@
+//===-------- OrcCBindingsStack.cpp - Orc JIT stack for C bindings --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OrcCBindingsStack.h"
+
+#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include <cstdio>
+#include <system_error>
+
+using namespace llvm;
+
+OrcCBindingsStack::CallbackManagerBuilder
+OrcCBindingsStack::createCallbackManagerBuilder(Triple T) {
+  switch (T.getArch()) {
+    default: return nullptr;
+
+    case Triple::x86_64: {
+      typedef orc::JITCompileCallbackManager<CompileLayerT,
+                                             orc::OrcX86_64> CCMgrT;
+      return [](CompileLayerT &CompileLayer, RuntimeDyld::MemoryManager &MemMgr,
+                LLVMContext &Context) {
+               return llvm::make_unique<CCMgrT>(CompileLayer, MemMgr, Context, 0,
+                                                64);
+             };
+    }
+  }
+}
+
+OrcCBindingsStack::IndirectStubsManagerBuilder
+OrcCBindingsStack::createIndirectStubsMgrBuilder(Triple T) {
+  switch (T.getArch()) {
+    default: return nullptr;
+
+    case Triple::x86_64:
+      return [](){
+        return llvm::make_unique<orc::IndirectStubsManager<orc::OrcX86_64>>();
+      };
+  }
+}
diff --git a/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/lib/ExecutionEngine/Orc/OrcCBindingsStack.h
new file mode 100644 (file)
index 0000000..5b58c00
--- /dev/null
@@ -0,0 +1,268 @@
+//===--- OrcCBindingsStack.h - Orc JIT stack for C bindings ---*- C++ -*---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H
+#define LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
+#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
+#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
+#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/IR/LLVMContext.h"
+
+namespace llvm {
+
+class OrcCBindingsStack {
+private:
+
+public:
+
+  typedef orc::TargetAddress (*CExternalSymbolResolverFn)(const char *Name,
+                                                          void *Ctx);
+
+  typedef orc::JITCompileCallbackManagerBase CompileCallbackMgr;
+  typedef orc::ObjectLinkingLayer<> ObjLayerT;
+  typedef orc::IRCompileLayer<ObjLayerT> CompileLayerT;
+  typedef orc::CompileOnDemandLayer<CompileLayerT, CompileCallbackMgr> CODLayerT;
+
+  typedef std::function<
+            std::unique_ptr<CompileCallbackMgr>(CompileLayerT&,
+                                                RuntimeDyld::MemoryManager&,
+                                                LLVMContext&)>
+    CallbackManagerBuilder;
+
+  typedef CODLayerT::IndirectStubsManagerBuilderT IndirectStubsManagerBuilder;
+
+private:
+
+  typedef enum { Invalid, CODLayerHandle, ObjectLayerHandle } HandleType;
+  union RawHandleUnion {
+    RawHandleUnion() { memset(this, 0, sizeof(RawHandleUnion)); }
+    ObjLayerT::ObjSetHandleT Obj;
+    CODLayerT::ModuleSetHandleT COD;
+  };
+
+  struct ModuleHandleData {
+
+    ModuleHandleData() : Type(Invalid) {}
+
+    ModuleHandleData(ObjLayerT::ObjSetHandleT H)
+        : Type(ObjectLayerHandle) {
+      RawHandle.Obj = std::move(H);
+    }
+
+    ModuleHandleData(CODLayerT::ModuleSetHandleT H)
+      : Type(CODLayerHandle) {
+      RawHandle.COD = std::move(H);
+    }
+
+    HandleType Type;
+    RawHandleUnion RawHandle;
+  };
+
+public:
+
+  // We need a 'ModuleSetHandleT' to conform to the layer concept.
+  typedef unsigned ModuleSetHandleT;
+
+  typedef unsigned ModuleHandleT;
+
+  static CallbackManagerBuilder createCallbackManagerBuilder(Triple T);
+  static IndirectStubsManagerBuilder createIndirectStubsMgrBuilder(Triple T);
+
+  OrcCBindingsStack(TargetMachine &TM, LLVMContext &Context,
+                    CallbackManagerBuilder &BuildCallbackMgr,
+                    IndirectStubsManagerBuilder IndirectStubsMgrBuilder)
+    : DL(TM.createDataLayout()),
+      ObjectLayer(),
+      CompileLayer(ObjectLayer, orc::SimpleCompiler(TM)),
+      CCMgr(BuildCallbackMgr(CompileLayer, CCMgrMemMgr, Context)),
+      CODLayer(CompileLayer,
+               [](Function &F) { std::set<Function*> S; S.insert(&F); return S; },
+               *CCMgr, std::move(IndirectStubsMgrBuilder), false),
+      CXXRuntimeOverrides([this](const std::string &S) { return mangle(S); }) {}
+
+  ~OrcCBindingsStack() {
+    // Run any destructors registered with __cxa_atexit.
+    CXXRuntimeOverrides.runDestructors();
+    // Run any IR destructors.
+    for (auto &DtorRunner : IRStaticDestructorRunners)
+      DtorRunner.runViaLayer(*this);
+  }
+
+  std::string mangle(StringRef Name) {
+    std::string MangledName;
+    {
+      raw_string_ostream MangledNameStream(MangledName);
+      Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
+    }
+    return MangledName;
+  }
+
+  template <typename PtrTy>
+  static PtrTy fromTargetAddress(orc::TargetAddress Addr) {
+    return reinterpret_cast<PtrTy>(static_cast<uintptr_t>(Addr));
+  }
+
+  std::shared_ptr<RuntimeDyld::SymbolResolver>
+  createResolver(CExternalSymbolResolverFn ExternalResolver,
+                 void *ExternalResolverCtx) {
+    auto Resolver = orc::createLambdaResolver(
+      [this, ExternalResolver, ExternalResolverCtx](const std::string &Name) {
+        // Search order:
+        // 1. JIT'd symbols.
+        // 2. Runtime overrides.
+        // 3. External resolver (if present).
+
+        if (auto Sym = CODLayer.findSymbol(Name, true))
+          return RuntimeDyld::SymbolInfo(Sym.getAddress(),
+                                         Sym.getFlags());
+        if (auto Sym = CXXRuntimeOverrides.searchOverrides(Name))
+          return Sym;
+
+        if (ExternalResolver)
+          return RuntimeDyld::SymbolInfo(ExternalResolver(Name.c_str(),
+                                                          ExternalResolverCtx),
+                                         llvm::JITSymbolFlags::Exported);
+
+        return RuntimeDyld::SymbolInfo(nullptr);
+      },
+      [](const std::string &Name) {
+        return RuntimeDyld::SymbolInfo(nullptr);
+      }
+    );
+
+    return std::shared_ptr<RuntimeDyld::SymbolResolver>(std::move(Resolver));
+  }
+
+  template <typename LayerT>
+  ModuleHandleT addIRModule(LayerT &Layer,
+                            Module *M,
+                            std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr,
+                            CExternalSymbolResolverFn ExternalResolver,
+                            void *ExternalResolverCtx) {
+
+    // Attach a data-layout if one isn't already present.
+    if (M->getDataLayout().isDefault())
+      M->setDataLayout(DL);
+
+    // Record the static constructors and destructors. We have to do this before
+    // we hand over ownership of the module to the JIT.
+    std::vector<std::string> CtorNames, DtorNames;
+    for (auto Ctor : orc::getConstructors(*M))
+      CtorNames.push_back(mangle(Ctor.Func->getName()));
+    for (auto Dtor : orc::getDestructors(*M))
+      DtorNames.push_back(mangle(Dtor.Func->getName()));
+
+    // Create the resolver.
+    auto Resolver = createResolver(ExternalResolver, ExternalResolverCtx);
+
+    // Add the module to the JIT.
+    std::vector<Module*> S;
+    S.push_back(std::move(M));
+
+    auto LH = Layer.addModuleSet(std::move(S), std::move(MemMgr),
+                                 std::move(Resolver));
+    ModuleHandleT H = createHandle(LH);
+
+    // Run the static constructors, and save the static destructor runner for
+    // execution when the JIT is torn down.
+    orc::CtorDtorRunner<OrcCBindingsStack> CtorRunner(std::move(CtorNames), H);
+    CtorRunner.runViaLayer(*this);
+
+    IRStaticDestructorRunners.emplace_back(std::move(DtorNames), H);
+
+    return H;
+  }
+
+  ModuleHandleT addIRModuleEager(Module* M,
+                                 CExternalSymbolResolverFn ExternalResolver,
+                                 void *ExternalResolverCtx) {
+    return addIRModule(CompileLayer, std::move(M),
+                       llvm::make_unique<SectionMemoryManager>(),
+                       std::move(ExternalResolver), ExternalResolverCtx);
+  }
+
+  ModuleHandleT addIRModuleLazy(Module* M,
+                                CExternalSymbolResolverFn ExternalResolver,
+                                void *ExternalResolverCtx) {
+    return addIRModule(CODLayer, std::move(M), nullptr,
+                       std::move(ExternalResolver), ExternalResolverCtx);
+  }
+
+  void removeModule(ModuleHandleT H) {
+    auto &HD = HandleData[H];
+    switch (HD.Type) {
+    case ObjectLayerHandle:
+      ObjectLayer.removeObjectSet(HD.RawHandle.Obj);
+      break;
+    case CODLayerHandle:
+      CODLayer.removeModuleSet(HD.RawHandle.COD);
+      break;
+    default:
+      llvm_unreachable("removeModule called on invalid handle type");
+    }
+  }
+
+  orc::JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
+    return CODLayer.findSymbol(mangle(Name), ExportedSymbolsOnly);
+  }
+
+  orc::JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name,
+                              bool ExportedSymbolsOnly) {
+    auto &HD = HandleData[H];
+    switch (HD.Type) {
+    case ObjectLayerHandle:
+      return ObjectLayer.findSymbolIn(HD.RawHandle.Obj, mangle(Name),
+                                      ExportedSymbolsOnly);
+    case CODLayerHandle:
+      return CODLayer.findSymbolIn(HD.RawHandle.COD, mangle(Name),
+                                   ExportedSymbolsOnly);
+    default:
+      llvm_unreachable("removeModule called on invalid handle type");
+    }
+  }
+
+private:
+
+  template <typename LayerHandleT>
+  unsigned createHandle(LayerHandleT LH) {
+    unsigned NewHandle;
+    if (!FreeHandles.empty()) {
+      NewHandle = FreeHandles.back();
+      FreeHandles.pop_back();
+      HandleData[NewHandle] = ModuleHandleData(std::move(LH));
+      return NewHandle;
+    } else {
+      NewHandle = HandleData.size();
+      HandleData.push_back(ModuleHandleData(std::move(LH)));
+    }
+    return NewHandle;
+  }
+
+  DataLayout DL;
+  SectionMemoryManager CCMgrMemMgr;
+
+  ObjLayerT ObjectLayer;
+  CompileLayerT CompileLayer;
+  std::unique_ptr<CompileCallbackMgr> CCMgr;
+  CODLayerT CODLayer;
+
+  std::vector<ModuleHandleData> HandleData;
+  std::vector<unsigned> FreeHandles;
+
+  orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides;
+  std::vector<orc::CtorDtorRunner<OrcCBindingsStack>> IRStaticDestructorRunners;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H
index 031eea5..dc401c9 100644 (file)
@@ -1,7 +1,11 @@
+
 set(LLVM_LINK_COMPONENTS
   Core
   OrcJIT
+  MC
   Support
+  Target
+  native
   )
 
 add_llvm_unittest(OrcJITTests
@@ -10,5 +14,6 @@ add_llvm_unittest(OrcJITTests
   GlobalMappingLayerTest.cpp
   LazyEmittingLayerTest.cpp
   ObjectTransformLayerTest.cpp
+  OrcCAPITest.cpp
   OrcTestCommon.cpp
   )
index 1a533b0..38b60ea 100644 (file)
@@ -18,7 +18,7 @@ namespace {
 
 TEST(IndirectionUtilsTest, MakeStub) {
   ModuleBuilder MB(getGlobalContext(), "x86_64-apple-macosx10.10", "");
-  Function *F = MB.createFunctionDecl<void(DummyStruct, DummyStruct)>(MB.getModule(), "");
+  Function *F = MB.createFunctionDecl<void(DummyStruct, DummyStruct)>("");
   SmallVector<AttributeSet, 4> Attrs;
   Attrs.push_back(
     AttributeSet::get(MB.getModule()->getContext(), 1U,
diff --git a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
new file mode 100644 (file)
index 0000000..bddb6a7
--- /dev/null
@@ -0,0 +1,109 @@
+//===--------------- OrcCAPITest.cpp - Unit tests Orc C API ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OrcTestCommon.h"
+#include "gtest/gtest.h"
+#include "llvm-c/OrcBindings.h"
+#include "llvm-c/Target.h"
+#include "llvm-c/TargetMachine.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace llvm {
+
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef);
+
+class OrcCAPIExecutionTest : public testing::Test, public OrcExecutionTest {
+protected:
+
+  std::unique_ptr<Module> createTestModule(const Triple &TT) {
+    ModuleBuilder MB(getGlobalContext(), TT.str(), "");
+    Function *TestFunc = MB.createFunctionDecl<int()>("testFunc");
+    Function *Main = MB.createFunctionDecl<int(int, char*[])>("main");
+
+    Main->getBasicBlockList().push_back(BasicBlock::Create(getGlobalContext()));
+    IRBuilder<> B(&Main->back());
+    Value* Result = B.CreateCall(TestFunc);
+    B.CreateRet(Result);
+
+    return MB.takeModule();
+  }
+
+  typedef int (*MainFnTy)(void);
+
+  static int myTestFuncImpl(void) {
+    return 42;
+  }
+
+  static char *testFuncName;
+
+  static uint64_t myResolver(const char *Name, void *Ctx) {
+    if (!strncmp(Name, testFuncName, 8))
+      return (uint64_t)&myTestFuncImpl;
+    return 0;
+  }
+
+};
+
+char *OrcCAPIExecutionTest::testFuncName = 0;
+
+TEST_F(OrcCAPIExecutionTest, TestEagerIRCompilation) {
+  auto TM = getHostTargetMachineIfSupported();
+
+  if (!TM)
+    return;
+
+  std::unique_ptr<Module> M = createTestModule(TM->getTargetTriple());
+
+  LLVMOrcJITStackRef JIT =
+    LLVMOrcCreateInstance(wrap(TM.get()), LLVMGetGlobalContext());
+
+  LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc");
+
+  LLVMOrcModuleHandle H =
+    LLVMOrcAddEagerlyCompiledIR(JIT, wrap(M.get()), myResolver, 0);
+  MainFnTy MainFn = (MainFnTy)LLVMOrcGetSymbolAddress(JIT, "main");
+  int Result = MainFn();
+  EXPECT_EQ(Result, 42)
+    << "Eagerly JIT'd code did not return expected result";
+
+  LLVMOrcRemoveModule(JIT, H);
+
+  LLVMOrcDisposeMangledSymbol(testFuncName);
+  LLVMOrcDisposeInstance(JIT);
+}
+
+TEST_F(OrcCAPIExecutionTest, TestLazyIRCompilation) {
+  auto TM = getHostTargetMachineIfSupported();
+
+  if (!TM)
+    return;
+
+  std::unique_ptr<Module> M = createTestModule(TM->getTargetTriple());
+
+  LLVMOrcJITStackRef JIT =
+    LLVMOrcCreateInstance(wrap(TM.get()), LLVMGetGlobalContext());
+
+  LLVMOrcGetMangledSymbol(JIT, &testFuncName, "testFunc");
+  LLVMOrcModuleHandle H =
+    LLVMOrcAddLazilyCompiledIR(JIT, wrap(M.get()), myResolver, 0);
+  MainFnTy MainFn = (MainFnTy)LLVMOrcGetSymbolAddress(JIT, "main");
+  int Result = MainFn();
+  EXPECT_EQ(Result, 42)
+    << "Lazily JIT'd code did not return expected result";
+
+  LLVMOrcRemoveModule(JIT, H);
+
+  LLVMOrcDisposeMangledSymbol(testFuncName);
+  LLVMOrcDisposeInstance(JIT);
+}
+
+}
index 5fea3c8..1b5485d 100644 (file)
@@ -15,6 +15,8 @@
 
 using namespace llvm;
 
+bool OrcExecutionTest::NativeTargetInitialized = false;
+
 ModuleBuilder::ModuleBuilder(LLVMContext &Context, StringRef Triple,
                              StringRef Name)
   : M(new Module(Name, Context)),
index 4be2e19..18e3874 100644 (file)
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/TypeBuilder.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
 #include "llvm/ExecutionEngine/Orc/JITSymbol.h"
+#include "llvm/Support/TargetSelect.h"
 #include <memory>
 
 namespace llvm {
 
+// Base class for Orc tests that will execute code.
+class OrcExecutionTest {
+public:
+
+  OrcExecutionTest() {
+    if (!NativeTargetInitialized) {
+      InitializeNativeTarget();
+      InitializeNativeTargetAsmParser();
+      InitializeNativeTargetAsmPrinter();
+      NativeTargetInitialized = true;
+    }
+  };
+
+  // Get a target machine for the host if it supports JIT execution.
+  std::unique_ptr<TargetMachine> getHostTargetMachineIfSupported() {
+    std::unique_ptr<TargetMachine> TM(EngineBuilder().selectTarget());
+
+    const Triple& TT = TM->getTargetTriple();
+
+    if (TT.getArch() == Triple::x86_64)
+      return std::move(TM);
+
+    return nullptr;
+  }
+
+private:
+  static bool NativeTargetInitialized;
+};
+
 class ModuleBuilder {
 public:
   ModuleBuilder(LLVMContext &Context, StringRef Triple,
                 StringRef Name);
 
   template <typename FuncType>
-  Function* createFunctionDecl(Module *M, StringRef Name) {
+  Function* createFunctionDecl(StringRef Name) {
     return Function::Create(
              TypeBuilder<FuncType, false>::get(M->getContext()),
-             GlobalValue::ExternalLinkage, Name, M);
+             GlobalValue::ExternalLinkage, Name, M.get());
   }
 
   Module* getModule() { return M.get(); }