summaryrefslogtreecommitdiff
path: root/unittests/ExecutionEngine
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2013-12-22 00:04:03 +0000
committerDimitry Andric <dim@FreeBSD.org>2013-12-22 00:04:03 +0000
commitf8af5cf600354830d4ccf59732403f0f073eccb9 (patch)
tree2ba0398b4c42ad4f55561327538044fd2c925a8b /unittests/ExecutionEngine
parent59d6cff90eecf31cb3dd860c4e786674cfdd42eb (diff)
Diffstat (limited to 'unittests/ExecutionEngine')
-rw-r--r--unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp23
-rw-r--r--unittests/ExecutionEngine/JIT/JITTest.cpp173
-rw-r--r--unittests/ExecutionEngine/MCJIT/CMakeLists.txt2
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp175
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp344
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp395
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp24
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITTest.cpp113
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h20
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITTestBase.h217
-rw-r--r--unittests/ExecutionEngine/MCJIT/Makefile2
11 files changed, 1006 insertions, 482 deletions
diff --git a/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp b/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp
index 21ca0d448ced3..731f7807f5934 100644
--- a/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp
+++ b/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp
@@ -277,4 +277,27 @@ TEST(JITMemoryManagerTest, TestManyStubs) {
EXPECT_EQ(3U, MemMgr->GetNumStubSlabs());
}
+// Check section allocation and alignment
+TEST(JITMemoryManagerTest, AllocateSection) {
+ OwningPtr<JITMemoryManager> MemMgr(
+ JITMemoryManager::CreateDefaultMemManager());
+ uint8_t *code1 = MemMgr->allocateCodeSection(256, 0, 1, StringRef());
+ uint8_t *data1 = MemMgr->allocateDataSection(256, 16, 2, StringRef(), true);
+ uint8_t *code2 = MemMgr->allocateCodeSection(257, 32, 3, StringRef());
+ uint8_t *data2 = MemMgr->allocateDataSection(256, 64, 4, StringRef(), false);
+ uint8_t *code3 = MemMgr->allocateCodeSection(258, 64, 5, StringRef());
+
+ EXPECT_NE((uint8_t*)0, code1);
+ EXPECT_NE((uint8_t*)0, code2);
+ EXPECT_NE((uint8_t*)0, data1);
+ EXPECT_NE((uint8_t*)0, data2);
+
+ // Check alignment
+ EXPECT_EQ((uint64_t)code1 & 0xf, 0u);
+ EXPECT_EQ((uint64_t)code2 & 0x1f, 0u);
+ EXPECT_EQ((uint64_t)code3 & 0x3f, 0u);
+ EXPECT_EQ((uint64_t)data1 & 0xf, 0u);
+ EXPECT_EQ((uint64_t)data2 & 0x3f, 0u);
+}
+
}
diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp
index e6f4cb9af25f5..4c7b1e23195d9 100644
--- a/unittests/ExecutionEngine/JIT/JITTest.cpp
+++ b/unittests/ExecutionEngine/JIT/JITTest.cpp
@@ -33,6 +33,22 @@
using namespace llvm;
+// This variable is intentionally defined differently in the statically-compiled
+// program from the IR input to the JIT to assert that the JIT doesn't use its
+// definition. Note that this variable must be defined even on platforms where
+// JIT tests are disabled as it is referenced from the .def file.
+extern "C" int32_t JITTest_AvailableExternallyGlobal;
+int32_t JITTest_AvailableExternallyGlobal LLVM_ATTRIBUTE_USED = 42;
+
+// This function is intentionally defined differently in the statically-compiled
+// program from the IR input to the JIT to assert that the JIT doesn't use its
+// definition. Note that this function must be defined even on platforms where
+// JIT tests are disabled as it is referenced from the .def file.
+extern "C" int32_t JITTest_AvailableExternallyFunction() LLVM_ATTRIBUTE_USED;
+extern "C" int32_t JITTest_AvailableExternallyFunction() {
+ return 42;
+}
+
namespace {
// Tests on ARM, PowerPC and SystemZ disabled as we're running the old jit
@@ -119,15 +135,19 @@ public:
EndFunctionBodyCall(F, FunctionStart, FunctionEnd));
Base->endFunctionBody(F, FunctionStart, FunctionEnd);
}
- virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID, bool IsReadOnly) {
- return Base->allocateDataSection(Size, Alignment, SectionID, IsReadOnly);
+ virtual uint8_t *allocateDataSection(
+ uintptr_t Size, unsigned Alignment, unsigned SectionID,
+ StringRef SectionName, bool IsReadOnly) {
+ return Base->allocateDataSection(
+ Size, Alignment, SectionID, SectionName, IsReadOnly);
}
- virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID) {
- return Base->allocateCodeSection(Size, Alignment, SectionID);
+ virtual uint8_t *allocateCodeSection(
+ uintptr_t Size, unsigned Alignment, unsigned SectionID,
+ StringRef SectionName) {
+ return Base->allocateCodeSection(
+ Size, Alignment, SectionID, SectionName);
}
- virtual bool applyPermissions(std::string *ErrMsg) { return false; }
+ virtual bool finalizeMemory(std::string *ErrMsg) { return false; }
virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
return Base->allocateSpace(Size, Alignment);
}
@@ -143,54 +163,6 @@ public:
deallocateFunctionBodyCalls.push_back(DeallocateFunctionBodyCall(Body));
Base->deallocateFunctionBody(Body);
}
- struct DeallocateExceptionTableCall {
- DeallocateExceptionTableCall(const void *ET) : ET(ET) {}
- const void *ET;
- };
- std::vector<DeallocateExceptionTableCall> deallocateExceptionTableCalls;
- virtual void deallocateExceptionTable(void *ET) {
- deallocateExceptionTableCalls.push_back(DeallocateExceptionTableCall(ET));
- Base->deallocateExceptionTable(ET);
- }
- struct StartExceptionTableCall {
- StartExceptionTableCall(uint8_t *Result, const Function *F,
- uintptr_t ActualSize, uintptr_t ActualSizeResult)
- : Result(Result), F(F), F_dump(DumpFunction(F)),
- ActualSize(ActualSize), ActualSizeResult(ActualSizeResult) {}
- uint8_t *Result;
- const Function *F;
- std::string F_dump;
- uintptr_t ActualSize;
- uintptr_t ActualSizeResult;
- };
- std::vector<StartExceptionTableCall> startExceptionTableCalls;
- virtual uint8_t *startExceptionTable(const Function *F,
- uintptr_t &ActualSize) {
- uintptr_t InitialActualSize = ActualSize;
- uint8_t *Result = Base->startExceptionTable(F, ActualSize);
- startExceptionTableCalls.push_back(
- StartExceptionTableCall(Result, F, InitialActualSize, ActualSize));
- return Result;
- }
- struct EndExceptionTableCall {
- EndExceptionTableCall(const Function *F, uint8_t *TableStart,
- uint8_t *TableEnd, uint8_t* FrameRegister)
- : F(F), F_dump(DumpFunction(F)),
- TableStart(TableStart), TableEnd(TableEnd),
- FrameRegister(FrameRegister) {}
- const Function *F;
- std::string F_dump;
- uint8_t *TableStart;
- uint8_t *TableEnd;
- uint8_t *FrameRegister;
- };
- std::vector<EndExceptionTableCall> endExceptionTableCalls;
- virtual void endExceptionTable(const Function *F, uint8_t *TableStart,
- uint8_t *TableEnd, uint8_t* FrameRegister) {
- endExceptionTableCalls.push_back(
- EndExceptionTableCall(F, TableStart, TableEnd, FrameRegister));
- return Base->endExceptionTable(F, TableStart, TableEnd, FrameRegister);
- }
};
bool LoadAssemblyInto(Module *M, const char *assembly) {
@@ -216,7 +188,6 @@ class JITTest : public testing::Test {
RJMM->setPoisonMemory(true);
std::string Error;
TargetOptions Options;
- Options.JITExceptionHandling = true;
TheJIT.reset(EngineBuilder(M).setEngineKind(EngineKind::JIT)
.setJITMemoryManager(RJMM)
.setErrorStr(&Error)
@@ -302,46 +273,6 @@ TEST(JIT, GlobalInFunction) {
EXPECT_EQ(3, *GPtr);
}
-// Regression test for a bug. The JITEmitter wasn't checking to verify that
-// it hadn't run out of space while generating the DWARF exception information
-// for an emitted function.
-
-class ExceptionMemoryManagerMock : public RecordingJITMemoryManager {
- public:
- virtual uint8_t *startExceptionTable(const Function *F,
- uintptr_t &ActualSize) {
- // force an insufficient size the first time through.
- bool ChangeActualSize = false;
- if (ActualSize == 0)
- ChangeActualSize = true;;
- uint8_t *result =
- RecordingJITMemoryManager::startExceptionTable(F, ActualSize);
- if (ChangeActualSize)
- ActualSize = 1;
- return result;
- }
-};
-
-class JITExceptionMemoryTest : public JITTest {
- protected:
- virtual RecordingJITMemoryManager *createMemoryManager() {
- return new ExceptionMemoryManagerMock;
- }
-};
-
-TEST_F(JITExceptionMemoryTest, ExceptionTableOverflow) {
- Function *F = Function::Create(TypeBuilder<void(void), false>::get(Context),
- Function::ExternalLinkage,
- "func1", M);
- BasicBlock *Block = BasicBlock::Create(Context, "block", F);
- IRBuilder<> Builder(Block);
- Builder.CreateRetVoid();
- TheJIT->getPointerToFunction(F);
- ASSERT_TRUE(RJMM->startExceptionTableCalls.size() == 2);
- ASSERT_TRUE(RJMM->deallocateExceptionTableCalls.size() == 1);
- ASSERT_TRUE(RJMM->endExceptionTableCalls.size() == 1);
-}
-
int PlusOne(int arg) {
return arg + 1;
}
@@ -501,27 +432,6 @@ TEST_F(JITTest, ModuleDeletion) {
}
EXPECT_EQ(RJMM->startFunctionBodyCalls.size(),
RJMM->deallocateFunctionBodyCalls.size());
-
- SmallPtrSet<const void*, 2> ExceptionTablesDeallocated;
- unsigned NumTablesDeallocated = 0;
- for (unsigned i = 0, e = RJMM->deallocateExceptionTableCalls.size();
- i != e; ++i) {
- ExceptionTablesDeallocated.insert(
- RJMM->deallocateExceptionTableCalls[i].ET);
- if (RJMM->deallocateExceptionTableCalls[i].ET != NULL) {
- // If JITEmitDebugInfo is off, we'll "deallocate" NULL, which doesn't
- // appear in startExceptionTableCalls.
- NumTablesDeallocated++;
- }
- }
- for (unsigned i = 0, e = RJMM->startExceptionTableCalls.size(); i != e; ++i) {
- EXPECT_TRUE(ExceptionTablesDeallocated.count(
- RJMM->startExceptionTableCalls[i].Result))
- << "Function's exception table leaked: \n"
- << RJMM->startExceptionTableCalls[i].F_dump;
- }
- EXPECT_EQ(RJMM->startExceptionTableCalls.size(),
- NumTablesDeallocated);
}
// ARM, MIPS and PPC still emit stubs for calls since the target may be
@@ -637,14 +547,6 @@ TEST_F(JITTest, FunctionIsRecompiledAndRelinked) {
}
#endif // !defined(__arm__)
-} // anonymous namespace
-// This variable is intentionally defined differently in the statically-compiled
-// program from the IR input to the JIT to assert that the JIT doesn't use its
-// definition.
-extern "C" int32_t JITTest_AvailableExternallyGlobal;
-int32_t JITTest_AvailableExternallyGlobal LLVM_ATTRIBUTE_USED = 42;
-namespace {
-
TEST_F(JITTest, AvailableExternallyGlobalIsntEmitted) {
TheJIT->DisableLazyCompilation(true);
LoadAssembly("@JITTest_AvailableExternallyGlobal = "
@@ -661,15 +563,6 @@ TEST_F(JITTest, AvailableExternallyGlobalIsntEmitted) {
EXPECT_EQ(42, loader()) << "func should return 42 from the external global,"
<< " not 7 from the IR version.";
}
-} // anonymous namespace
-// This function is intentionally defined differently in the statically-compiled
-// program from the IR input to the JIT to assert that the JIT doesn't use its
-// definition.
-extern "C" int32_t JITTest_AvailableExternallyFunction() LLVM_ATTRIBUTE_USED;
-extern "C" int32_t JITTest_AvailableExternallyFunction() {
- return 42;
-}
-namespace {
TEST_F(JITTest, AvailableExternallyFunctionIsntCompiled) {
TheJIT->DisableLazyCompilation(true);
@@ -828,16 +721,4 @@ TEST(LazyLoadedJITTest, EagerCompiledRecursionThroughGhost) {
}
#endif // !defined(__arm__) && !defined(__powerpc__) && !defined(__s390__)
-// This code is copied from JITEventListenerTest, but it only runs once for all
-// the tests in this directory. Everything seems fine, but that's strange
-// behavior.
-class JITEnvironment : public testing::Environment {
- virtual void SetUp() {
- // Required to create a JIT.
- InitializeNativeTarget();
- }
-};
-testing::Environment* const jit_env =
- testing::AddGlobalTestEnvironment(new JITEnvironment);
-
}
diff --git a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt
index 922cb7efd5eb6..ed4309919387d 100644
--- a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt
+++ b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt
@@ -2,7 +2,6 @@ set(LLVM_LINK_COMPONENTS
asmparser
bitreader
bitwriter
- jit
mcjit
nativecodegen
)
@@ -11,6 +10,7 @@ set(MCJITTestsSources
MCJITTest.cpp
MCJITCAPITest.cpp
MCJITMemoryManagerTest.cpp
+ MCJITMultipleModuleTest.cpp
MCJITObjectCacheTest.cpp
)
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
index 07ea1afe1a85f..46d6d9b8a9a60 100644
--- a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
+++ b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
@@ -17,81 +17,180 @@
#include "llvm-c/ExecutionEngine.h"
#include "llvm-c/Target.h"
#include "llvm-c/Transforms/Scalar.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/Support/Host.h"
#include "MCJITTestAPICommon.h"
#include "gtest/gtest.h"
using namespace llvm;
+static bool didCallAllocateCodeSection;
+
+static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
+ unsigned alignment,
+ unsigned sectionID,
+ const char *sectionName) {
+ didCallAllocateCodeSection = true;
+ return static_cast<SectionMemoryManager*>(object)->allocateCodeSection(
+ size, alignment, sectionID, sectionName);
+}
+
+static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
+ unsigned alignment,
+ unsigned sectionID,
+ const char *sectionName,
+ LLVMBool isReadOnly) {
+ return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
+ size, alignment, sectionID, sectionName, isReadOnly);
+}
+
+static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) {
+ std::string errMsgString;
+ bool result =
+ static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString);
+ if (result) {
+ *errMsg = LLVMCreateMessage(errMsgString.c_str());
+ return 1;
+ }
+ return 0;
+}
+
+static void roundTripDestroy(void *object) {
+ delete static_cast<SectionMemoryManager*>(object);
+}
+
+namespace {
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::aarch64);
SupportedArchs.push_back(Triple::arm);
SupportedArchs.push_back(Triple::mips);
SupportedArchs.push_back(Triple::x86);
SupportedArchs.push_back(Triple::x86_64);
+ // Some architectures have sub-architectures in which tests will fail, like
+ // ARM. These two vectors will define if they do have sub-archs (to avoid
+ // extra work for those who don't), and if so, if they are listed to work
+ HasSubArchs.push_back(Triple::arm);
+ SupportedSubArchs.push_back("armv6");
+ SupportedSubArchs.push_back("armv7");
+
// 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;
+ virtual void SetUp() {
+ didCallAllocateCodeSection = false;
+ Module = 0;
+ Function = 0;
+ Engine = 0;
+ Error = 0;
+ }
- // Creates a function that returns 42, compiles it, and runs it.
+ virtual void TearDown() {
+ if (Engine)
+ LLVMDisposeExecutionEngine(Engine);
+ else if (Module)
+ LLVMDisposeModule(Module);
+ }
- LLVMModuleRef module = LLVMModuleCreateWithName("simple_module");
-
- LLVMSetTarget(module, HostTriple.c_str());
+ void buildSimpleFunction() {
+ Module = LLVMModuleCreateWithName("simple_module");
+
+ LLVMSetTarget(Module, HostTriple.c_str());
+
+ 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);
+ }
- LLVMValueRef function = LLVMAddFunction(
- module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
- LLVMSetFunctionCallConv(function, LLVMCCallConv);
+ void buildMCJITOptions() {
+ LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
+ Options.OptLevel = 2;
+
+ // Just ensure that this field still exists.
+ Options.NoFramePointerElim = false;
+ }
- LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function, "entry");
- LLVMBuilderRef builder = LLVMCreateBuilder();
- LLVMPositionBuilderAtEnd(builder, entry);
- LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
+ void useRoundTripSectionMemoryManager() {
+ Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
+ new SectionMemoryManager(),
+ roundTripAllocateCodeSection,
+ roundTripAllocateDataSection,
+ roundTripFinalizeMemory,
+ roundTripDestroy);
+ }
- LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
- LLVMDisposeMessage(error);
+ void buildMCJITEngine() {
+ ASSERT_EQ(
+ 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options,
+ sizeof(Options), &Error));
+ }
- LLVMDisposeBuilder(builder);
+ void buildAndRunPasses() {
+ LLVMPassManagerRef pass = LLVMCreatePassManager();
+ LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass);
+ LLVMAddConstantPropagationPass(pass);
+ LLVMAddInstructionCombiningPass(pass);
+ LLVMRunPassManager(pass, Module);
+ LLVMDisposePassManager(pass);
+ }
- LLVMMCJITCompilerOptions options;
- LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
- options.OptLevel = 2;
+ LLVMModuleRef Module;
+ LLVMValueRef Function;
+ LLVMMCJITCompilerOptions Options;
+ LLVMExecutionEngineRef Engine;
+ char *Error;
+};
+} // end anonymous namespace
+
+TEST_F(MCJITCAPITest, simple_function) {
+ SKIP_UNSUPPORTED_PLATFORM;
- // Just ensure that this field still exists.
- options.NoFramePointerElim = false;
+ buildSimpleFunction();
+ buildMCJITOptions();
+ buildMCJITEngine();
+ buildAndRunPasses();
- LLVMExecutionEngineRef engine;
- ASSERT_EQ(
- 0, LLVMCreateMCJITCompilerForModule(&engine, module, &options,
- sizeof(options), &error));
+ union {
+ void *raw;
+ int (*usable)();
+ } functionPointer;
+ functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
- LLVMPassManagerRef pass = LLVMCreatePassManager();
- LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass);
- LLVMAddConstantPropagationPass(pass);
- LLVMAddInstructionCombiningPass(pass);
- LLVMRunPassManager(pass, module);
- LLVMDisposePassManager(pass);
+ EXPECT_EQ(42, functionPointer.usable());
+}
+
+TEST_F(MCJITCAPITest, custom_memory_manager) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ buildSimpleFunction();
+ buildMCJITOptions();
+ useRoundTripSectionMemoryManager();
+ buildMCJITEngine();
+ buildAndRunPasses();
union {
void *raw;
int (*usable)();
} functionPointer;
- functionPointer.raw = LLVMGetPointerToGlobal(engine, function);
+ functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
EXPECT_EQ(42, functionPointer.usable());
-
- LLVMDisposeExecutionEngine(engine);
+ EXPECT_TRUE(didCallAllocateCodeSection);
}
-
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp
index ab09acad0d3b6..c24346de84eee 100644
--- a/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp
+++ b/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp
@@ -1,172 +1,172 @@
-//===- MCJITMemoryManagerTest.cpp - Unit tests for the JIT memory manager -===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ExecutionEngine/SectionMemoryManager.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ExecutionEngine/JIT.h"
-#include "gtest/gtest.h"
-
-using namespace llvm;
-
-namespace {
-
-TEST(MCJITMemoryManagerTest, BasicAllocations) {
- OwningPtr<SectionMemoryManager> MemMgr(new SectionMemoryManager());
-
- uint8_t *code1 = MemMgr->allocateCodeSection(256, 0, 1);
- uint8_t *data1 = MemMgr->allocateDataSection(256, 0, 2, true);
- uint8_t *code2 = MemMgr->allocateCodeSection(256, 0, 3);
- uint8_t *data2 = MemMgr->allocateDataSection(256, 0, 4, false);
-
- EXPECT_NE((uint8_t*)0, code1);
- EXPECT_NE((uint8_t*)0, code2);
- EXPECT_NE((uint8_t*)0, data1);
- EXPECT_NE((uint8_t*)0, data2);
-
- // Initialize the data
- for (unsigned i = 0; i < 256; ++i) {
- code1[i] = 1;
- code2[i] = 2;
- data1[i] = 3;
- data2[i] = 4;
- }
-
- // Verify the data (this is checking for overlaps in the addresses)
- for (unsigned i = 0; i < 256; ++i) {
- EXPECT_EQ(1, code1[i]);
- EXPECT_EQ(2, code2[i]);
- EXPECT_EQ(3, data1[i]);
- EXPECT_EQ(4, data2[i]);
- }
-
- std::string Error;
- EXPECT_FALSE(MemMgr->applyPermissions(&Error));
-}
-
-TEST(MCJITMemoryManagerTest, LargeAllocations) {
- OwningPtr<SectionMemoryManager> MemMgr(new SectionMemoryManager());
-
- uint8_t *code1 = MemMgr->allocateCodeSection(0x100000, 0, 1);
- uint8_t *data1 = MemMgr->allocateDataSection(0x100000, 0, 2, true);
- uint8_t *code2 = MemMgr->allocateCodeSection(0x100000, 0, 3);
- uint8_t *data2 = MemMgr->allocateDataSection(0x100000, 0, 4, false);
-
- EXPECT_NE((uint8_t*)0, code1);
- EXPECT_NE((uint8_t*)0, code2);
- EXPECT_NE((uint8_t*)0, data1);
- EXPECT_NE((uint8_t*)0, data2);
-
- // Initialize the data
- for (unsigned i = 0; i < 0x100000; ++i) {
- code1[i] = 1;
- code2[i] = 2;
- data1[i] = 3;
- data2[i] = 4;
- }
-
- // Verify the data (this is checking for overlaps in the addresses)
- for (unsigned i = 0; i < 0x100000; ++i) {
- EXPECT_EQ(1, code1[i]);
- EXPECT_EQ(2, code2[i]);
- EXPECT_EQ(3, data1[i]);
- EXPECT_EQ(4, data2[i]);
- }
-
- std::string Error;
- EXPECT_FALSE(MemMgr->applyPermissions(&Error));
-}
-
-TEST(MCJITMemoryManagerTest, ManyAllocations) {
- OwningPtr<SectionMemoryManager> MemMgr(new SectionMemoryManager());
-
- uint8_t* code[10000];
- uint8_t* data[10000];
-
- for (unsigned i = 0; i < 10000; ++i) {
- const bool isReadOnly = i % 2 == 0;
-
- code[i] = MemMgr->allocateCodeSection(32, 0, 1);
- data[i] = MemMgr->allocateDataSection(32, 0, 2, isReadOnly);
-
- for (unsigned j = 0; j < 32; j++) {
- code[i][j] = 1 + (i % 254);
- data[i][j] = 2 + (i % 254);
- }
-
- EXPECT_NE((uint8_t *)0, code[i]);
- EXPECT_NE((uint8_t *)0, data[i]);
- }
-
- // Verify the data (this is checking for overlaps in the addresses)
- for (unsigned i = 0; i < 10000; ++i) {
- for (unsigned j = 0; j < 32;j++ ) {
- uint8_t ExpectedCode = 1 + (i % 254);
- uint8_t ExpectedData = 2 + (i % 254);
- EXPECT_EQ(ExpectedCode, code[i][j]);
- EXPECT_EQ(ExpectedData, data[i][j]);
- }
- }
-
- std::string Error;
- EXPECT_FALSE(MemMgr->applyPermissions(&Error));
-}
-
-TEST(MCJITMemoryManagerTest, ManyVariedAllocations) {
- OwningPtr<SectionMemoryManager> MemMgr(new SectionMemoryManager());
-
- uint8_t* code[10000];
- uint8_t* data[10000];
-
- for (unsigned i = 0; i < 10000; ++i) {
- uintptr_t CodeSize = i % 16 + 1;
- uintptr_t DataSize = i % 8 + 1;
-
- bool isReadOnly = i % 3 == 0;
- unsigned Align = 8 << (i % 4);
-
- code[i] = MemMgr->allocateCodeSection(CodeSize, Align, i);
- data[i] = MemMgr->allocateDataSection(DataSize, Align, i + 10000,
- isReadOnly);
-
- for (unsigned j = 0; j < CodeSize; j++) {
- code[i][j] = 1 + (i % 254);
- }
-
- for (unsigned j = 0; j < DataSize; j++) {
- data[i][j] = 2 + (i % 254);
- }
-
- EXPECT_NE((uint8_t *)0, code[i]);
- EXPECT_NE((uint8_t *)0, data[i]);
-
- uintptr_t CodeAlign = Align ? (uintptr_t)code[i] % Align : 0;
- uintptr_t DataAlign = Align ? (uintptr_t)data[i] % Align : 0;
-
- EXPECT_EQ((uintptr_t)0, CodeAlign);
- EXPECT_EQ((uintptr_t)0, DataAlign);
- }
-
- for (unsigned i = 0; i < 10000; ++i) {
- uintptr_t CodeSize = i % 16 + 1;
- uintptr_t DataSize = i % 8 + 1;
-
- for (unsigned j = 0; j < CodeSize; j++) {
- uint8_t ExpectedCode = 1 + (i % 254);
- EXPECT_EQ(ExpectedCode, code[i][j]);
- }
-
- for (unsigned j = 0; j < DataSize; j++) {
- uint8_t ExpectedData = 2 + (i % 254);
- EXPECT_EQ(ExpectedData, data[i][j]);
- }
- }
-}
-
-} // Namespace
-
+//===- MCJITMemoryManagerTest.cpp - Unit tests for the JIT memory manager -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ExecutionEngine/JIT.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(MCJITMemoryManagerTest, BasicAllocations) {
+ OwningPtr<SectionMemoryManager> MemMgr(new SectionMemoryManager());
+
+ uint8_t *code1 = MemMgr->allocateCodeSection(256, 0, 1, "");
+ uint8_t *data1 = MemMgr->allocateDataSection(256, 0, 2, "", true);
+ uint8_t *code2 = MemMgr->allocateCodeSection(256, 0, 3, "");
+ uint8_t *data2 = MemMgr->allocateDataSection(256, 0, 4, "", false);
+
+ EXPECT_NE((uint8_t*)0, code1);
+ EXPECT_NE((uint8_t*)0, code2);
+ EXPECT_NE((uint8_t*)0, data1);
+ EXPECT_NE((uint8_t*)0, data2);
+
+ // Initialize the data
+ for (unsigned i = 0; i < 256; ++i) {
+ code1[i] = 1;
+ code2[i] = 2;
+ data1[i] = 3;
+ data2[i] = 4;
+ }
+
+ // Verify the data (this is checking for overlaps in the addresses)
+ for (unsigned i = 0; i < 256; ++i) {
+ EXPECT_EQ(1, code1[i]);
+ EXPECT_EQ(2, code2[i]);
+ EXPECT_EQ(3, data1[i]);
+ EXPECT_EQ(4, data2[i]);
+ }
+
+ std::string Error;
+ EXPECT_FALSE(MemMgr->finalizeMemory(&Error));
+}
+
+TEST(MCJITMemoryManagerTest, LargeAllocations) {
+ OwningPtr<SectionMemoryManager> MemMgr(new SectionMemoryManager());
+
+ uint8_t *code1 = MemMgr->allocateCodeSection(0x100000, 0, 1, "");
+ uint8_t *data1 = MemMgr->allocateDataSection(0x100000, 0, 2, "", true);
+ uint8_t *code2 = MemMgr->allocateCodeSection(0x100000, 0, 3, "");
+ uint8_t *data2 = MemMgr->allocateDataSection(0x100000, 0, 4, "", false);
+
+ EXPECT_NE((uint8_t*)0, code1);
+ EXPECT_NE((uint8_t*)0, code2);
+ EXPECT_NE((uint8_t*)0, data1);
+ EXPECT_NE((uint8_t*)0, data2);
+
+ // Initialize the data
+ for (unsigned i = 0; i < 0x100000; ++i) {
+ code1[i] = 1;
+ code2[i] = 2;
+ data1[i] = 3;
+ data2[i] = 4;
+ }
+
+ // Verify the data (this is checking for overlaps in the addresses)
+ for (unsigned i = 0; i < 0x100000; ++i) {
+ EXPECT_EQ(1, code1[i]);
+ EXPECT_EQ(2, code2[i]);
+ EXPECT_EQ(3, data1[i]);
+ EXPECT_EQ(4, data2[i]);
+ }
+
+ std::string Error;
+ EXPECT_FALSE(MemMgr->finalizeMemory(&Error));
+}
+
+TEST(MCJITMemoryManagerTest, ManyAllocations) {
+ OwningPtr<SectionMemoryManager> MemMgr(new SectionMemoryManager());
+
+ uint8_t* code[10000];
+ uint8_t* data[10000];
+
+ for (unsigned i = 0; i < 10000; ++i) {
+ const bool isReadOnly = i % 2 == 0;
+
+ code[i] = MemMgr->allocateCodeSection(32, 0, 1, "");
+ data[i] = MemMgr->allocateDataSection(32, 0, 2, "", isReadOnly);
+
+ for (unsigned j = 0; j < 32; j++) {
+ code[i][j] = 1 + (i % 254);
+ data[i][j] = 2 + (i % 254);
+ }
+
+ EXPECT_NE((uint8_t *)0, code[i]);
+ EXPECT_NE((uint8_t *)0, data[i]);
+ }
+
+ // Verify the data (this is checking for overlaps in the addresses)
+ for (unsigned i = 0; i < 10000; ++i) {
+ for (unsigned j = 0; j < 32;j++ ) {
+ uint8_t ExpectedCode = 1 + (i % 254);
+ uint8_t ExpectedData = 2 + (i % 254);
+ EXPECT_EQ(ExpectedCode, code[i][j]);
+ EXPECT_EQ(ExpectedData, data[i][j]);
+ }
+ }
+
+ std::string Error;
+ EXPECT_FALSE(MemMgr->finalizeMemory(&Error));
+}
+
+TEST(MCJITMemoryManagerTest, ManyVariedAllocations) {
+ OwningPtr<SectionMemoryManager> MemMgr(new SectionMemoryManager());
+
+ uint8_t* code[10000];
+ uint8_t* data[10000];
+
+ for (unsigned i = 0; i < 10000; ++i) {
+ uintptr_t CodeSize = i % 16 + 1;
+ uintptr_t DataSize = i % 8 + 1;
+
+ bool isReadOnly = i % 3 == 0;
+ unsigned Align = 8 << (i % 4);
+
+ code[i] = MemMgr->allocateCodeSection(CodeSize, Align, i, "");
+ data[i] = MemMgr->allocateDataSection(DataSize, Align, i + 10000, "",
+ isReadOnly);
+
+ for (unsigned j = 0; j < CodeSize; j++) {
+ code[i][j] = 1 + (i % 254);
+ }
+
+ for (unsigned j = 0; j < DataSize; j++) {
+ data[i][j] = 2 + (i % 254);
+ }
+
+ EXPECT_NE((uint8_t *)0, code[i]);
+ EXPECT_NE((uint8_t *)0, data[i]);
+
+ uintptr_t CodeAlign = Align ? (uintptr_t)code[i] % Align : 0;
+ uintptr_t DataAlign = Align ? (uintptr_t)data[i] % Align : 0;
+
+ EXPECT_EQ((uintptr_t)0, CodeAlign);
+ EXPECT_EQ((uintptr_t)0, DataAlign);
+ }
+
+ for (unsigned i = 0; i < 10000; ++i) {
+ uintptr_t CodeSize = i % 16 + 1;
+ uintptr_t DataSize = i % 8 + 1;
+
+ for (unsigned j = 0; j < CodeSize; j++) {
+ uint8_t ExpectedCode = 1 + (i % 254);
+ EXPECT_EQ(ExpectedCode, code[i][j]);
+ }
+
+ for (unsigned j = 0; j < DataSize; j++) {
+ uint8_t ExpectedData = 2 + (i % 254);
+ EXPECT_EQ(ExpectedData, data[i][j]);
+ }
+ }
+}
+
+} // Namespace
+
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp
new file mode 100644
index 0000000000000..7c3239ea2598d
--- /dev/null
+++ b/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp
@@ -0,0 +1,395 @@
+//===- MCJITMultipeModuleTest.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 MCJIT for handling multiple modules in a single
+// ExecutionEngine by building multiple modules, making function calls across
+// modules, accessing global variables, etc.
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/MCJIT.h"
+#include "MCJITTestBase.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class MCJITMultipleModuleTest : public testing::Test, public MCJITTestBase {};
+
+// FIXME: ExecutionEngine has no support empty modules
+/*
+TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ createJIT(M.take());
+ // JIT-compile
+ EXPECT_NE(0, TheJIT->getObjectImage())
+ << "Unable to generate executable loaded object image";
+
+ TheJIT->addModule(createEmptyModule("<other module>"));
+ TheJIT->addModule(createEmptyModule("<other other module>"));
+
+ // JIT again
+ EXPECT_NE(0, TheJIT->getObjectImage())
+ << "Unable to generate executable loaded object image";
+}
+*/
+
+// Helper Function to test add operation
+void checkAdd(uint64_t ptr) {
+ ASSERT_TRUE(ptr != 0) << "Unable to get pointer to function.";
+ int (*AddPtr)(int, int) = (int (*)(int, int))ptr;
+ EXPECT_EQ(0, AddPtr(0, 0));
+ EXPECT_EQ(1, AddPtr(1, 0));
+ EXPECT_EQ(3, AddPtr(1, 2));
+ EXPECT_EQ(-5, AddPtr(-2, -3));
+ EXPECT_EQ(30, AddPtr(10, 20));
+ EXPECT_EQ(-30, AddPtr(-10, -20));
+ EXPECT_EQ(-40, AddPtr(-10, -30));
+}
+
+void checkAccumulate(uint64_t ptr) {
+ ASSERT_TRUE(ptr != 0) << "Unable to get pointer to function.";
+ int32_t (*FPtr)(int32_t) = (int32_t (*)(int32_t))(intptr_t)ptr;
+ EXPECT_EQ(0, FPtr(0));
+ EXPECT_EQ(1, FPtr(1));
+ EXPECT_EQ(3, FPtr(2));
+ EXPECT_EQ(6, FPtr(3));
+ EXPECT_EQ(10, FPtr(4));
+ EXPECT_EQ(15, FPtr(5));
+}
+
+// FIXME: ExecutionEngine has no support empty modules
+/*
+TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ createJIT(M.take());
+ // JIT-compile
+ EXPECT_NE(0, TheJIT->getObjectImage())
+ << "Unable to generate executable loaded object image";
+
+ TheJIT->addModule(createEmptyModule("<other module>"));
+ TheJIT->addModule(createEmptyModule("<other other module>"));
+
+ // JIT again
+ EXPECT_NE(0, TheJIT->getObjectImage())
+ << "Unable to generate executable loaded object image";
+}
+*/
+
+// Module A { Function FA },
+// Module B { Function FB },
+// execute FA then FB
+TEST_F(MCJITMultipleModuleTest, two_module_case) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B;
+ Function *FA, *FB;
+ createTwoModuleCase(A, FA, B, FB);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FB->getName().str());
+ checkAdd(ptr);
+}
+
+// Module A { Function FA },
+// Module B { Function FB },
+// execute FB then FA
+TEST_F(MCJITMultipleModuleTest, two_module_reverse_case) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B;
+ Function *FA, *FB;
+ createTwoModuleCase(A, FA, B, FB);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
+ TheJIT->finalizeObject();
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FA->getName().str());
+ checkAdd(ptr);
+}
+
+// Module A { Function FA },
+// Module B { Extern FA, Function FB which calls FA },
+// execute FB then FA
+TEST_F(MCJITMultipleModuleTest, two_module_extern_reverse_case) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B;
+ Function *FA, *FB;
+ createTwoModuleExternCase(A, FA, B, FB);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
+ TheJIT->finalizeObject();
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FA->getName().str());
+ checkAdd(ptr);
+}
+
+// Module A { Function FA },
+// Module B { Extern FA, Function FB which calls FA },
+// execute FA then FB
+TEST_F(MCJITMultipleModuleTest, two_module_extern_case) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B;
+ Function *FA, *FB;
+ createTwoModuleExternCase(A, FA, B, FB);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FB->getName().str());
+ checkAdd(ptr);
+}
+
+// Module A { Function FA1, Function FA2 which calls FA1 },
+// Module B { Extern FA1, Function FB which calls FA1 },
+// execute FB then FA2
+TEST_F(MCJITMultipleModuleTest, two_module_consecutive_call_case) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B;
+ Function *FA1, *FA2, *FB;
+ createTwoModuleExternCase(A, FA1, B, FB);
+ FA2 = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(A.get(), FA1);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str());
+ TheJIT->finalizeObject();
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FA2->getName().str());
+ checkAdd(ptr);
+}
+
+// TODO:
+// Module A { Extern Global GVB, Global Variable GVA, Function FA loads GVB },
+// Module B { Extern Global GVA, Global Variable GVB, Function FB loads GVA },
+
+
+// Module A { Global Variable GVA, Function FA loads GVA },
+// Module B { Global Variable GVB, Function FB loads GVB },
+// execute FB then FA
+TEST_F(MCJITMultipleModuleTest, two_module_global_variables_case) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B;
+ Function *FA, *FB;
+ GlobalVariable *GVA, *GVB;
+ A.reset(createEmptyModule("A"));
+ B.reset(createEmptyModule("B"));
+
+ int32_t initialNum = 7;
+ GVA = insertGlobalInt32(A.get(), "GVA", initialNum);
+ GVB = insertGlobalInt32(B.get(), "GVB", initialNum);
+ FA = startFunction<int32_t(void)>(A.get(), "FA");
+ endFunctionWithRet(FA, Builder.CreateLoad(GVA));
+ FB = startFunction<int32_t(void)>(B.get(), "FB");
+ endFunctionWithRet(FB, Builder.CreateLoad(GVB));
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+
+ uint64_t FBPtr = TheJIT->getFunctionAddress(FB->getName().str());
+ TheJIT->finalizeObject();
+ EXPECT_TRUE(0 != FBPtr);
+ int32_t(*FuncPtr)(void) = (int32_t(*)(void))FBPtr;
+ EXPECT_EQ(initialNum, FuncPtr())
+ << "Invalid value for global returned from JITted function in module B";
+
+ uint64_t FAPtr = TheJIT->getFunctionAddress(FA->getName().str());
+ EXPECT_TRUE(0 != FAPtr);
+ FuncPtr = (int32_t(*)(void))FAPtr;
+ EXPECT_EQ(initialNum, FuncPtr())
+ << "Invalid value for global returned from JITted function in module A";
+}
+
+// Module A { Function FA },
+// Module B { Extern FA, Function FB which calls FA },
+// Module C { Extern FA, Function FC which calls FA },
+// execute FC, FB, FA
+TEST_F(MCJITMultipleModuleTest, three_module_case) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B, C;
+ Function *FA, *FB, *FC;
+ createThreeModuleCase(A, FA, B, FB, C, FC);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+ TheJIT->addModule(C.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str());
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FB->getName().str());
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FA->getName().str());
+ checkAdd(ptr);
+}
+
+// Module A { Function FA },
+// Module B { Extern FA, Function FB which calls FA },
+// Module C { Extern FA, Function FC which calls FA },
+// execute FA, FB, FC
+TEST_F(MCJITMultipleModuleTest, three_module_case_reverse_order) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B, C;
+ Function *FA, *FB, *FC;
+ createThreeModuleCase(A, FA, B, FB, C, FC);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+ TheJIT->addModule(C.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FB->getName().str());
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FC->getName().str());
+ checkAdd(ptr);
+}
+
+// Module A { Function FA },
+// Module B { Extern FA, Function FB which calls FA },
+// Module C { Extern FB, Function FC which calls FB },
+// execute FC, FB, FA
+TEST_F(MCJITMultipleModuleTest, three_module_chain_case) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B, C;
+ Function *FA, *FB, *FC;
+ createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+ TheJIT->addModule(C.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str());
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FB->getName().str());
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FA->getName().str());
+ checkAdd(ptr);
+}
+
+// Module A { Function FA },
+// Module B { Extern FA, Function FB which calls FA },
+// Module C { Extern FB, Function FC which calls FB },
+// execute FA, FB, FC
+TEST_F(MCJITMultipleModuleTest, three_modules_chain_case_reverse_order) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B, C;
+ Function *FA, *FB, *FC;
+ createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+ TheJIT->addModule(C.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FB->getName().str());
+ checkAdd(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FC->getName().str());
+ checkAdd(ptr);
+}
+
+// Module A { Extern FB, Function FA which calls FB1 },
+// Module B { Extern FA, Function FB1, Function FB2 which calls FA },
+// execute FA, then FB1
+// FIXME: this test case is not supported by MCJIT
+TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B;
+ Function *FA, *FB1, *FB2;
+ createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str());
+ checkAccumulate(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FB1->getName().str());
+ checkAccumulate(ptr);
+}
+
+// Module A { Extern FB, Function FA which calls FB1 },
+// Module B { Extern FA, Function FB1, Function FB2 which calls FA },
+// execute FB1 then FA
+// FIXME: this test case is not supported by MCJIT
+TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case_reverse_order) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B;
+ Function *FA, *FB1, *FB2;
+ createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
+ checkAccumulate(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FA->getName().str());
+ checkAccumulate(ptr);
+}
+
+// Module A { Extern FB1, Function FA which calls FB1 },
+// Module B { Extern FA, Function FB1, Function FB2 which calls FA },
+// execute FB1 then FB2
+// FIXME: this test case is not supported by MCJIT
+TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case3) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ OwningPtr<Module> A, B;
+ Function *FA, *FB1, *FB2;
+ createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
+
+ createJIT(A.take());
+ TheJIT->addModule(B.take());
+
+ uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
+ checkAccumulate(ptr);
+
+ ptr = TheJIT->getFunctionAddress(FB2->getName().str());
+ checkAccumulate(ptr);
+}
+}
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp
index 0061e30e7a541..7073a5265d62c 100644
--- a/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp
+++ b/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp
@@ -28,7 +28,7 @@ public:
virtual ~TestObjectCache() {
// Free any buffers we've allocated.
- SmallVector<MemoryBuffer *, 2>::iterator it, end;
+ SmallVectorImpl<MemoryBuffer *>::iterator it, end;
end = AllocatedBuffers.end();
for (it = AllocatedBuffers.begin(); it != end; ++it) {
delete *it;
@@ -45,6 +45,16 @@ public:
ObjMap[ModuleID] = copyBuffer(Obj);
}
+ virtual MemoryBuffer* getObject(const Module* M) {
+ const MemoryBuffer* BufferFound = getObjectInternal(M);
+ ModulesLookedUp.insert(M->getModuleIdentifier());
+ if (!BufferFound)
+ return NULL;
+ // Our test cache wants to maintain ownership of its object buffers
+ // so we make a copy here for the execution engine.
+ return MemoryBuffer::getMemBufferCopy(BufferFound->getBuffer());
+ }
+
// Test-harness-specific functions
bool wereDuplicatesInserted() { return DuplicateInserted; }
@@ -62,13 +72,6 @@ public:
return it->second;
}
-protected:
- virtual const MemoryBuffer* getObject(const Module* M) {
- const MemoryBuffer* BufferFound = getObjectInternal(M);
- ModulesLookedUp.insert(M->getModuleIdentifier());
- return BufferFound;
- }
-
private:
MemoryBuffer *copyBuffer(const MemoryBuffer *Buf) {
// Create a local copy of the buffer.
@@ -98,14 +101,13 @@ protected:
void compileAndRun(int ExpectedRC = OriginalRC) {
// This function shouldn't be called until after SetUp.
- ASSERT_TRUE(0 != TheJIT);
+ ASSERT_TRUE(TheJIT.isValid());
ASSERT_TRUE(0 != Main);
+ // We may be using a null cache, so ensure compilation is valid.
TheJIT->finalizeObject();
void *vPtr = TheJIT->getPointerToFunction(Main);
- static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache();
-
EXPECT_TRUE(0 != vPtr)
<< "Unable to get pointer to main() from JIT";
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp
index e9cf904b1813f..fab81551fa5eb 100644
--- a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp
+++ b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp
@@ -18,19 +18,24 @@
using namespace llvm;
+namespace {
+
class MCJITTest : public testing::Test, public MCJITTestBase {
protected:
-
- virtual void SetUp() {
- M.reset(createEmptyModule("<main>"));
- }
+ virtual void SetUp() { M.reset(createEmptyModule("<main>")); }
};
-namespace {
+// FIXME: Ensure creating an execution engine does not crash when constructed
+// with a null module.
+/*
+TEST_F(MCJITTest, null_module) {
+ createJIT(0);
+}
+*/
// FIXME: In order to JIT an empty module, there needs to be
// an interface to ExecutionEngine that forces compilation but
-// does require retrieval of a pointer to a function/global.
+// does not require retrieval of a pointer to a function/global.
/*
TEST_F(MCJITTest, empty_module) {
createJIT(M.take());
@@ -46,8 +51,6 @@ TEST_F(MCJITTest, global_variable) {
GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue);
createJIT(M.take());
void *globalPtr = TheJIT->getPointerToGlobal(Global);
- MM->applyPermissions();
- static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache();
EXPECT_TRUE(0 != globalPtr)
<< "Unable to get pointer to global value from JIT";
@@ -60,16 +63,19 @@ TEST_F(MCJITTest, add_function) {
Function *F = insertAddFunction(M.get());
createJIT(M.take());
- void *addPtr = TheJIT->getPointerToFunction(F);
- MM->applyPermissions();
- static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache();
+ uint64_t addPtr = TheJIT->getFunctionAddress(F->getName().str());
EXPECT_TRUE(0 != addPtr)
<< "Unable to get pointer to function from JIT";
- int (*AddPtrTy)(int, int) = (int(*)(int, int))(intptr_t)addPtr;
- EXPECT_EQ(0, AddPtrTy(0, 0));
- EXPECT_EQ(3, AddPtrTy(1, 2));
- EXPECT_EQ(-5, AddPtrTy(-2, -3));
+ ASSERT_TRUE(addPtr != 0) << "Unable to get pointer to function .";
+ int (*AddPtr)(int, int) = (int(*)(int, int))addPtr ;
+ EXPECT_EQ(0, AddPtr(0, 0));
+ EXPECT_EQ(1, AddPtr(1, 0));
+ EXPECT_EQ(3, AddPtr(1, 2));
+ EXPECT_EQ(-5, AddPtr(-2, -3));
+ EXPECT_EQ(30, AddPtr(10, 20));
+ EXPECT_EQ(-30, AddPtr(-10, -20));
+ EXPECT_EQ(-40, AddPtr(-10, -30));
}
TEST_F(MCJITTest, run_main) {
@@ -78,13 +84,11 @@ TEST_F(MCJITTest, run_main) {
int rc = 6;
Function *Main = insertMainFunction(M.get(), 6);
createJIT(M.take());
- void *vPtr = TheJIT->getPointerToFunction(Main);
- MM->applyPermissions();
- static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache();
- EXPECT_TRUE(0 != vPtr)
+ uint64_t ptr = TheJIT->getFunctionAddress(Main->getName().str());
+ EXPECT_TRUE(0 != ptr)
<< "Unable to get pointer to main() from JIT";
- int (*FuncPtr)(void) = (int(*)(void))(intptr_t)vPtr;
+ int (*FuncPtr)(void) = (int(*)(void))ptr;
int returnCode = FuncPtr();
EXPECT_EQ(returnCode, rc);
}
@@ -101,12 +105,10 @@ TEST_F(MCJITTest, return_global) {
endFunctionWithRet(ReturnGlobal, ReadGlobal);
createJIT(M.take());
- void *rgvPtr = TheJIT->getPointerToFunction(ReturnGlobal);
- MM->applyPermissions();
- static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache();
+ uint64_t rgvPtr = TheJIT->getFunctionAddress(ReturnGlobal->getName().str());
EXPECT_TRUE(0 != rgvPtr);
- int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)rgvPtr;
+ int32_t(*FuncPtr)(void) = (int32_t(*)(void))rgvPtr;
EXPECT_EQ(initialNum, FuncPtr())
<< "Invalid value for global returned from JITted function";
}
@@ -136,7 +138,7 @@ TEST_F(MCJITTest, increment_global) {
void *gvPtr = TheJIT->getPointerToGlobal(GV);
EXPECT_EQ(initialNum, *(int32_t*)gvPtr);
- void *vPtr = TheJIT->getPointerToFunction(IncrementGlobal);
+ void *vPtr = TheJIT->getFunctionAddress(IncrementGlobal->getName().str());
EXPECT_TRUE(0 != vPtr)
<< "Unable to get pointer to main() from JIT";
@@ -150,6 +152,9 @@ TEST_F(MCJITTest, increment_global) {
}
*/
+// PR16013: XFAIL this test on ARM, which currently can't handle multiple relocations.
+#if !defined(__arm__)
+
TEST_F(MCJITTest, multiple_functions) {
SKIP_UNSUPPORTED_PLATFORM;
@@ -171,65 +176,15 @@ TEST_F(MCJITTest, multiple_functions) {
}
createJIT(M.take());
- void *vPtr = TheJIT->getPointerToFunction(Outer);
- MM->applyPermissions();
- static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache();
- EXPECT_TRUE(0 != vPtr)
+ uint64_t ptr = TheJIT->getFunctionAddress(Outer->getName().str());
+ EXPECT_TRUE(0 != ptr)
<< "Unable to get pointer to outer function from JIT";
- int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)vPtr;
+ int32_t(*FuncPtr)(void) = (int32_t(*)(void))ptr;
EXPECT_EQ(innerRetVal, FuncPtr())
<< "Incorrect result returned from function";
}
-// FIXME: ExecutionEngine has no support empty modules
-/*
-TEST_F(MCJITTest, multiple_empty_modules) {
- SKIP_UNSUPPORTED_PLATFORM;
-
- createJIT(M.take());
- // JIT-compile
- EXPECT_NE(0, TheJIT->getObjectImage())
- << "Unable to generate executable loaded object image";
-
- TheJIT->addModule(createEmptyModule("<other module>"));
- TheJIT->addModule(createEmptyModule("<other other module>"));
-
- // JIT again
- EXPECT_NE(0, TheJIT->getObjectImage())
- << "Unable to generate executable loaded object image";
-}
-*/
-
-// FIXME: MCJIT must support multiple modules
-/*
-TEST_F(MCJITTest, multiple_modules) {
- SKIP_UNSUPPORTED_PLATFORM;
-
- Function *Callee = insertAddFunction(M.get());
- createJIT(M.take());
-
- // caller function is defined in a different module
- M.reset(createEmptyModule("<caller module>"));
-
- Function *CalleeRef = insertExternalReferenceToFunction(M.get(), Callee);
- Function *Caller = insertSimpleCallFunction(M.get(), CalleeRef);
-
- TheJIT->addModule(M.take());
-
- // get a function pointer in a module that was not used in EE construction
- void *vPtr = TheJIT->getPointerToFunction(Caller);
- EXPECT_NE(0, vPtr)
- << "Unable to get pointer to caller function from JIT";
-
- int(*FuncPtr)(int, int) = (int(*)(int, int))(intptr_t)vPtr;
- EXPECT_EQ(0, FuncPtr(0, 0));
- EXPECT_EQ(30, FuncPtr(10, 20));
- EXPECT_EQ(-30, FuncPtr(-10, -20));
-
- // ensure caller is destroyed before callee (free use before def)
- M.reset();
-}
-*/
+#endif /*!defined(__arm__)*/
}
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h b/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h
index 8160a186f413b..7b6e39fb23854 100644
--- a/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h
+++ b/unittests/ExecutionEngine/MCJIT/MCJITTestAPICommon.h
@@ -49,11 +49,23 @@ protected:
/// Returns true if the host architecture is known to support MCJIT
bool ArchSupportsMCJIT() {
Triple Host(HostTriple);
+ // If ARCH is not supported, bail
if (std::find(SupportedArchs.begin(), SupportedArchs.end(), Host.getArch())
- == SupportedArchs.end()) {
+ == SupportedArchs.end())
return false;
- }
- return true;
+
+ // If ARCH is supported and has no specific sub-arch support
+ if (std::find(HasSubArchs.begin(), HasSubArchs.end(), Host.getArch())
+ == HasSubArchs.end())
+ return true;
+
+ // If ARCH has sub-arch support, find it
+ SmallVectorImpl<std::string>::const_iterator I = SupportedSubArchs.begin();
+ for(; I != SupportedSubArchs.end(); ++I)
+ if (Host.getArchName().startswith(I->c_str()))
+ return true;
+
+ return false;
}
/// Returns true if the host OS is known to support MCJIT
@@ -68,6 +80,8 @@ protected:
std::string HostTriple;
SmallVector<Triple::ArchType, 4> SupportedArchs;
+ SmallVector<Triple::ArchType, 1> HasSubArchs;
+ SmallVector<std::string, 2> SupportedSubArchs; // We need to own the memory
SmallVector<Triple::OSType, 4> UnsupportedOSs;
};
diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h
index b0e98a88defc1..b42a9c0980db1 100644
--- a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h
+++ b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h
@@ -30,35 +30,19 @@
namespace llvm {
-class MCJITTestBase : public MCJITTestAPICommon {
+/// Helper class that can build very simple Modules
+class TrivialModuleBuilder {
protected:
+ LLVMContext Context;
+ IRBuilder<> Builder;
+ std::string BuilderTriple;
- MCJITTestBase()
- : OptLevel(CodeGenOpt::None)
- , RelocModel(Reloc::Default)
- , CodeModel(CodeModel::Default)
- , MArch("")
- , Builder(Context)
- , MM(new SectionMemoryManager)
- {
- // 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 incompatible with MCJIT as
- // they are copied from the test/ExecutionEngine/MCJIT/lit.local.cfg and
- // should be kept in sync.
- UnsupportedOSs.push_back(Triple::Cygwin);
- UnsupportedOSs.push_back(Triple::Darwin);
- }
+ TrivialModuleBuilder(const std::string &Triple)
+ : Builder(Context), BuilderTriple(Triple) {}
- Module *createEmptyModule(StringRef Name) {
+ Module *createEmptyModule(StringRef Name = StringRef()) {
Module * M = new Module(Name, Context);
- M->setTargetTriple(Triple::normalize(HostTriple));
+ M->setTargetTriple(Triple::normalize(BuilderTriple));
return M;
}
@@ -135,12 +119,13 @@ protected:
// Inserts an declaration to a function defined elsewhere
Function *insertExternalReferenceToFunction(Module *M, Function *Func) {
Function *Result = Function::Create(Func->getFunctionType(),
- GlobalValue::AvailableExternallyLinkage,
+ GlobalValue::ExternalLinkage,
Func->getName(), M);
return Result;
}
// Inserts a global variable of type int32
+ // FIXME: make this a template function to support any type
GlobalVariable *insertGlobalInt32(Module *M,
StringRef name,
int32_t InitialValue) {
@@ -155,6 +140,179 @@ protected:
return Global;
}
+ // Inserts a function
+ // int32_t recursive_add(int32_t num) {
+ // if (num == 0) {
+ // return num;
+ // } else {
+ // int32_t recursive_param = num - 1;
+ // return num + Helper(recursive_param);
+ // }
+ // }
+ // NOTE: if Helper is left as the default parameter, Helper == recursive_add.
+ Function *insertAccumulateFunction(Module *M,
+ Function *Helper = 0,
+ StringRef Name = "accumulate") {
+ Function *Result = startFunction<int32_t(int32_t)>(M, Name);
+ if (Helper == 0)
+ Helper = Result;
+
+ BasicBlock *BaseCase = BasicBlock::Create(Context, "", Result);
+ BasicBlock *RecursiveCase = BasicBlock::Create(Context, "", Result);
+
+ // if (num == 0)
+ Value *Param = Result->arg_begin();
+ Value *Zero = ConstantInt::get(Context, APInt(32, 0));
+ Builder.CreateCondBr(Builder.CreateICmpEQ(Param, Zero),
+ BaseCase, RecursiveCase);
+
+ // return num;
+ Builder.SetInsertPoint(BaseCase);
+ Builder.CreateRet(Param);
+
+ // int32_t recursive_param = num - 1;
+ // return Helper(recursive_param);
+ Builder.SetInsertPoint(RecursiveCase);
+ Value *One = ConstantInt::get(Context, APInt(32, 1));
+ Value *RecursiveParam = Builder.CreateSub(Param, One);
+ Value *RecursiveReturn = Builder.CreateCall(Helper, RecursiveParam);
+ Value *Accumulator = Builder.CreateAdd(Param, RecursiveReturn);
+ Builder.CreateRet(Accumulator);
+
+ return Result;
+ }
+
+ // Populates Modules A and B:
+ // Module A { Extern FB1, Function FA which calls FB1 },
+ // Module B { Extern FA, Function FB1, Function FB2 which calls FA },
+ void createCrossModuleRecursiveCase(OwningPtr<Module> &A,
+ Function *&FA,
+ OwningPtr<Module> &B,
+ Function *&FB1,
+ Function *&FB2) {
+ // Define FB1 in B.
+ B.reset(createEmptyModule("B"));
+ FB1 = insertAccumulateFunction(B.get(), 0, "FB1");
+
+ // Declare FB1 in A (as an external).
+ A.reset(createEmptyModule("A"));
+ Function *FB1Extern = insertExternalReferenceToFunction(A.get(), FB1);
+
+ // Define FA in A (with a call to FB1).
+ FA = insertAccumulateFunction(A.get(), FB1Extern, "FA");
+
+ // Declare FA in B (as an external)
+ Function *FAExtern = insertExternalReferenceToFunction(B.get(), FA);
+
+ // Define FB2 in B (with a call to FA)
+ FB2 = insertAccumulateFunction(B.get(), FAExtern, "FB2");
+ }
+
+ // Module A { Function FA },
+ // Module B { Extern FA, Function FB which calls FA },
+ // Module C { Extern FB, Function FC which calls FB },
+ void createThreeModuleChainedCallsCase(OwningPtr<Module> &A,
+ Function *&FA,
+ OwningPtr<Module> &B,
+ Function *&FB,
+ OwningPtr<Module> &C,
+ Function *&FC) {
+ A.reset(createEmptyModule("A"));
+ FA = insertAddFunction(A.get());
+
+ B.reset(createEmptyModule("B"));
+ Function *FAExtern_in_B = insertExternalReferenceToFunction(B.get(), FA);
+ FB = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(B.get(), FAExtern_in_B);
+
+ C.reset(createEmptyModule("C"));
+ Function *FBExtern_in_C = insertExternalReferenceToFunction(C.get(), FB);
+ FC = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(C.get(), FBExtern_in_C);
+ }
+
+
+ // Module A { Function FA },
+ // Populates Modules A and B:
+ // Module B { Function FB }
+ void createTwoModuleCase(OwningPtr<Module> &A, Function *&FA,
+ OwningPtr<Module> &B, Function *&FB) {
+ A.reset(createEmptyModule("A"));
+ FA = insertAddFunction(A.get());
+
+ B.reset(createEmptyModule("B"));
+ FB = insertAddFunction(B.get());
+ }
+
+ // Module A { Function FA },
+ // Module B { Extern FA, Function FB which calls FA }
+ void createTwoModuleExternCase(OwningPtr<Module> &A, Function *&FA,
+ OwningPtr<Module> &B, Function *&FB) {
+ A.reset(createEmptyModule("A"));
+ FA = insertAddFunction(A.get());
+
+ B.reset(createEmptyModule("B"));
+ Function *FAExtern_in_B = insertExternalReferenceToFunction(B.get(), FA);
+ FB = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(B.get(),
+ FAExtern_in_B);
+ }
+
+ // Module A { Function FA },
+ // Module B { Extern FA, Function FB which calls FA },
+ // Module C { Extern FB, Function FC which calls FA },
+ void createThreeModuleCase(OwningPtr<Module> &A,
+ Function *&FA,
+ OwningPtr<Module> &B,
+ Function *&FB,
+ OwningPtr<Module> &C,
+ Function *&FC) {
+ A.reset(createEmptyModule("A"));
+ FA = insertAddFunction(A.get());
+
+ B.reset(createEmptyModule("B"));
+ Function *FAExtern_in_B = insertExternalReferenceToFunction(B.get(), FA);
+ FB = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(B.get(), FAExtern_in_B);
+
+ C.reset(createEmptyModule("C"));
+ Function *FAExtern_in_C = insertExternalReferenceToFunction(C.get(), FA);
+ FC = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(C.get(), FAExtern_in_C);
+ }
+};
+
+
+class MCJITTestBase : public MCJITTestAPICommon, public TrivialModuleBuilder {
+protected:
+
+ MCJITTestBase()
+ : TrivialModuleBuilder(HostTriple)
+ , OptLevel(CodeGenOpt::None)
+ , RelocModel(Reloc::Default)
+ , CodeModel(CodeModel::Default)
+ , MArch("")
+ , MM(new SectionMemoryManager)
+ {
+ // 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::aarch64);
+ SupportedArchs.push_back(Triple::arm);
+ SupportedArchs.push_back(Triple::mips);
+ SupportedArchs.push_back(Triple::mipsel);
+ SupportedArchs.push_back(Triple::x86);
+ SupportedArchs.push_back(Triple::x86_64);
+
+ // Some architectures have sub-architectures in which tests will fail, like
+ // ARM. These two vectors will define if they do have sub-archs (to avoid
+ // extra work for those who don't), and if so, if they are listed to work
+ HasSubArchs.push_back(Triple::arm);
+ SupportedSubArchs.push_back("armv6");
+ SupportedSubArchs.push_back("armv7");
+
+ // The operating systems below are known to be incompatible with MCJIT as
+ // they are copied from the test/ExecutionEngine/MCJIT/lit.local.cfg and
+ // should be kept in sync.
+ UnsupportedOSs.push_back(Triple::Cygwin);
+ UnsupportedOSs.push_back(Triple::Darwin);
+ }
+
void createJIT(Module *M) {
// Due to the EngineBuilder constructor, it is required to have a Module
@@ -165,7 +323,7 @@ protected:
std::string Error;
TheJIT.reset(EB.setEngineKind(EngineKind::JIT)
.setUseMCJIT(true) /* can this be folded into the EngineKind enum? */
- .setJITMemoryManager(MM)
+ .setMCJITMemoryManager(MM)
.setErrorStr(&Error)
.setOptLevel(CodeGenOpt::None)
.setAllocateGVsWithCode(false) /*does this do anything?*/
@@ -179,16 +337,13 @@ protected:
assert(TheJIT.get() != NULL && "error creating MCJIT with EngineBuilder");
}
- LLVMContext Context;
CodeGenOpt::Level OptLevel;
Reloc::Model RelocModel;
CodeModel::Model CodeModel;
StringRef MArch;
SmallVector<std::string, 1> MAttrs;
- OwningPtr<TargetMachine> TM;
OwningPtr<ExecutionEngine> TheJIT;
- IRBuilder<> Builder;
- JITMemoryManager *MM;
+ RTDyldMemoryManager *MM;
OwningPtr<Module> M;
};
diff --git a/unittests/ExecutionEngine/MCJIT/Makefile b/unittests/ExecutionEngine/MCJIT/Makefile
index 454f83099d4b4..33b043be9ebd0 100644
--- a/unittests/ExecutionEngine/MCJIT/Makefile
+++ b/unittests/ExecutionEngine/MCJIT/Makefile
@@ -9,7 +9,7 @@
LEVEL = ../../..
TESTNAME = MCJIT
-LINK_COMPONENTS := core jit mcjit native support
+LINK_COMPONENTS := core mcjit native support
include $(LEVEL)/Makefile.config
include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest