Index: unittests/ExecutionEngine/MCJIT/CMakeLists.txt =================================================================== --- unittests/ExecutionEngine/MCJIT/CMakeLists.txt +++ unittests/ExecutionEngine/MCJIT/CMakeLists.txt @@ -11,6 +11,7 @@ MCJITTest.cpp MCJITCAPITest.cpp MCJITMemoryManagerTest.cpp + MCJITMultipleModuleTest.cpp MCJITObjectCacheTest.cpp ) Index: unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp =================================================================== --- /dev/null +++ unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp @@ -0,0 +1,284 @@ +//===- 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 basic MCJIT functionality such as making function +// calls, using global variables, and compiling multpile modules. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/MCJIT.h" +#include "MCJITTestBase.h" +#include "gtest/gtest.h" + +using namespace llvm; + +class MCJITMultipleModuleTest : public testing::Test, public MCJITTestBase { +protected: + + // virtual void SetUp() { + // M.reset(createEmptyModule("
")); + // } +}; + +namespace { + +// FIXME: In order to JIT an empty module, there needs to be +// an interface to ExecutionEngine that forces compilation but +// does not require retrieval of a pointer to a function/global. +/* +TEST_F(MCJITMultipleModuleTest, empty_module) { + createJIT(M.take()); + TheJIT->finalizeObject(); + //EXPECT_NE(0, TheJIT->getObjectImage()) + // << "Unable to generate executable loaded object image"; +} +*/ + +// 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("")); + TheJIT->addModule(createEmptyModule("")); + + // JIT again + EXPECT_NE(0, TheJIT->getObjectImage()) + << "Unable to generate executable loaded object image"; +} +*/ +TEST_F(MCJITMultipleModuleTest, test1) { + SKIP_UNSUPPORTED_PLATFORM; + + Function *FA = insertDummyFunction(M.get()); + createJIT(M.take()); + void *fAPtr = TheJIT->getPointerToFunction(FA); + + // caller function is defined in a different module + M.reset(createEmptyModule("")); + + Function *FB = insertDummyFunction(M.get()); + TheJIT->addModule(M.take()); + void *fBPtr = TheJIT->getPointerToFunction(FB); + + TheJIT->finalizeObject(); + EXPECT_TRUE(0 != fAPtr) + << "Unable to get pointer to function in module A from JIT"; + EXPECT_TRUE(0 != fBPtr) + << "Unable to get pointer to function in module B from JIT"; + + int (*fAPtrTy)(int) = (int(*)(int))(intptr_t)fAPtr; + int (*fBPtrTy)(int) = (int(*)(int))(intptr_t)fBPtr; + EXPECT_EQ(0, fAPtrTy(0)); + EXPECT_EQ(0, fBPtrTy(0)); + EXPECT_EQ(1, fAPtrTy(1)); + EXPECT_EQ(1, fBPtrTy(1)); + EXPECT_EQ(-2, fAPtrTy(-2)); + EXPECT_EQ(-2, fBPtrTy(-2)); +} + +TEST_F(MCJITMultipleModuleTest, test2) { + SKIP_UNSUPPORTED_PLATFORM; + + Function *FA = insertDummyFunction(M.get()); + createJIT(M.take()); + void *fAPtr = TheJIT->getPointerToFunction(FA); + + // caller function is defined in a different module + M.reset(createEmptyModule("")); + + Function *FB = insertDummyFunction(M.get()); + TheJIT->addModule(M.take()); + void *fBPtr = TheJIT->getPointerToFunction(FB); + + TheJIT->finalizeObject(); + EXPECT_TRUE(0 != fAPtr) + << "Unable to get pointer to function in module A from JIT"; + EXPECT_TRUE(0 != fBPtr) + << "Unable to get pointer to function in module B from JIT"; + + int (*fAPtrTy)(int) = (int(*)(int))(intptr_t)fAPtr; + int (*fBPtrTy)(int) = (int(*)(int))(intptr_t)fBPtr; + EXPECT_EQ(0, fBPtrTy(0)); + EXPECT_EQ(0, fAPtrTy(0)); + EXPECT_EQ(1, fBPtrTy(1)); + EXPECT_EQ(1, fAPtrTy(1)); + EXPECT_EQ(-2, fBPtrTy(-2)); + EXPECT_EQ(-2, fAPtrTy(-2)); +} + + +// FIXME: MCJIT must support multiple modules +TEST_F(MCJITMultipleModuleTest, test3) { + SKIP_UNSUPPORTED_PLATFORM; + + Function *FA = insertAddFunction(M.get()); + createJIT(M.take()); + + // caller function is defined in a different module + M.reset(createEmptyModule("")); + + Function *EFA = insertExternalReferenceToFunction(M.get(), FA); + Function *FB = insertSimpleCallFunction(M.get(), EFA); + + // FIXME: The fact that I need this pointer probably indicates that the finalizeModule interface is bad. + Module *SaveM = M.get(); + TheJIT->addModule(M.take()); + + // get a function pointer in a module that was not used in EE construction + void *fBPtr = TheJIT->getPointerToFunction(FB); + TheJIT->finalizeModule(SaveM); + EXPECT_TRUE(0 != fBPtr) + << "Unable to get pointer to caller function module B from JIT"; + void *fAPtr = TheJIT->getPointerToFunction(FA); + EXPECT_TRUE(0 != fAPtr) + << "Unable to get pointer to callee function in module A from JIT"; + + int (*fAPtrTy)(int, int) = (int(*)(int, int))(intptr_t)fAPtr; + int (*fBPtrTy)(int, int) = (int(*)(int, int))(intptr_t)fBPtr; + EXPECT_EQ(0, fBPtrTy(0, 0)); + EXPECT_EQ(0, fAPtrTy(0, 0)); + EXPECT_EQ(30, fBPtrTy(10, 20)); + EXPECT_EQ(30, fAPtrTy(10, 20)); + EXPECT_EQ(-30, fBPtrTy(-10, -20)); + EXPECT_EQ(-30, fAPtrTy(-10, -20)); + + // ensure caller is destroyed before callee (free use before def) + M.reset(); +} + +TEST_F(MCJITMultipleModuleTest, test4) { + SKIP_UNSUPPORTED_PLATFORM; + + Function *FA = insertAddFunction(M.get()); + createJIT(M.take()); + + // caller function is defined in a different module + M.reset(createEmptyModule("")); + + Function *EFA = insertExternalReferenceToFunction(M.get(), FA); + Function *FB = insertSimpleCallFunction(M.get(), EFA); + + Module *SaveM = M.get(); + TheJIT->addModule(M.take()); + + // get a function pointer in a module that was not used in EE construction + void *fBPtr = TheJIT->getPointerToFunction(FB); + TheJIT->finalizeModule(SaveM); + EXPECT_TRUE(0 != fBPtr) + << "Unable to get pointer to caller function module B from JIT"; + void *fAPtr = TheJIT->getPointerToFunction(FA); + EXPECT_TRUE(0 != fAPtr) + << "Unable to get pointer to callee function in module A from JIT"; + + int (*fAPtrTy)(int, int) = (int(*)(int, int))(intptr_t)fAPtr; + int (*fBPtrTy)(int, int) = (int(*)(int, int))(intptr_t)fBPtr; + + EXPECT_EQ(0, fAPtrTy(0, 0)); + EXPECT_EQ(0, fBPtrTy(0, 0)); + EXPECT_EQ(30, fAPtrTy(10, 20)); + EXPECT_EQ(30, fBPtrTy(10, 20)); + EXPECT_EQ(-30, fAPtrTy(-10, -20)); + EXPECT_EQ(-30, fBPtrTy(-10, -20)); + +} + +TEST_F(MCJITMultipleModuleTest, test5) { + SKIP_UNSUPPORTED_PLATFORM; + + Function *FA1 = insertAddFunction(M.get()); + Function *FA2 = insertSimpleCallFunction(M.get(), FA1); + createJIT(M.take()); + + // caller function is defined in a different module + M.reset(createEmptyModule("")); + + Function *EFA1 = insertExternalReferenceToFunction(M.get(), FA1); + Function *FB = insertSimpleCallFunction(M.get(), EFA1); + + Module *SaveM = M.get(); + TheJIT->addModule(M.take()); + + // get a function pointer in a module that was not used in EE construction + void *fBPtr = TheJIT->getPointerToFunction(FB); + TheJIT->finalizeModule(SaveM); + EXPECT_TRUE(0 != fBPtr) + << "Unable to get pointer to caller function module B from JIT"; + void *fA2Ptr = TheJIT->getPointerToFunction(FA2); + EXPECT_TRUE(0 != fA2Ptr) + << "Unable to get pointer to caller function in module A from JIT"; + + int (*fA2PtrTy)(int, int) = (int(*)(int, int))(intptr_t)fA2Ptr; + int (*fBPtrTy)(int, int) = (int(*)(int, int))(intptr_t)fBPtr; + + EXPECT_EQ(0, fBPtrTy(0, 0)); + EXPECT_EQ(0, fA2PtrTy(0, 0)); + EXPECT_EQ(30, fBPtrTy(10, 20)); + EXPECT_EQ(30, fA2PtrTy(10, 20)); + EXPECT_EQ(-30, fBPtrTy(-10, -20)); + EXPECT_EQ(-30, fA2PtrTy(-10, -20)); + +} + +TEST_F(MCJITMultipleModuleTest, test6) { + SKIP_UNSUPPORTED_PLATFORM; + + Function *FA = insertAddFunction(M.get()); + createJIT(M.take()); + + void *fAPtr = TheJIT->getPointerToFunction(FA); + EXPECT_TRUE(0 != fAPtr) + << "Unable to get pointer to callee function in module A from JIT"; + + // caller function is defined in a different module + M.reset(createEmptyModule("")); + + Function *EFA = insertExternalReferenceToFunction(M.get(), FA); + Function *FB = insertSimpleCallFunction(M.get(), EFA); + + Module *SaveM = M.get(); + TheJIT->addModule(M.take()); + + void *fBPtr = TheJIT->getPointerToFunction(FB); + TheJIT->finalizeModule(SaveM); + EXPECT_TRUE(0 != fBPtr) + << "Unable to get pointer to caller function module B from JIT"; + + // caller function is defined in a different module + M.reset(createEmptyModule("")); + Function *FC = insertSimpleCallFunction(M.get(), EFA); + + SaveM = M.get(); + TheJIT->addModule(M.take()); + + void *fCPtr = TheJIT->getPointerToFunction(FC); + TheJIT->finalizeModule(SaveM); + EXPECT_TRUE(0 != fCPtr) + << "Unable to get pointer to caller function module C from JIT"; + + int (*fAPtrTy)(int, int) = (int(*)(int, int))(intptr_t)fAPtr; + int (*fBPtrTy)(int, int) = (int(*)(int, int))(intptr_t)fBPtr; + int (*fCPtrTy)(int, int) = (int(*)(int, int))(intptr_t)fCPtr; + + EXPECT_EQ(0, fCPtrTy(0, 0)); + EXPECT_EQ(0, fBPtrTy(0, 0)); + EXPECT_EQ(0, fAPtrTy(0, 0)); + EXPECT_EQ(30, fCPtrTy(10, 20)); + EXPECT_EQ(30, fAPtrTy(10, 20)); + EXPECT_EQ(-30, fCPtrTy(-10, -20)); + EXPECT_EQ(-30, fBPtrTy(-10, -20)); + EXPECT_EQ(-30, fAPtrTy(-10, -20)); +} + +} Index: unittests/ExecutionEngine/MCJIT/MCJITTestBase.h =================================================================== --- unittests/ExecutionEngine/MCJIT/MCJITTestBase.h +++ unittests/ExecutionEngine/MCJIT/MCJITTestBase.h @@ -92,6 +92,17 @@ } // Inserts a function + // int32_t dummy(int32_t a) { return a; } + // in the current module and returns a pointer to it. + Function *insertDummyFunction(Module *M, StringRef Name = "dummy") { + Function *Result = startFunction(M, Name); + + endFunctionWithRet(Result, Result->arg_begin()); + + return Result; + } + + // Inserts a function // int32_t add(int32_t a, int32_t b) { return a + b; } // in the current module and returns a pointer to it. Function *insertAddFunction(Module *M, StringRef Name = "add") {