From 70c1ea493e6156eccde5270c139ef423b19ab580 Mon Sep 17 00:00:00 2001 From: Andrew Kaylor Date: Tue, 1 Oct 2013 01:48:36 +0000 Subject: [PATCH] Tests for MCJIT multiple module support git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191723 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../ExecutionEngine/MCJIT/CMakeLists.txt | 1 + .../MCJIT/MCJITMultipleModuleTest.cpp | 387 ++++++++++++++++++ unittests/ExecutionEngine/MCJIT/MCJITTest.cpp | 101 ++--- .../ExecutionEngine/MCJIT/MCJITTestBase.h | 142 ++++++- 4 files changed, 556 insertions(+), 75 deletions(-) create mode 100644 unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp diff --git a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt index 922cb7efd5e..911b604a90a 100644 --- a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt +++ b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt @@ -11,6 +11,7 @@ set(MCJITTestsSources MCJITTest.cpp MCJITCAPITest.cpp MCJITMemoryManagerTest.cpp + MCJITMultipleModuleTest.cpp MCJITObjectCacheTest.cpp ) diff --git a/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp new file mode 100644 index 00000000000..a7fc7fe2e2c --- /dev/null +++ b/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp @@ -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("")); + TheJIT->addModule(createEmptyModule("")); + + // 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("")); + TheJIT->addModule(createEmptyModule("")); + + // 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 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 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 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 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 A, B; + Function *FA1, *FA2, *FB; + createTwoModuleExternCase(A, FA1, B, FB); + FA2 = insertSimpleCallFunction(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 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(A.get(), "FA"); + endFunctionWithRet(FA, Builder.CreateLoad(GVA)); + FB = startFunction(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 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 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 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 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 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 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 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/MCJITTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp index 43a82984c45..7ccd2546c06 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp @@ -28,13 +28,20 @@ protected: 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()); - TheJIT->finalizeObject(); //EXPECT_NE(0, TheJIT->getObjectImage()) // << "Unable to generate executable loaded object image"; } @@ -47,7 +54,6 @@ TEST_F(MCJITTest, global_variable) { GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue); createJIT(M.take()); void *globalPtr = TheJIT->getPointerToGlobal(Global); - TheJIT->finalizeObject(); EXPECT_TRUE(0 != globalPtr) << "Unable to get pointer to global value from JIT"; @@ -60,15 +66,19 @@ TEST_F(MCJITTest, add_function) { Function *F = insertAddFunction(M.get()); createJIT(M.take()); - void *addPtr = TheJIT->getPointerToFunction(F); - TheJIT->finalizeObject(); + 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) { @@ -77,12 +87,11 @@ TEST_F(MCJITTest, run_main) { int rc = 6; Function *Main = insertMainFunction(M.get(), 6); createJIT(M.take()); - void *vPtr = TheJIT->getPointerToFunction(Main); - TheJIT->finalizeObject(); - 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); } @@ -99,11 +108,10 @@ TEST_F(MCJITTest, return_global) { endFunctionWithRet(ReturnGlobal, ReadGlobal); createJIT(M.take()); - void *rgvPtr = TheJIT->getPointerToFunction(ReturnGlobal); - TheJIT->finalizeObject(); + 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"; } @@ -131,10 +139,9 @@ TEST_F(MCJITTest, increment_global) { createJIT(M.take()); void *gvPtr = TheJIT->getPointerToGlobal(GV); - TheJIT->finalizeObject(); 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"; @@ -172,67 +179,15 @@ TEST_F(MCJITTest, multiple_functions) { } createJIT(M.take()); - void *vPtr = TheJIT->getPointerToFunction(Outer); - TheJIT->finalizeObject(); - 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"; } #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("")); - TheJIT->addModule(createEmptyModule("")); - - // 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("")); - - 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(); -} -*/ - } diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h index 5debb8b5785..b42a9c0980d 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h +++ b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h @@ -119,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) { @@ -138,11 +139,148 @@ protected: name); 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(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 &A, + Function *&FA, + OwningPtr &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 &A, + Function *&FA, + OwningPtr &B, + Function *&FB, + OwningPtr &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(B.get(), FAExtern_in_B); + + C.reset(createEmptyModule("C")); + Function *FBExtern_in_C = insertExternalReferenceToFunction(C.get(), FB); + FC = insertSimpleCallFunction(C.get(), FBExtern_in_C); + } + + + // Module A { Function FA }, + // Populates Modules A and B: + // Module B { Function FB } + void createTwoModuleCase(OwningPtr &A, Function *&FA, + OwningPtr &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 &A, Function *&FA, + OwningPtr &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(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 &A, + Function *&FA, + OwningPtr &B, + Function *&FB, + OwningPtr &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(B.get(), FAExtern_in_B); + + C.reset(createEmptyModule("C")); + Function *FAExtern_in_C = insertExternalReferenceToFunction(C.get(), FA); + FC = insertSimpleCallFunction(C.get(), FAExtern_in_C); + } }; + class MCJITTestBase : public MCJITTestAPICommon, public TrivialModuleBuilder { protected: - + MCJITTestBase() : TrivialModuleBuilder(HostTriple) , OptLevel(CodeGenOpt::None) -- 2.34.1