You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.207
Former-commit-id: 3b152f462918d427ce18620a2cbe4f8b79650449
This commit is contained in:
parent
8e12397d70
commit
eb85e2fc17
@ -1,33 +0,0 @@
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
Analysis
|
||||
Core
|
||||
ExecutionEngine
|
||||
IPO
|
||||
MC
|
||||
MCJIT
|
||||
RuntimeDyld
|
||||
ScalarOpts
|
||||
Support
|
||||
Target
|
||||
nativecodegen
|
||||
)
|
||||
|
||||
set(MCJITTestsSources
|
||||
MCJITTest.cpp
|
||||
MCJITCAPITest.cpp
|
||||
MCJITMemoryManagerTest.cpp
|
||||
MCJITMultipleModuleTest.cpp
|
||||
MCJITObjectCacheTest.cpp
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
list(APPEND MCJITTestsSources MCJITTests.def)
|
||||
endif()
|
||||
|
||||
add_llvm_unittest(MCJITTests
|
||||
${MCJITTestsSources}
|
||||
)
|
||||
|
||||
if(MINGW OR CYGWIN)
|
||||
set_property(TARGET MCJITTests PROPERTY LINK_FLAGS -Wl,--export-all-symbols)
|
||||
endif()
|
File diff suppressed because it is too large
Load Diff
@ -1,170 +0,0 @@
|
||||
//===- 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 "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(MCJITMemoryManagerTest, BasicAllocations) {
|
||||
std::unique_ptr<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*)nullptr, code1);
|
||||
EXPECT_NE((uint8_t*)nullptr, code2);
|
||||
EXPECT_NE((uint8_t*)nullptr, data1);
|
||||
EXPECT_NE((uint8_t*)nullptr, 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) {
|
||||
std::unique_ptr<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*)nullptr, code1);
|
||||
EXPECT_NE((uint8_t*)nullptr, code2);
|
||||
EXPECT_NE((uint8_t*)nullptr, data1);
|
||||
EXPECT_NE((uint8_t*)nullptr, 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) {
|
||||
std::unique_ptr<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 *)nullptr, code[i]);
|
||||
EXPECT_NE((uint8_t *)nullptr, 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) {
|
||||
std::unique_ptr<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 *)nullptr, code[i]);
|
||||
EXPECT_NE((uint8_t *)nullptr, 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
|
||||
|
@ -1,423 +0,0 @@
|
||||
//===- MCJITMultipeModuleTest.cpp - Unit tests for the MCJIT ----*- C++ -*-===//
|
||||
//
|
||||
// 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 "MCJITTestBase.h"
|
||||
#include "llvm/ExecutionEngine/MCJIT.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;
|
||||
|
||||
std::unique_ptr<Module> A, B;
|
||||
Function *FA, *FB;
|
||||
createTwoModuleCase(A, FA, B, FB);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
|
||||
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;
|
||||
|
||||
std::unique_ptr<Module> A, B;
|
||||
Function *FA, *FB;
|
||||
createTwoModuleCase(A, FA, B, FB);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
|
||||
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;
|
||||
|
||||
std::unique_ptr<Module> A, B;
|
||||
Function *FA, *FB;
|
||||
createTwoModuleExternCase(A, FA, B, FB);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
|
||||
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;
|
||||
|
||||
std::unique_ptr<Module> A, B;
|
||||
Function *FA, *FB;
|
||||
createTwoModuleExternCase(A, FA, B, FB);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
|
||||
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;
|
||||
|
||||
std::unique_ptr<Module> A, B;
|
||||
Function *FA1, *FA2, *FB;
|
||||
createTwoModuleExternCase(A, FA1, B, FB);
|
||||
FA2 = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(A.get(), FA1);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
|
||||
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, Internal Global GVC, Function FB loads GVB },
|
||||
// execute FB then FA, also check that the global variables are properly accesible
|
||||
// through the ExecutionEngine APIs
|
||||
TEST_F(MCJITMultipleModuleTest, two_module_global_variables_case) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
std::unique_ptr<Module> A, B;
|
||||
Function *FA, *FB;
|
||||
GlobalVariable *GVA, *GVB, *GVC;
|
||||
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));
|
||||
|
||||
GVC = insertGlobalInt32(B.get(), "GVC", initialNum);
|
||||
GVC->setLinkage(GlobalValue::InternalLinkage);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
|
||||
EXPECT_EQ(GVA, TheJIT->FindGlobalVariableNamed("GVA"));
|
||||
EXPECT_EQ(GVB, TheJIT->FindGlobalVariableNamed("GVB"));
|
||||
EXPECT_EQ(GVC, TheJIT->FindGlobalVariableNamed("GVC",true));
|
||||
EXPECT_EQ(nullptr, TheJIT->FindGlobalVariableNamed("GVC"));
|
||||
|
||||
uint64_t FBPtr = TheJIT->getFunctionAddress(FB->getName().str());
|
||||
TheJIT->finalizeObject();
|
||||
EXPECT_TRUE(0 != FBPtr);
|
||||
int32_t(*FuncPtr)() = (int32_t(*)())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(*)())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;
|
||||
|
||||
std::unique_ptr<Module> A, B, C;
|
||||
Function *FA, *FB, *FC;
|
||||
createThreeModuleCase(A, FA, B, FB, C, FC);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
TheJIT->addModule(std::move(C));
|
||||
|
||||
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;
|
||||
|
||||
std::unique_ptr<Module> A, B, C;
|
||||
Function *FA, *FB, *FC;
|
||||
createThreeModuleCase(A, FA, B, FB, C, FC);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
TheJIT->addModule(std::move(C));
|
||||
|
||||
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;
|
||||
|
||||
std::unique_ptr<Module> A, B, C;
|
||||
Function *FA, *FB, *FC;
|
||||
createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
TheJIT->addModule(std::move(C));
|
||||
|
||||
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;
|
||||
|
||||
std::unique_ptr<Module> A, B, C;
|
||||
Function *FA, *FB, *FC;
|
||||
createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
TheJIT->addModule(std::move(C));
|
||||
|
||||
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;
|
||||
|
||||
std::unique_ptr<Module> A, B;
|
||||
Function *FA, *FB1, *FB2;
|
||||
createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
|
||||
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;
|
||||
|
||||
std::unique_ptr<Module> A, B;
|
||||
Function *FA, *FB1, *FB2;
|
||||
createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
|
||||
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;
|
||||
|
||||
std::unique_ptr<Module> A, B;
|
||||
Function *FA, *FB1, *FB2;
|
||||
createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
|
||||
uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str());
|
||||
checkAccumulate(ptr);
|
||||
|
||||
ptr = TheJIT->getFunctionAddress(FB2->getName().str());
|
||||
checkAccumulate(ptr);
|
||||
}
|
||||
|
||||
// Test that FindFunctionNamed finds the definition of
|
||||
// a function in the correct module. We check two functions
|
||||
// in two different modules, to make sure that for at least
|
||||
// one of them MCJIT had to ignore the extern declaration.
|
||||
TEST_F(MCJITMultipleModuleTest, FindFunctionNamed_test) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
std::unique_ptr<Module> A, B;
|
||||
Function *FA, *FB1, *FB2;
|
||||
createCrossModuleRecursiveCase(A, FA, B, FB1, FB2);
|
||||
|
||||
createJIT(std::move(A));
|
||||
TheJIT->addModule(std::move(B));
|
||||
|
||||
EXPECT_EQ(FA, TheJIT->FindFunctionNamed(FA->getName().data()));
|
||||
EXPECT_EQ(FB1, TheJIT->FindFunctionNamed(FB1->getName().data()));
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
@ -1,229 +0,0 @@
|
||||
//===- MCJITObjectCacheTest.cpp - Unit tests for MCJIT object caching -----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MCJITTestBase.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/ExecutionEngine/MCJIT.h"
|
||||
#include "llvm/ExecutionEngine/ObjectCache.h"
|
||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class TestObjectCache : public ObjectCache {
|
||||
public:
|
||||
TestObjectCache() : DuplicateInserted(false) { }
|
||||
|
||||
void notifyObjectCompiled(const Module *M, MemoryBufferRef Obj) override {
|
||||
// If we've seen this module before, note that.
|
||||
const std::string ModuleID = M->getModuleIdentifier();
|
||||
if (ObjMap.find(ModuleID) != ObjMap.end())
|
||||
DuplicateInserted = true;
|
||||
// Store a copy of the buffer in our map.
|
||||
ObjMap[ModuleID] = copyBuffer(Obj);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> getObject(const Module *M) override {
|
||||
const MemoryBuffer* BufferFound = getObjectInternal(M);
|
||||
ModulesLookedUp.insert(M->getModuleIdentifier());
|
||||
if (!BufferFound)
|
||||
return nullptr;
|
||||
// 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; }
|
||||
|
||||
bool wasModuleLookedUp(const Module *M) {
|
||||
return ModulesLookedUp.find(M->getModuleIdentifier())
|
||||
!= ModulesLookedUp.end();
|
||||
}
|
||||
|
||||
const MemoryBuffer* getObjectInternal(const Module* M) {
|
||||
// Look for the module in our map.
|
||||
const std::string ModuleID = M->getModuleIdentifier();
|
||||
StringMap<const MemoryBuffer *>::iterator it = ObjMap.find(ModuleID);
|
||||
if (it == ObjMap.end())
|
||||
return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
MemoryBuffer *copyBuffer(MemoryBufferRef Buf) {
|
||||
// Create a local copy of the buffer.
|
||||
std::unique_ptr<MemoryBuffer> NewBuffer =
|
||||
MemoryBuffer::getMemBufferCopy(Buf.getBuffer());
|
||||
MemoryBuffer *Ret = NewBuffer.get();
|
||||
AllocatedBuffers.push_back(std::move(NewBuffer));
|
||||
return Ret;
|
||||
}
|
||||
|
||||
StringMap<const MemoryBuffer *> ObjMap;
|
||||
StringSet<> ModulesLookedUp;
|
||||
SmallVector<std::unique_ptr<MemoryBuffer>, 2> AllocatedBuffers;
|
||||
bool DuplicateInserted;
|
||||
};
|
||||
|
||||
class MCJITObjectCacheTest : public testing::Test, public MCJITTestBase {
|
||||
protected:
|
||||
enum {
|
||||
OriginalRC = 6,
|
||||
ReplacementRC = 7
|
||||
};
|
||||
|
||||
void SetUp() override {
|
||||
M.reset(createEmptyModule("<main>"));
|
||||
Main = insertMainFunction(M.get(), OriginalRC);
|
||||
}
|
||||
|
||||
void compileAndRun(int ExpectedRC = OriginalRC) {
|
||||
// This function shouldn't be called until after SetUp.
|
||||
ASSERT_TRUE(bool(TheJIT));
|
||||
ASSERT_TRUE(nullptr != Main);
|
||||
|
||||
// We may be using a null cache, so ensure compilation is valid.
|
||||
TheJIT->finalizeObject();
|
||||
void *vPtr = TheJIT->getPointerToFunction(Main);
|
||||
|
||||
EXPECT_TRUE(nullptr != vPtr)
|
||||
<< "Unable to get pointer to main() from JIT";
|
||||
|
||||
int (*FuncPtr)() = (int(*)())(intptr_t)vPtr;
|
||||
int returnCode = FuncPtr();
|
||||
EXPECT_EQ(returnCode, ExpectedRC);
|
||||
}
|
||||
|
||||
Function *Main;
|
||||
};
|
||||
|
||||
TEST_F(MCJITObjectCacheTest, SetNullObjectCache) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
createJIT(std::move(M));
|
||||
|
||||
TheJIT->setObjectCache(nullptr);
|
||||
|
||||
compileAndRun();
|
||||
}
|
||||
|
||||
TEST_F(MCJITObjectCacheTest, VerifyBasicObjectCaching) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
|
||||
|
||||
// Save a copy of the module pointer before handing it off to MCJIT.
|
||||
const Module * SavedModulePointer = M.get();
|
||||
|
||||
createJIT(std::move(M));
|
||||
|
||||
TheJIT->setObjectCache(Cache.get());
|
||||
|
||||
// Verify that our object cache does not contain the module yet.
|
||||
const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SavedModulePointer);
|
||||
EXPECT_EQ(nullptr, ObjBuffer);
|
||||
|
||||
compileAndRun();
|
||||
|
||||
// Verify that MCJIT tried to look-up this module in the cache.
|
||||
EXPECT_TRUE(Cache->wasModuleLookedUp(SavedModulePointer));
|
||||
|
||||
// Verify that our object cache now contains the module.
|
||||
ObjBuffer = Cache->getObjectInternal(SavedModulePointer);
|
||||
EXPECT_TRUE(nullptr != ObjBuffer);
|
||||
|
||||
// Verify that the cache was only notified once.
|
||||
EXPECT_FALSE(Cache->wereDuplicatesInserted());
|
||||
}
|
||||
|
||||
TEST_F(MCJITObjectCacheTest, VerifyLoadFromCache) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
|
||||
|
||||
// Compile this module with an MCJIT engine
|
||||
createJIT(std::move(M));
|
||||
TheJIT->setObjectCache(Cache.get());
|
||||
TheJIT->finalizeObject();
|
||||
|
||||
// Destroy the MCJIT engine we just used
|
||||
TheJIT.reset();
|
||||
|
||||
// Create a new memory manager.
|
||||
MM.reset(new SectionMemoryManager());
|
||||
|
||||
// Create a new module and save it. Use a different return code so we can
|
||||
// tell if MCJIT compiled this module or used the cache.
|
||||
M.reset(createEmptyModule("<main>"));
|
||||
Main = insertMainFunction(M.get(), ReplacementRC);
|
||||
const Module * SecondModulePointer = M.get();
|
||||
|
||||
// Create a new MCJIT instance to load this module then execute it.
|
||||
createJIT(std::move(M));
|
||||
TheJIT->setObjectCache(Cache.get());
|
||||
compileAndRun();
|
||||
|
||||
// Verify that MCJIT tried to look-up this module in the cache.
|
||||
EXPECT_TRUE(Cache->wasModuleLookedUp(SecondModulePointer));
|
||||
|
||||
// Verify that MCJIT didn't try to cache this again.
|
||||
EXPECT_FALSE(Cache->wereDuplicatesInserted());
|
||||
}
|
||||
|
||||
TEST_F(MCJITObjectCacheTest, VerifyNonLoadFromCache) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
|
||||
|
||||
// Compile this module with an MCJIT engine
|
||||
createJIT(std::move(M));
|
||||
TheJIT->setObjectCache(Cache.get());
|
||||
TheJIT->finalizeObject();
|
||||
|
||||
// Destroy the MCJIT engine we just used
|
||||
TheJIT.reset();
|
||||
|
||||
// Create a new memory manager.
|
||||
MM.reset(new SectionMemoryManager());
|
||||
|
||||
// Create a new module and save it. Use a different return code so we can
|
||||
// tell if MCJIT compiled this module or used the cache. Note that we use
|
||||
// a new module name here so the module shouldn't be found in the cache.
|
||||
M.reset(createEmptyModule("<not-main>"));
|
||||
Main = insertMainFunction(M.get(), ReplacementRC);
|
||||
const Module * SecondModulePointer = M.get();
|
||||
|
||||
// Create a new MCJIT instance to load this module then execute it.
|
||||
createJIT(std::move(M));
|
||||
TheJIT->setObjectCache(Cache.get());
|
||||
|
||||
// Verify that our object cache does not contain the module yet.
|
||||
const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SecondModulePointer);
|
||||
EXPECT_EQ(nullptr, ObjBuffer);
|
||||
|
||||
// Run the function and look for the replacement return code.
|
||||
compileAndRun(ReplacementRC);
|
||||
|
||||
// Verify that MCJIT tried to look-up this module in the cache.
|
||||
EXPECT_TRUE(Cache->wasModuleLookedUp(SecondModulePointer));
|
||||
|
||||
// Verify that our object cache now contains the module.
|
||||
ObjBuffer = Cache->getObjectInternal(SecondModulePointer);
|
||||
EXPECT_TRUE(nullptr != ObjBuffer);
|
||||
|
||||
// Verify that MCJIT didn't try to cache this again.
|
||||
EXPECT_FALSE(Cache->wereDuplicatesInserted());
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
@ -1,283 +0,0 @@
|
||||
//===- MCJITTest.cpp - Unit tests for the MCJIT -----------------*- C++ -*-===//
|
||||
//
|
||||
// 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 "MCJITTestBase.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class MCJITTest : public testing::Test, public MCJITTestBase {
|
||||
protected:
|
||||
void SetUp() override { M.reset(createEmptyModule("<main>")); }
|
||||
};
|
||||
|
||||
// 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 not require retrieval of a pointer to a function/global.
|
||||
/*
|
||||
TEST_F(MCJITTest, empty_module) {
|
||||
createJIT(M.take());
|
||||
//EXPECT_NE(0, TheJIT->getObjectImage())
|
||||
// << "Unable to generate executable loaded object image";
|
||||
}
|
||||
*/
|
||||
|
||||
TEST_F(MCJITTest, global_variable) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
int initialValue = 5;
|
||||
GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue);
|
||||
createJIT(std::move(M));
|
||||
void *globalPtr = TheJIT->getPointerToGlobal(Global);
|
||||
EXPECT_TRUE(nullptr != globalPtr)
|
||||
<< "Unable to get pointer to global value from JIT";
|
||||
|
||||
EXPECT_EQ(initialValue, *(int32_t*)globalPtr)
|
||||
<< "Unexpected initial value of global";
|
||||
}
|
||||
|
||||
TEST_F(MCJITTest, add_function) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
Function *F = insertAddFunction(M.get());
|
||||
createJIT(std::move(M));
|
||||
uint64_t addPtr = TheJIT->getFunctionAddress(F->getName().str());
|
||||
EXPECT_TRUE(0 != addPtr)
|
||||
<< "Unable to get pointer to function from JIT";
|
||||
|
||||
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) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
int rc = 6;
|
||||
Function *Main = insertMainFunction(M.get(), 6);
|
||||
createJIT(std::move(M));
|
||||
uint64_t ptr = TheJIT->getFunctionAddress(Main->getName().str());
|
||||
EXPECT_TRUE(0 != ptr)
|
||||
<< "Unable to get pointer to main() from JIT";
|
||||
|
||||
int (*FuncPtr)() = (int(*)())ptr;
|
||||
int returnCode = FuncPtr();
|
||||
EXPECT_EQ(returnCode, rc);
|
||||
}
|
||||
|
||||
TEST_F(MCJITTest, return_global) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
int32_t initialNum = 7;
|
||||
GlobalVariable *GV = insertGlobalInt32(M.get(), "myglob", initialNum);
|
||||
|
||||
Function *ReturnGlobal = startFunction<int32_t(void)>(M.get(),
|
||||
"ReturnGlobal");
|
||||
Value *ReadGlobal = Builder.CreateLoad(GV);
|
||||
endFunctionWithRet(ReturnGlobal, ReadGlobal);
|
||||
|
||||
createJIT(std::move(M));
|
||||
uint64_t rgvPtr = TheJIT->getFunctionAddress(ReturnGlobal->getName().str());
|
||||
EXPECT_TRUE(0 != rgvPtr);
|
||||
|
||||
int32_t(*FuncPtr)() = (int32_t(*)())rgvPtr;
|
||||
EXPECT_EQ(initialNum, FuncPtr())
|
||||
<< "Invalid value for global returned from JITted function";
|
||||
}
|
||||
|
||||
// FIXME: This case fails due to a bug with getPointerToGlobal().
|
||||
// The bug is due to MCJIT not having an implementation of getPointerToGlobal()
|
||||
// which results in falling back on the ExecutionEngine implementation that
|
||||
// allocates a new memory block for the global instead of using the same
|
||||
// global variable that is emitted by MCJIT. Hence, the pointer (gvPtr below)
|
||||
// has the correct initial value, but updates to the real global (accessed by
|
||||
// JITted code) are not propagated. Instead, getPointerToGlobal() should return
|
||||
// a pointer into the loaded ObjectImage to reference the emitted global.
|
||||
/*
|
||||
TEST_F(MCJITTest, increment_global) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
int32_t initialNum = 5;
|
||||
Function *IncrementGlobal = startFunction<int32_t(void)>(M.get(), "IncrementGlobal");
|
||||
GlobalVariable *GV = insertGlobalInt32(M.get(), "my_global", initialNum);
|
||||
Value *DerefGV = Builder.CreateLoad(GV);
|
||||
Value *AddResult = Builder.CreateAdd(DerefGV,
|
||||
ConstantInt::get(Context, APInt(32, 1)));
|
||||
Builder.CreateStore(AddResult, GV);
|
||||
endFunctionWithRet(IncrementGlobal, AddResult);
|
||||
|
||||
createJIT(M.take());
|
||||
void *gvPtr = TheJIT->getPointerToGlobal(GV);
|
||||
EXPECT_EQ(initialNum, *(int32_t*)gvPtr);
|
||||
|
||||
void *vPtr = TheJIT->getFunctionAddress(IncrementGlobal->getName().str());
|
||||
EXPECT_TRUE(0 != vPtr)
|
||||
<< "Unable to get pointer to main() from JIT";
|
||||
|
||||
int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)vPtr;
|
||||
|
||||
for(int i = 1; i < 3; ++i) {
|
||||
int32_t result = FuncPtr();
|
||||
EXPECT_EQ(initialNum + i, result); // OK
|
||||
EXPECT_EQ(initialNum + i, *(int32_t*)gvPtr); // FAILS
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// PR16013: XFAIL this test on ARM, which currently can't handle multiple relocations.
|
||||
#if !defined(__arm__)
|
||||
|
||||
TEST_F(MCJITTest, multiple_functions) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
unsigned int numLevels = 23;
|
||||
int32_t innerRetVal= 5;
|
||||
|
||||
Function *Inner = startFunction<int32_t(void)>(M.get(), "Inner");
|
||||
endFunctionWithRet(Inner, ConstantInt::get(Context, APInt(32, innerRetVal)));
|
||||
|
||||
Function *Outer;
|
||||
for (unsigned int i = 0; i < numLevels; ++i) {
|
||||
std::stringstream funcName;
|
||||
funcName << "level_" << i;
|
||||
Outer = startFunction<int32_t(void)>(M.get(), funcName.str());
|
||||
Value *innerResult = Builder.CreateCall(Inner, {});
|
||||
endFunctionWithRet(Outer, innerResult);
|
||||
|
||||
Inner = Outer;
|
||||
}
|
||||
|
||||
createJIT(std::move(M));
|
||||
uint64_t ptr = TheJIT->getFunctionAddress(Outer->getName().str());
|
||||
EXPECT_TRUE(0 != ptr)
|
||||
<< "Unable to get pointer to outer function from JIT";
|
||||
|
||||
int32_t(*FuncPtr)() = (int32_t(*)())ptr;
|
||||
EXPECT_EQ(innerRetVal, FuncPtr())
|
||||
<< "Incorrect result returned from function";
|
||||
}
|
||||
|
||||
#endif /*!defined(__arm__)*/
|
||||
|
||||
TEST_F(MCJITTest, multiple_decl_lookups) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
Function *Foo = insertExternalReferenceToFunction<void(void)>(M.get(), "_exit");
|
||||
createJIT(std::move(M));
|
||||
void *A = TheJIT->getPointerToFunction(Foo);
|
||||
void *B = TheJIT->getPointerToFunction(Foo);
|
||||
|
||||
EXPECT_TRUE(A != nullptr) << "Failed lookup - test not correctly configured.";
|
||||
EXPECT_EQ(A, B) << "Repeat calls to getPointerToFunction fail.";
|
||||
}
|
||||
|
||||
typedef void * (*FunctionHandlerPtr)(const std::string &str);
|
||||
|
||||
TEST_F(MCJITTest, lazy_function_creator_pointer) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
Function *Foo = insertExternalReferenceToFunction<int32_t(void)>(M.get(),
|
||||
"\1Foo");
|
||||
startFunction<int32_t(void)>(M.get(), "Parent");
|
||||
CallInst *Call = Builder.CreateCall(Foo, {});
|
||||
Builder.CreateRet(Call);
|
||||
|
||||
createJIT(std::move(M));
|
||||
|
||||
// Set up the lazy function creator that records the name of the last
|
||||
// unresolved external function found in the module. Using a function pointer
|
||||
// prevents us from capturing local variables, which is why this is static.
|
||||
static std::string UnresolvedExternal;
|
||||
FunctionHandlerPtr UnresolvedHandler = [] (const std::string &str) {
|
||||
// Try to resolve the function in the current process before marking it as
|
||||
// unresolved. This solves an issue on ARM where '__aeabi_*' function names
|
||||
// are passed to this handler.
|
||||
void *symbol =
|
||||
llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(str.c_str());
|
||||
if (symbol) {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
UnresolvedExternal = str;
|
||||
return (void *)(uintptr_t)-1;
|
||||
};
|
||||
TheJIT->InstallLazyFunctionCreator(UnresolvedHandler);
|
||||
|
||||
// JIT the module.
|
||||
TheJIT->finalizeObject();
|
||||
|
||||
// Verify that our handler was called.
|
||||
EXPECT_EQ(UnresolvedExternal, "Foo");
|
||||
}
|
||||
|
||||
TEST_F(MCJITTest, lazy_function_creator_lambda) {
|
||||
SKIP_UNSUPPORTED_PLATFORM;
|
||||
|
||||
Function *Foo1 = insertExternalReferenceToFunction<int32_t(void)>(M.get(),
|
||||
"\1Foo1");
|
||||
Function *Foo2 = insertExternalReferenceToFunction<int32_t(void)>(M.get(),
|
||||
"\1Foo2");
|
||||
startFunction<int32_t(void)>(M.get(), "Parent");
|
||||
CallInst *Call1 = Builder.CreateCall(Foo1, {});
|
||||
CallInst *Call2 = Builder.CreateCall(Foo2, {});
|
||||
Value *Result = Builder.CreateAdd(Call1, Call2);
|
||||
Builder.CreateRet(Result);
|
||||
|
||||
createJIT(std::move(M));
|
||||
|
||||
// Set up the lazy function creator that records the name of unresolved
|
||||
// external functions in the module.
|
||||
std::vector<std::string> UnresolvedExternals;
|
||||
auto UnresolvedHandler = [&UnresolvedExternals] (const std::string &str) {
|
||||
// Try to resolve the function in the current process before marking it as
|
||||
// unresolved. This solves an issue on ARM where '__aeabi_*' function names
|
||||
// are passed to this handler.
|
||||
void *symbol =
|
||||
llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(str.c_str());
|
||||
if (symbol) {
|
||||
return symbol;
|
||||
}
|
||||
UnresolvedExternals.push_back(str);
|
||||
return (void *)(uintptr_t)-1;
|
||||
};
|
||||
TheJIT->InstallLazyFunctionCreator(UnresolvedHandler);
|
||||
|
||||
// JIT the module.
|
||||
TheJIT->finalizeObject();
|
||||
|
||||
// Verify that our handler was called for each unresolved function.
|
||||
auto I = UnresolvedExternals.begin(), E = UnresolvedExternals.end();
|
||||
EXPECT_EQ(UnresolvedExternals.size(), 2u);
|
||||
EXPECT_FALSE(std::find(I, E, "Foo1") == E);
|
||||
EXPECT_FALSE(std::find(I, E, "Foo2") == E);
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
@ -1,101 +0,0 @@
|
||||
//===- MCJITTestBase.h - Common base class for MCJIT Unit tests ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class implements functionality shared by both MCJIT C API tests, and
|
||||
// the C++ API tests.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTAPICOMMON_H
|
||||
#define LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTAPICOMMON_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
|
||||
// Used to skip tests on unsupported architectures and operating systems.
|
||||
// To skip a test, add this macro at the top of a test-case in a suite that
|
||||
// inherits from MCJITTestBase. See MCJITTest.cpp for examples.
|
||||
#define SKIP_UNSUPPORTED_PLATFORM \
|
||||
do \
|
||||
if (!ArchSupportsMCJIT() || !OSSupportsMCJIT()) \
|
||||
return; \
|
||||
while(0)
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MCJITTestAPICommon {
|
||||
protected:
|
||||
MCJITTestAPICommon()
|
||||
: HostTriple(sys::getProcessTriple())
|
||||
{
|
||||
InitializeNativeTarget();
|
||||
InitializeNativeTargetAsmPrinter();
|
||||
|
||||
// FIXME: It isn't at all clear why this is necesasry, but without it we
|
||||
// fail to initialize the AssumptionCacheTracker.
|
||||
initializeAssumptionCacheTrackerPass(*PassRegistry::getPassRegistry());
|
||||
|
||||
#ifdef LLVM_ON_WIN32
|
||||
// On Windows, generate ELF objects by specifying "-elf" in triple
|
||||
HostTriple += "-elf";
|
||||
#endif // LLVM_ON_WIN32
|
||||
HostTriple = Triple::normalize(HostTriple);
|
||||
}
|
||||
|
||||
/// Returns true if the host architecture is known to support MCJIT
|
||||
bool ArchSupportsMCJIT() {
|
||||
Triple Host(HostTriple);
|
||||
// If ARCH is not supported, bail
|
||||
if (!is_contained(SupportedArchs, Host.getArch()))
|
||||
return false;
|
||||
|
||||
// If ARCH is supported and has no specific sub-arch support
|
||||
if (!is_contained(HasSubArchs, Host.getArch()))
|
||||
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))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns true if the host OS is known to support MCJIT
|
||||
bool OSSupportsMCJIT() {
|
||||
Triple Host(HostTriple);
|
||||
|
||||
if (find(UnsupportedEnvironments, Host.getEnvironment()) !=
|
||||
UnsupportedEnvironments.end())
|
||||
return false;
|
||||
|
||||
if (!is_contained(UnsupportedOSs, Host.getOS()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
SmallVector<Triple::EnvironmentType, 1> UnsupportedEnvironments;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -1,338 +0,0 @@
|
||||
//===- MCJITTestBase.h - Common base class for MCJIT Unit tests -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class implements common functionality required by the MCJIT unit tests,
|
||||
// as well as logic to skip tests on unsupported architectures and operating
|
||||
// systems.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTBASE_H
|
||||
#define LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTBASE_H
|
||||
|
||||
#include "MCJITTestAPICommon.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/TypeBuilder.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Helper class that can build very simple Modules
|
||||
class TrivialModuleBuilder {
|
||||
protected:
|
||||
LLVMContext Context;
|
||||
IRBuilder<> Builder;
|
||||
std::string BuilderTriple;
|
||||
|
||||
TrivialModuleBuilder(const std::string &Triple)
|
||||
: Builder(Context), BuilderTriple(Triple) {}
|
||||
|
||||
Module *createEmptyModule(StringRef Name = StringRef()) {
|
||||
Module * M = new Module(Name, Context);
|
||||
M->setTargetTriple(Triple::normalize(BuilderTriple));
|
||||
return M;
|
||||
}
|
||||
|
||||
template<typename FuncType>
|
||||
Function *startFunction(Module *M, StringRef Name) {
|
||||
Function *Result = Function::Create(
|
||||
TypeBuilder<FuncType, false>::get(Context),
|
||||
GlobalValue::ExternalLinkage, Name, M);
|
||||
|
||||
BasicBlock *BB = BasicBlock::Create(Context, Name, Result);
|
||||
Builder.SetInsertPoint(BB);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void endFunctionWithRet(Function *Func, Value *RetValue) {
|
||||
Builder.CreateRet(RetValue);
|
||||
}
|
||||
|
||||
// Inserts a simple function that invokes Callee and takes the same arguments:
|
||||
// int Caller(...) { return Callee(...); }
|
||||
template<typename Signature>
|
||||
Function *insertSimpleCallFunction(Module *M, Function *Callee) {
|
||||
Function *Result = startFunction<Signature>(M, "caller");
|
||||
|
||||
SmallVector<Value*, 1> CallArgs;
|
||||
|
||||
for (Argument &A : Result->args())
|
||||
CallArgs.push_back(&A);
|
||||
|
||||
Value *ReturnCode = Builder.CreateCall(Callee, CallArgs);
|
||||
Builder.CreateRet(ReturnCode);
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Inserts a function named 'main' that returns a uint32_t:
|
||||
// int32_t main() { return X; }
|
||||
// where X is given by returnCode
|
||||
Function *insertMainFunction(Module *M, uint32_t returnCode) {
|
||||
Function *Result = startFunction<int32_t(void)>(M, "main");
|
||||
|
||||
Value *ReturnVal = ConstantInt::get(Context, APInt(32, returnCode));
|
||||
endFunctionWithRet(Result, ReturnVal);
|
||||
|
||||
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") {
|
||||
Function *Result = startFunction<int32_t(int32_t, int32_t)>(M, Name);
|
||||
|
||||
Function::arg_iterator args = Result->arg_begin();
|
||||
Value *Arg1 = &*args;
|
||||
Value *Arg2 = &*++args;
|
||||
Value *AddResult = Builder.CreateAdd(Arg1, Arg2);
|
||||
|
||||
endFunctionWithRet(Result, AddResult);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Inserts a declaration to a function defined elsewhere
|
||||
template <typename FuncType>
|
||||
Function *insertExternalReferenceToFunction(Module *M, StringRef Name) {
|
||||
Function *Result = Function::Create(
|
||||
TypeBuilder<FuncType, false>::get(Context),
|
||||
GlobalValue::ExternalLinkage, Name, M);
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Inserts an declaration to a function defined elsewhere
|
||||
Function *insertExternalReferenceToFunction(Module *M, StringRef Name,
|
||||
FunctionType *FuncTy) {
|
||||
Function *Result = Function::Create(FuncTy,
|
||||
GlobalValue::ExternalLinkage,
|
||||
Name, M);
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Inserts an declaration to a function defined elsewhere
|
||||
Function *insertExternalReferenceToFunction(Module *M, Function *Func) {
|
||||
Function *Result = Function::Create(Func->getFunctionType(),
|
||||
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) {
|
||||
Type *GlobalTy = TypeBuilder<types::i<32>, true>::get(Context);
|
||||
Constant *IV = ConstantInt::get(Context, APInt(32, InitialValue));
|
||||
GlobalVariable *Global = new GlobalVariable(*M,
|
||||
GlobalTy,
|
||||
false,
|
||||
GlobalValue::ExternalLinkage,
|
||||
IV,
|
||||
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 = nullptr,
|
||||
StringRef Name = "accumulate") {
|
||||
Function *Result = startFunction<int32_t(int32_t)>(M, Name);
|
||||
if (!Helper)
|
||||
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(std::unique_ptr<Module> &A, Function *&FA,
|
||||
std::unique_ptr<Module> &B,
|
||||
Function *&FB1, Function *&FB2) {
|
||||
// Define FB1 in B.
|
||||
B.reset(createEmptyModule("B"));
|
||||
FB1 = insertAccumulateFunction(B.get(), nullptr, "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(std::unique_ptr<Module> &A, Function *&FA,
|
||||
std::unique_ptr<Module> &B, Function *&FB,
|
||||
std::unique_ptr<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(std::unique_ptr<Module> &A, Function *&FA,
|
||||
std::unique_ptr<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(std::unique_ptr<Module> &A, Function *&FA,
|
||||
std::unique_ptr<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(std::unique_ptr<Module> &A, Function *&FA,
|
||||
std::unique_ptr<Module> &B, Function *&FB,
|
||||
std::unique_ptr<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),
|
||||
CodeModel(CodeModel::Small), 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::mips64);
|
||||
SupportedArchs.push_back(Triple::mips64el);
|
||||
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");
|
||||
|
||||
UnsupportedEnvironments.push_back(Triple::Cygnus);
|
||||
}
|
||||
|
||||
void createJIT(std::unique_ptr<Module> M) {
|
||||
|
||||
// Due to the EngineBuilder constructor, it is required to have a Module
|
||||
// in order to construct an ExecutionEngine (i.e. MCJIT)
|
||||
assert(M != 0 && "a non-null Module must be provided to create MCJIT");
|
||||
|
||||
EngineBuilder EB(std::move(M));
|
||||
std::string Error;
|
||||
TheJIT.reset(EB.setEngineKind(EngineKind::JIT)
|
||||
.setMCJITMemoryManager(std::move(MM))
|
||||
.setErrorStr(&Error)
|
||||
.setOptLevel(CodeGenOpt::None)
|
||||
.setMArch(MArch)
|
||||
.setMCPU(sys::getHostCPUName())
|
||||
//.setMAttrs(MAttrs)
|
||||
.create());
|
||||
// At this point, we cannot modify the module any more.
|
||||
assert(TheJIT.get() != NULL && "error creating MCJIT with EngineBuilder");
|
||||
}
|
||||
|
||||
CodeGenOpt::Level OptLevel;
|
||||
CodeModel::Model CodeModel;
|
||||
StringRef MArch;
|
||||
SmallVector<std::string, 1> MAttrs;
|
||||
std::unique_ptr<ExecutionEngine> TheJIT;
|
||||
std::unique_ptr<RTDyldMemoryManager> MM;
|
||||
|
||||
std::unique_ptr<Module> M;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTBASE_H
|
@ -1 +0,0 @@
|
||||
EXPORTS
|
Reference in New Issue
Block a user