mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
Tests for MCJIT multiple module support
llvm-svn: 191723
This commit is contained in:
parent
b068069d0c
commit
6f0e782b64
@ -11,6 +11,7 @@ set(MCJITTestsSources
|
|||||||
MCJITTest.cpp
|
MCJITTest.cpp
|
||||||
MCJITCAPITest.cpp
|
MCJITCAPITest.cpp
|
||||||
MCJITMemoryManagerTest.cpp
|
MCJITMemoryManagerTest.cpp
|
||||||
|
MCJITMultipleModuleTest.cpp
|
||||||
MCJITObjectCacheTest.cpp
|
MCJITObjectCacheTest.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
387
unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp
Normal file
387
unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
//===- 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;
|
||||||
|
|
||||||
|
class MCJITMultipleModuleTest : public testing::Test, public MCJITTestBase {};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -28,13 +28,20 @@ protected:
|
|||||||
|
|
||||||
namespace {
|
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
|
// FIXME: In order to JIT an empty module, there needs to be
|
||||||
// an interface to ExecutionEngine that forces compilation but
|
// 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) {
|
TEST_F(MCJITTest, empty_module) {
|
||||||
createJIT(M.take());
|
createJIT(M.take());
|
||||||
TheJIT->finalizeObject();
|
|
||||||
//EXPECT_NE(0, TheJIT->getObjectImage())
|
//EXPECT_NE(0, TheJIT->getObjectImage())
|
||||||
// << "Unable to generate executable loaded object image";
|
// << "Unable to generate executable loaded object image";
|
||||||
}
|
}
|
||||||
@ -47,7 +54,6 @@ TEST_F(MCJITTest, global_variable) {
|
|||||||
GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue);
|
GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue);
|
||||||
createJIT(M.take());
|
createJIT(M.take());
|
||||||
void *globalPtr = TheJIT->getPointerToGlobal(Global);
|
void *globalPtr = TheJIT->getPointerToGlobal(Global);
|
||||||
TheJIT->finalizeObject();
|
|
||||||
EXPECT_TRUE(0 != globalPtr)
|
EXPECT_TRUE(0 != globalPtr)
|
||||||
<< "Unable to get pointer to global value from JIT";
|
<< "Unable to get pointer to global value from JIT";
|
||||||
|
|
||||||
@ -60,15 +66,19 @@ TEST_F(MCJITTest, add_function) {
|
|||||||
|
|
||||||
Function *F = insertAddFunction(M.get());
|
Function *F = insertAddFunction(M.get());
|
||||||
createJIT(M.take());
|
createJIT(M.take());
|
||||||
void *addPtr = TheJIT->getPointerToFunction(F);
|
uint64_t addPtr = TheJIT->getFunctionAddress(F->getName().str());
|
||||||
TheJIT->finalizeObject();
|
|
||||||
EXPECT_TRUE(0 != addPtr)
|
EXPECT_TRUE(0 != addPtr)
|
||||||
<< "Unable to get pointer to function from JIT";
|
<< "Unable to get pointer to function from JIT";
|
||||||
|
|
||||||
int (*AddPtrTy)(int, int) = (int(*)(int, int))(intptr_t)addPtr;
|
ASSERT_TRUE(addPtr != 0) << "Unable to get pointer to function .";
|
||||||
EXPECT_EQ(0, AddPtrTy(0, 0));
|
int (*AddPtr)(int, int) = (int(*)(int, int))addPtr ;
|
||||||
EXPECT_EQ(3, AddPtrTy(1, 2));
|
EXPECT_EQ(0, AddPtr(0, 0));
|
||||||
EXPECT_EQ(-5, AddPtrTy(-2, -3));
|
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) {
|
TEST_F(MCJITTest, run_main) {
|
||||||
@ -77,12 +87,11 @@ TEST_F(MCJITTest, run_main) {
|
|||||||
int rc = 6;
|
int rc = 6;
|
||||||
Function *Main = insertMainFunction(M.get(), 6);
|
Function *Main = insertMainFunction(M.get(), 6);
|
||||||
createJIT(M.take());
|
createJIT(M.take());
|
||||||
void *vPtr = TheJIT->getPointerToFunction(Main);
|
uint64_t ptr = TheJIT->getFunctionAddress(Main->getName().str());
|
||||||
TheJIT->finalizeObject();
|
EXPECT_TRUE(0 != ptr)
|
||||||
EXPECT_TRUE(0 != vPtr)
|
|
||||||
<< "Unable to get pointer to main() from JIT";
|
<< "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();
|
int returnCode = FuncPtr();
|
||||||
EXPECT_EQ(returnCode, rc);
|
EXPECT_EQ(returnCode, rc);
|
||||||
}
|
}
|
||||||
@ -99,11 +108,10 @@ TEST_F(MCJITTest, return_global) {
|
|||||||
endFunctionWithRet(ReturnGlobal, ReadGlobal);
|
endFunctionWithRet(ReturnGlobal, ReadGlobal);
|
||||||
|
|
||||||
createJIT(M.take());
|
createJIT(M.take());
|
||||||
void *rgvPtr = TheJIT->getPointerToFunction(ReturnGlobal);
|
uint64_t rgvPtr = TheJIT->getFunctionAddress(ReturnGlobal->getName().str());
|
||||||
TheJIT->finalizeObject();
|
|
||||||
EXPECT_TRUE(0 != rgvPtr);
|
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())
|
EXPECT_EQ(initialNum, FuncPtr())
|
||||||
<< "Invalid value for global returned from JITted function";
|
<< "Invalid value for global returned from JITted function";
|
||||||
}
|
}
|
||||||
@ -131,10 +139,9 @@ TEST_F(MCJITTest, increment_global) {
|
|||||||
|
|
||||||
createJIT(M.take());
|
createJIT(M.take());
|
||||||
void *gvPtr = TheJIT->getPointerToGlobal(GV);
|
void *gvPtr = TheJIT->getPointerToGlobal(GV);
|
||||||
TheJIT->finalizeObject();
|
|
||||||
EXPECT_EQ(initialNum, *(int32_t*)gvPtr);
|
EXPECT_EQ(initialNum, *(int32_t*)gvPtr);
|
||||||
|
|
||||||
void *vPtr = TheJIT->getPointerToFunction(IncrementGlobal);
|
void *vPtr = TheJIT->getFunctionAddress(IncrementGlobal->getName().str());
|
||||||
EXPECT_TRUE(0 != vPtr)
|
EXPECT_TRUE(0 != vPtr)
|
||||||
<< "Unable to get pointer to main() from JIT";
|
<< "Unable to get pointer to main() from JIT";
|
||||||
|
|
||||||
@ -172,67 +179,15 @@ TEST_F(MCJITTest, multiple_functions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createJIT(M.take());
|
createJIT(M.take());
|
||||||
void *vPtr = TheJIT->getPointerToFunction(Outer);
|
uint64_t ptr = TheJIT->getFunctionAddress(Outer->getName().str());
|
||||||
TheJIT->finalizeObject();
|
EXPECT_TRUE(0 != ptr)
|
||||||
EXPECT_TRUE(0 != vPtr)
|
|
||||||
<< "Unable to get pointer to outer function from JIT";
|
<< "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())
|
EXPECT_EQ(innerRetVal, FuncPtr())
|
||||||
<< "Incorrect result returned from function";
|
<< "Incorrect result returned from function";
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /*!defined(__arm__)*/
|
#endif /*!defined(__arm__)*/
|
||||||
|
|
||||||
// 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);
|
|
||||||
TheJIT->finalizeObject();
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -119,12 +119,13 @@ protected:
|
|||||||
// Inserts an declaration to a function defined elsewhere
|
// Inserts an declaration to a function defined elsewhere
|
||||||
Function *insertExternalReferenceToFunction(Module *M, Function *Func) {
|
Function *insertExternalReferenceToFunction(Module *M, Function *Func) {
|
||||||
Function *Result = Function::Create(Func->getFunctionType(),
|
Function *Result = Function::Create(Func->getFunctionType(),
|
||||||
GlobalValue::AvailableExternallyLinkage,
|
GlobalValue::ExternalLinkage,
|
||||||
Func->getName(), M);
|
Func->getName(), M);
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserts a global variable of type int32
|
// Inserts a global variable of type int32
|
||||||
|
// FIXME: make this a template function to support any type
|
||||||
GlobalVariable *insertGlobalInt32(Module *M,
|
GlobalVariable *insertGlobalInt32(Module *M,
|
||||||
StringRef name,
|
StringRef name,
|
||||||
int32_t InitialValue) {
|
int32_t InitialValue) {
|
||||||
@ -138,11 +139,148 @@ protected:
|
|||||||
name);
|
name);
|
||||||
return Global;
|
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 {
|
class MCJITTestBase : public MCJITTestAPICommon, public TrivialModuleBuilder {
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
MCJITTestBase()
|
MCJITTestBase()
|
||||||
: TrivialModuleBuilder(HostTriple)
|
: TrivialModuleBuilder(HostTriple)
|
||||||
, OptLevel(CodeGenOpt::None)
|
, OptLevel(CodeGenOpt::None)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user