//===- MCJITTest.cpp - Unit tests for the MCJIT ---------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This test suite verifies basic MCJIT functionality when invoked form the C // API. // //===----------------------------------------------------------------------===// #include "llvm-c/Analysis.h" #include "llvm-c/Core.h" #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Target.h" #include "llvm-c/Transforms/Scalar.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/Support/Host.h" #include "MCJITTestAPICommon.h" #include "gtest/gtest.h" using namespace llvm; static bool didCallAllocateCodeSection; static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size, unsigned alignment, unsigned sectionID, const char *sectionName) { didCallAllocateCodeSection = true; return static_cast(object)->allocateCodeSection( size, alignment, sectionID, sectionName); } static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size, unsigned alignment, unsigned sectionID, const char *sectionName, LLVMBool isReadOnly) { return static_cast(object)->allocateDataSection( size, alignment, sectionID, sectionName, isReadOnly); } static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) { std::string errMsgString; bool result = static_cast(object)->finalizeMemory(&errMsgString); if (result) { *errMsg = LLVMCreateMessage(errMsgString.c_str()); return 1; } return 0; } static void roundTripDestroy(void *object) { delete static_cast(object); } class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon { protected: MCJITCAPITest() { // The architectures below are known to be compatible with MCJIT as they // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be // kept in sync. SupportedArchs.push_back(Triple::aarch64); SupportedArchs.push_back(Triple::arm); SupportedArchs.push_back(Triple::mips); SupportedArchs.push_back(Triple::x86); SupportedArchs.push_back(Triple::x86_64); // Some architectures have sub-architectures in which tests will fail, like // ARM. These two vectors will define if they do have sub-archs (to avoid // extra work for those who don't), and if so, if they are listed to work HasSubArchs.push_back(Triple::arm); SupportedSubArchs.push_back("armv6"); SupportedSubArchs.push_back("armv7"); // The operating systems below are known to be sufficiently incompatible // that they will fail the MCJIT C API tests. UnsupportedOSs.push_back(Triple::Cygwin); } virtual void SetUp(); virtual void TearDown() { if (Engine) LLVMDisposeExecutionEngine(Engine); else if (Module) LLVMDisposeModule(Module); } void buildSimpleFunction() { Module = LLVMModuleCreateWithName("simple_module"); LLVMSetTarget(Module, HostTriple.c_str()); Function = LLVMAddFunction( Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0)); LLVMSetFunctionCallConv(Function, LLVMCCallConv); LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry"); LLVMBuilderRef builder = LLVMCreateBuilder(); LLVMPositionBuilderAtEnd(builder, entry); LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0)); LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); LLVMDisposeMessage(Error); LLVMDisposeBuilder(builder); } void buildMCJITOptions() { LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options)); Options.OptLevel = 2; // Just ensure that this field still exists. Options.NoFramePointerElim = false; } void useRoundTripSectionMemoryManager() { Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager( new SectionMemoryManager(), roundTripAllocateCodeSection, roundTripAllocateDataSection, roundTripFinalizeMemory, roundTripDestroy); } void buildMCJITEngine() { ASSERT_EQ( 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options, sizeof(Options), &Error)); } void buildAndRunPasses() { LLVMPassManagerRef pass = LLVMCreatePassManager(); LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass); LLVMAddConstantPropagationPass(pass); LLVMAddInstructionCombiningPass(pass); LLVMRunPassManager(pass, Module); LLVMDisposePassManager(pass); } LLVMModuleRef Module; LLVMValueRef Function; LLVMMCJITCompilerOptions Options; LLVMExecutionEngineRef Engine; char *Error; }; // Provide out-of-line definition to prevent weak vtable. void MCJITCAPITest::SetUp() { didCallAllocateCodeSection = false; Module = 0; Function = 0; Engine = 0; Error = 0; } TEST_F(MCJITCAPITest, simple_function) { SKIP_UNSUPPORTED_PLATFORM; buildSimpleFunction(); buildMCJITOptions(); buildMCJITEngine(); buildAndRunPasses(); union { void *raw; int (*usable)(); } functionPointer; functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); EXPECT_EQ(42, functionPointer.usable()); } TEST_F(MCJITCAPITest, custom_memory_manager) { SKIP_UNSUPPORTED_PLATFORM; buildSimpleFunction(); buildMCJITOptions(); useRoundTripSectionMemoryManager(); buildMCJITEngine(); buildAndRunPasses(); union { void *raw; int (*usable)(); } functionPointer; functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); EXPECT_EQ(42, functionPointer.usable()); EXPECT_TRUE(didCallAllocateCodeSection); }