summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kaylor <andrew.kaylor@intel.com>2013-04-29 17:49:40 +0000
committerAndrew Kaylor <andrew.kaylor@intel.com>2013-04-29 17:49:40 +0000
commitd2755af8bda2e0fd80efb46556485c4cdbe8704a (patch)
tree2bf7b4c7494a8692b0a982b9b7c774a196cb100e
parent87b5017139e9d8ac9b046b3284a9cc68c76185d6 (diff)
downloadllvm-d2755af8bda2e0fd80efb46556485c4cdbe8704a.tar.gz
llvm-d2755af8bda2e0fd80efb46556485c4cdbe8704a.tar.bz2
llvm-d2755af8bda2e0fd80efb46556485c4cdbe8704a.tar.xz
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
-rw-r--r--bindings/ocaml/executionengine/Makefile2
-rw-r--r--include/llvm-c/ExecutionEngine.h28
-rw-r--r--lib/ExecutionEngine/ExecutionEngineBindings.cpp46
-rw-r--r--lib/ExecutionEngine/MCJIT/MCJIT.cpp3
-rw-r--r--unittests/ExecutionEngine/MCJIT/CMakeLists.txt1
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp93
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h77
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITTestBase.h50
8 files changed, 250 insertions, 50 deletions
diff --git a/bindings/ocaml/executionengine/Makefile b/bindings/ocaml/executionengine/Makefile
index 45b5049914..5fa3f22048 100644
--- a/bindings/ocaml/executionengine/Makefile
+++ b/bindings/ocaml/executionengine/Makefile
@@ -13,7 +13,7 @@
LEVEL := ../../..
LIBRARYNAME := llvm_executionengine
-UsedComponents := executionengine jit interpreter mcjit native
+UsedComponents := executionengine jit interpreter native
UsedOcamlInterfaces := llvm llvm_target
include ../Makefile.ocaml
diff --git a/include/llvm-c/ExecutionEngine.h b/include/llvm-c/ExecutionEngine.h
index be763312d2..8b654d5a5c 100644
--- a/include/llvm-c/ExecutionEngine.h
+++ b/include/llvm-c/ExecutionEngine.h
@@ -34,11 +34,17 @@ extern "C" {
*/
void LLVMLinkInJIT(void);
+void LLVMLinkInMCJIT(void);
void LLVMLinkInInterpreter(void);
typedef struct LLVMOpaqueGenericValue *LLVMGenericValueRef;
typedef struct LLVMOpaqueExecutionEngine *LLVMExecutionEngineRef;
+struct LLVMMCJITCompilerOptions {
+ unsigned OptLevel;
+ LLVMBool NoFramePointerElim;
+};
+
/*===-- Operations on generic values --------------------------------------===*/
LLVMGenericValueRef LLVMCreateGenericValueOfInt(LLVMTypeRef Ty,
@@ -75,6 +81,28 @@ LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
unsigned OptLevel,
char **OutError);
+/**
+ * Create an MCJIT execution engine for a module, with the given options. It is
+ * the responsibility of the caller to ensure that all fields in Options up to
+ * the given SizeOfOptions are initialized. It is correct to pass a smaller value
+ * of SizeOfOptions that omits some fields, and it is also correct to set any
+ * field to zero. The canonical way of using this is:
+ *
+ * LLVMMCJITCompilerOptions options;
+ * memset(&options, 0, sizeof(options));
+ * ... fill in those options you care about
+ * LLVMCreateMCJITCompilerForModule(&jit, mod, &options, sizeof(options), &error);
+ *
+ * Note that this is also correct, though possibly suboptimal:
+ *
+ * LLVMCreateMCJITCompilerForModule(&jit, mod, 0, 0, &error);
+ */
+LLVMBool LLVMCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
+ LLVMModuleRef M,
+ struct LLVMMCJITCompilerOptions *Options,
+ size_t SizeOfOptions,
+ char **OutError);
+
/** Deprecated: Use LLVMCreateExecutionEngineForModule instead. */
LLVMBool LLVMCreateExecutionEngine(LLVMExecutionEngineRef *OutEE,
LLVMModuleProviderRef MP,
diff --git a/lib/ExecutionEngine/ExecutionEngineBindings.cpp b/lib/ExecutionEngine/ExecutionEngineBindings.cpp
index 3e6dcdf5ba..44fa92205b 100644
--- a/lib/ExecutionEngine/ExecutionEngineBindings.cpp
+++ b/lib/ExecutionEngine/ExecutionEngineBindings.cpp
@@ -152,6 +152,46 @@ LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
return 1;
}
+LLVMBool LLVMCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
+ LLVMModuleRef M,
+ LLVMMCJITCompilerOptions *PassedOptions,
+ size_t SizeOfPassedOptions,
+ char **OutError) {
+ LLVMMCJITCompilerOptions options;
+ // If the user passed a larger sized options struct, then they were compiled
+ // against a newer LLVM. Tell them that something is wrong.
+ if (SizeOfPassedOptions > sizeof(options)) {
+ *OutError = strdup(
+ "Refusing to use options struct that is larger than my own; assuming LLVM "
+ "library mismatch.");
+ return 1;
+ }
+
+ // Defend against the user having an old version of the API by ensuring that
+ // any fields they didn't see are cleared. We must defend against fields being
+ // set to the bitwise equivalent of zero, and assume that this means "do the
+ // default" as if that option hadn't been available.
+ memset(&options, 0, sizeof(options));
+ memcpy(&options, PassedOptions, SizeOfPassedOptions);
+
+ TargetOptions targetOptions;
+ targetOptions.NoFramePointerElim = options.NoFramePointerElim;
+
+ std::string Error;
+ EngineBuilder builder(unwrap(M));
+ builder.setEngineKind(EngineKind::JIT)
+ .setErrorStr(&Error)
+ .setUseMCJIT(true)
+ .setOptLevel((CodeGenOpt::Level)options.OptLevel)
+ .setTargetOptions(targetOptions);
+ if (ExecutionEngine *JIT = builder.create()) {
+ *OutJIT = wrap(JIT);
+ return 0;
+ }
+ *OutError = strdup(Error.c_str());
+ return 1;
+}
+
LLVMBool LLVMCreateExecutionEngine(LLVMExecutionEngineRef *OutEE,
LLVMModuleProviderRef MP,
char **OutError) {
@@ -196,6 +236,8 @@ void LLVMRunStaticDestructors(LLVMExecutionEngineRef EE) {
int LLVMRunFunctionAsMain(LLVMExecutionEngineRef EE, LLVMValueRef F,
unsigned ArgC, const char * const *ArgV,
const char * const *EnvP) {
+ unwrap(EE)->finalizeObject();
+
std::vector<std::string> ArgVec;
for (unsigned I = 0; I != ArgC; ++I)
ArgVec.push_back(ArgV[I]);
@@ -206,6 +248,8 @@ int LLVMRunFunctionAsMain(LLVMExecutionEngineRef EE, LLVMValueRef F,
LLVMGenericValueRef LLVMRunFunction(LLVMExecutionEngineRef EE, LLVMValueRef F,
unsigned NumArgs,
LLVMGenericValueRef *Args) {
+ unwrap(EE)->finalizeObject();
+
std::vector<GenericValue> ArgVec;
ArgVec.reserve(NumArgs);
for (unsigned I = 0; I != NumArgs; ++I)
@@ -268,5 +312,7 @@ void LLVMAddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global,
}
void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global) {
+ unwrap(EE)->finalizeObject();
+
return unwrap(EE)->getPointerToGlobal(unwrap<GlobalValue>(Global));
}
diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp
index 9e42cd0441..f4e5e61aa8 100644
--- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp
+++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp
@@ -14,6 +14,7 @@
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectBuffer.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
@@ -46,7 +47,7 @@ ExecutionEngine *MCJIT::createJIT(Module *M,
// FIXME: Don't do this here.
sys::DynamicLibrary::LoadLibraryPermanently(0, NULL);
- return new MCJIT(M, TM, JMM, GVsWithCode);
+ return new MCJIT(M, TM, JMM ? JMM : new SectionMemoryManager(), GVsWithCode);
}
MCJIT::MCJIT(Module *m, TargetMachine *tm, RTDyldMemoryManager *MM,
diff --git a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt
index 9ffe6138ad..922cb7efd5 100644
--- a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt
+++ b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt
@@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS
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 0000000000..780fbc1b7b
--- /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 0000000000..8160a186f4
--- /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 fc774abd62..b0e98a88de 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 @@ protected:
, 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 @@ protected:
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 @@ protected:
IRBuilder<> Builder;
JITMemoryManager *MM;
- std::string HostTriple;
- SmallVector<Triple::ArchType, 4> SupportedArchs;
- SmallVector<Triple::OSType, 4> UnsupportedOSs;
-
OwningPtr<Module> M;
};