Exposing MCJIT through C API

Re-submitting with fix for OCaml dependency problems (removing dependency on SectionMemoryManager when it isn't used).

Patch by Fili Pizlo



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180720 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt
index 9ffe613..922cb7e 100644
--- a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt
+++ b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt
@@ -9,6 +9,7 @@
 
 set(MCJITTestsSources
   MCJITTest.cpp
+  MCJITCAPITest.cpp
   MCJITMemoryManagerTest.cpp
   MCJITObjectCacheTest.cpp
   )
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
new file mode 100644
index 0000000..780fbc1
--- /dev/null
+++ b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
@@ -0,0 +1,93 @@
+//===- MCJITTest.cpp - Unit tests for the MCJIT ---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This test suite verifies basic MCJIT functionality when invoked form the C
+// API.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c/Analysis.h"
+#include "llvm-c/Core.h"
+#include "llvm-c/ExecutionEngine.h"
+#include "llvm-c/Target.h"
+#include "llvm-c/Transforms/Scalar.h"
+#include "llvm/Support/Host.h"
+#include "MCJITTestAPICommon.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon {
+protected:
+  MCJITCAPITest() {
+    // The architectures below are known to be compatible with MCJIT as they
+    // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
+    // kept in sync.
+    SupportedArchs.push_back(Triple::arm);
+    SupportedArchs.push_back(Triple::mips);
+    SupportedArchs.push_back(Triple::x86);
+    SupportedArchs.push_back(Triple::x86_64);
+
+    // The operating systems below are known to be sufficiently incompatible
+    // that they will fail the MCJIT C API tests.
+    UnsupportedOSs.push_back(Triple::Cygwin);
+  }
+};
+
+TEST_F(MCJITCAPITest, simple_function) {
+  SKIP_UNSUPPORTED_PLATFORM;
+  
+  char *error = 0;
+  
+  // Creates a function that returns 42, compiles it, and runs it.
+  
+  LLVMModuleRef module = LLVMModuleCreateWithName("simple_module");
+  
+  LLVMValueRef function = LLVMAddFunction(
+    module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
+  LLVMSetFunctionCallConv(function, LLVMCCallConv);
+  
+  LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function, "entry");
+  LLVMBuilderRef builder = LLVMCreateBuilder();
+  LLVMPositionBuilderAtEnd(builder, entry);
+  LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
+  
+  LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
+  LLVMDisposeMessage(error);
+  
+  LLVMDisposeBuilder(builder);
+  
+  LLVMMCJITCompilerOptions options;
+  memset(&options, 0, sizeof(options));
+  options.OptLevel = 2;
+  options.NoFramePointerElim = false; // Just ensure that this field still exists.
+  
+  LLVMExecutionEngineRef engine;
+  ASSERT_EQ(
+    0, LLVMCreateMCJITCompilerForModule(&engine, module, &options, sizeof(options),
+                                        &error));
+  
+  LLVMPassManagerRef pass = LLVMCreatePassManager();
+  LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass);
+  LLVMAddConstantPropagationPass(pass);
+  LLVMAddInstructionCombiningPass(pass);
+  LLVMRunPassManager(pass, module);
+  LLVMDisposePassManager(pass);
+  
+  union {
+    void *raw;
+    int (*usable)();
+  } functionPointer;
+  functionPointer.raw = LLVMGetPointerToGlobal(engine, function);
+  
+  EXPECT_EQ(42, functionPointer.usable());
+  
+  LLVMDisposeExecutionEngine(engine);
+}
+
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h b/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h
new file mode 100644
index 0000000..8160a18
--- /dev/null
+++ b/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h
@@ -0,0 +1,77 @@
+//===- MCJITTestBase.h - Common base class for MCJIT Unit tests  ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements functionality shared by both MCJIT C API tests, and
+// the C++ API tests.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MCJIT_TEST_API_COMMON_H
+#define MCJIT_TEST_API_COMMON_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/TargetSelect.h"
+
+// Used to skip tests on unsupported architectures and operating systems.
+// To skip a test, add this macro at the top of a test-case in a suite that
+// inherits from MCJITTestBase. See MCJITTest.cpp for examples.
+#define SKIP_UNSUPPORTED_PLATFORM \
+  do \
+    if (!ArchSupportsMCJIT() || !OSSupportsMCJIT()) \
+      return; \
+  while(0)
+
+namespace llvm {
+
+class MCJITTestAPICommon {
+protected:
+  MCJITTestAPICommon()
+    : HostTriple(sys::getProcessTriple())
+  {
+    InitializeNativeTarget();
+    InitializeNativeTargetAsmPrinter();
+
+#ifdef LLVM_ON_WIN32
+    // On Windows, generate ELF objects by specifying "-elf" in triple
+    HostTriple += "-elf";
+#endif // LLVM_ON_WIN32
+    HostTriple = Triple::normalize(HostTriple);
+  }
+
+  /// Returns true if the host architecture is known to support MCJIT
+  bool ArchSupportsMCJIT() {
+    Triple Host(HostTriple);
+    if (std::find(SupportedArchs.begin(), SupportedArchs.end(), Host.getArch())
+        == SupportedArchs.end()) {
+      return false;
+    }
+    return true;
+  }
+
+  /// Returns true if the host OS is known to support MCJIT
+  bool OSSupportsMCJIT() {
+    Triple Host(HostTriple);
+    if (std::find(UnsupportedOSs.begin(), UnsupportedOSs.end(), Host.getOS())
+        == UnsupportedOSs.end()) {
+      return true;
+    }
+    return false;
+  }
+
+  std::string HostTriple;
+  SmallVector<Triple::ArchType, 4> SupportedArchs;
+  SmallVector<Triple::OSType, 4> UnsupportedOSs;
+};
+
+} // namespace llvm
+
+#endif // MCJIT_TEST_API_COMMON_H
+
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h
index fc774ab..b0e98a8 100644
--- a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h
+++ b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h
@@ -17,8 +17,6 @@
 #ifndef MCJIT_TEST_BASE_H
 #define MCJIT_TEST_BASE_H
 
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
 #include "llvm/Config/config.h"
 #include "llvm/ExecutionEngine/ExecutionEngine.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
@@ -28,21 +26,11 @@
 #include "llvm/IR/Module.h"
 #include "llvm/IR/TypeBuilder.h"
 #include "llvm/Support/CodeGen.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/TargetSelect.h"
-
-// Used to skip tests on unsupported architectures and operating systems.
-// To skip a test, add this macro at the top of a test-case in a suite that
-// inherits from MCJITTestBase. See MCJITTest.cpp for examples.
-#define SKIP_UNSUPPORTED_PLATFORM \
-  do \
-    if (!ArchSupportsMCJIT() || !OSSupportsMCJIT()) \
-      return; \
-  while(0);
+#include "MCJITTestAPICommon.h"
 
 namespace llvm {
 
-class MCJITTestBase {
+class MCJITTestBase : public MCJITTestAPICommon {
 protected:
 
   MCJITTestBase()
@@ -52,17 +40,7 @@
     , MArch("")
     , Builder(Context)
     , MM(new SectionMemoryManager)
-    , HostTriple(sys::getProcessTriple())
   {
-    InitializeNativeTarget();
-    InitializeNativeTargetAsmPrinter();
-
-#ifdef LLVM_ON_WIN32
-    // On Windows, generate ELF objects by specifying "-elf" in triple
-    HostTriple += "-elf";
-#endif // LLVM_ON_WIN32
-    HostTriple = Triple::normalize(HostTriple);
-
     // The architectures below are known to be compatible with MCJIT as they
     // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be
     // kept in sync.
@@ -78,26 +56,6 @@
     UnsupportedOSs.push_back(Triple::Darwin);
   }
 
-  /// Returns true if the host architecture is known to support MCJIT
-  bool ArchSupportsMCJIT() {
-    Triple Host(HostTriple);
-    if (std::find(SupportedArchs.begin(), SupportedArchs.end(), Host.getArch())
-        == SupportedArchs.end()) {
-      return false;
-    }
-    return true;
-  }
-
-  /// Returns true if the host OS is known to support MCJIT
-  bool OSSupportsMCJIT() {
-    Triple Host(HostTriple);
-    if (std::find(UnsupportedOSs.begin(), UnsupportedOSs.end(), Host.getOS())
-        == UnsupportedOSs.end()) {
-      return true;
-    }
-    return false;
-  }
-
   Module *createEmptyModule(StringRef Name) {
     Module * M = new Module(Name, Context);
     M->setTargetTriple(Triple::normalize(HostTriple));
@@ -232,10 +190,6 @@
   IRBuilder<> Builder;
   JITMemoryManager *MM;
 
-  std::string HostTriple;
-  SmallVector<Triple::ArchType, 4> SupportedArchs;
-  SmallVector<Triple::OSType, 4> UnsupportedOSs;
-
   OwningPtr<Module> M;
 };