1//===- MCJITTest.cpp - Unit tests for the MCJIT -----------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This test suite verifies basic MCJIT functionality when invoked form the C 11// API. 12// 13//===----------------------------------------------------------------------===// 14 15#include "llvm-c/Analysis.h" 16#include "MCJITTestAPICommon.h" 17#include "llvm-c/Core.h" 18#include "llvm-c/ExecutionEngine.h" 19#include "llvm-c/Target.h" 20#include "llvm-c/Transforms/PassManagerBuilder.h" 21#include "llvm-c/Transforms/Scalar.h" 22#include "llvm/ExecutionEngine/SectionMemoryManager.h" 23#include "llvm/Support/Debug.h" 24#include "llvm/Support/Host.h" 25#include "gtest/gtest.h" 26 27using namespace llvm; 28 29static bool didCallAllocateCodeSection; 30static bool didAllocateCompactUnwindSection; 31static bool didCallYield; 32 33static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size, 34 unsigned alignment, 35 unsigned sectionID, 36 const char *sectionName) { 37 didCallAllocateCodeSection = true; 38 return static_cast<SectionMemoryManager*>(object)->allocateCodeSection( 39 size, alignment, sectionID, sectionName); 40} 41 42static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size, 43 unsigned alignment, 44 unsigned sectionID, 45 const char *sectionName, 46 LLVMBool isReadOnly) { 47 if (!strcmp(sectionName, "__compact_unwind")) 48 didAllocateCompactUnwindSection = true; 49 return static_cast<SectionMemoryManager*>(object)->allocateDataSection( 50 size, alignment, sectionID, sectionName, isReadOnly); 51} 52 53static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) { 54 std::string errMsgString; 55 bool result = 56 static_cast<SectionMemoryManager*>(object)->finalizeMemory(&errMsgString); 57 if (result) { 58 *errMsg = LLVMCreateMessage(errMsgString.c_str()); 59 return 1; 60 } 61 return 0; 62} 63 64static void roundTripDestroy(void *object) { 65 delete static_cast<SectionMemoryManager*>(object); 66} 67 68static void yield(LLVMContextRef, void *) { 69 didCallYield = true; 70} 71 72namespace { 73 74// memory manager to test reserve allocation space callback 75class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager { 76public: 77 uintptr_t ReservedCodeSize; 78 uintptr_t UsedCodeSize; 79 uintptr_t ReservedDataSizeRO; 80 uintptr_t UsedDataSizeRO; 81 uintptr_t ReservedDataSizeRW; 82 uintptr_t UsedDataSizeRW; 83 84 TestReserveAllocationSpaceMemoryManager() : 85 ReservedCodeSize(0), UsedCodeSize(0), ReservedDataSizeRO(0), 86 UsedDataSizeRO(0), ReservedDataSizeRW(0), UsedDataSizeRW(0) { 87 } 88 89 bool needsToReserveAllocationSpace() override { return true; } 90 91 void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, 92 uintptr_t DataSizeRO, uint32_t RODataAlign, 93 uintptr_t DataSizeRW, uint32_t RWDataAlign) override { 94 ReservedCodeSize = CodeSize; 95 ReservedDataSizeRO = DataSizeRO; 96 ReservedDataSizeRW = DataSizeRW; 97 } 98 99 void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) { 100 uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment; 101 uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment; 102 *UsedSize = AlignedBegin + AlignedSize; 103 } 104 105 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 106 unsigned SectionID, StringRef SectionName, 107 bool IsReadOnly) override { 108 useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment); 109 return SectionMemoryManager::allocateDataSection(Size, Alignment, 110 SectionID, SectionName, IsReadOnly); 111 } 112 113 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, 114 unsigned SectionID, 115 StringRef SectionName) override { 116 useSpace(&UsedCodeSize, Size, Alignment); 117 return SectionMemoryManager::allocateCodeSection(Size, Alignment, 118 SectionID, SectionName); 119 } 120}; 121 122class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon { 123protected: 124 MCJITCAPITest() { 125 // The architectures below are known to be compatible with MCJIT as they 126 // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be 127 // kept in sync. 128 SupportedArchs.push_back(Triple::aarch64); 129 SupportedArchs.push_back(Triple::arm); 130 SupportedArchs.push_back(Triple::mips); 131 SupportedArchs.push_back(Triple::mips64); 132 SupportedArchs.push_back(Triple::mips64el); 133 SupportedArchs.push_back(Triple::x86); 134 SupportedArchs.push_back(Triple::x86_64); 135 136 // Some architectures have sub-architectures in which tests will fail, like 137 // ARM. These two vectors will define if they do have sub-archs (to avoid 138 // extra work for those who don't), and if so, if they are listed to work 139 HasSubArchs.push_back(Triple::arm); 140 SupportedSubArchs.push_back("armv6"); 141 SupportedSubArchs.push_back("armv7"); 142 143 // The operating systems below are known to be sufficiently incompatible 144 // that they will fail the MCJIT C API tests. 145 UnsupportedEnvironments.push_back(Triple::Cygnus); 146 } 147 148 void SetUp() override { 149 didCallAllocateCodeSection = false; 150 didAllocateCompactUnwindSection = false; 151 didCallYield = false; 152 Module = nullptr; 153 Function = nullptr; 154 Engine = nullptr; 155 Error = nullptr; 156 } 157 158 void TearDown() override { 159 if (Engine) 160 LLVMDisposeExecutionEngine(Engine); 161 else if (Module) 162 LLVMDisposeModule(Module); 163 } 164 165 void buildSimpleFunction() { 166 Module = LLVMModuleCreateWithName("simple_module"); 167 168 LLVMSetTarget(Module, HostTriple.c_str()); 169 170 Function = LLVMAddFunction(Module, "simple_function", 171 LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0)); 172 LLVMSetFunctionCallConv(Function, LLVMCCallConv); 173 174 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry"); 175 LLVMBuilderRef builder = LLVMCreateBuilder(); 176 LLVMPositionBuilderAtEnd(builder, entry); 177 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0)); 178 179 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 180 LLVMDisposeMessage(Error); 181 182 LLVMDisposeBuilder(builder); 183 } 184 185 void buildFunctionThatUsesStackmap() { 186 Module = LLVMModuleCreateWithName("simple_module"); 187 188 LLVMSetTarget(Module, HostTriple.c_str()); 189 190 LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() }; 191 LLVMValueRef stackmap = LLVMAddFunction( 192 Module, "llvm.experimental.stackmap", 193 LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1)); 194 LLVMSetLinkage(stackmap, LLVMExternalLinkage); 195 196 Function = LLVMAddFunction(Module, "simple_function", 197 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0)); 198 199 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry"); 200 LLVMBuilderRef builder = LLVMCreateBuilder(); 201 LLVMPositionBuilderAtEnd(builder, entry); 202 LLVMValueRef stackmapArgs[] = { 203 LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0), 204 LLVMConstInt(LLVMInt32Type(), 42, 0) 205 }; 206 LLVMBuildCall(builder, stackmap, stackmapArgs, 3, ""); 207 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0)); 208 209 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 210 LLVMDisposeMessage(Error); 211 212 LLVMDisposeBuilder(builder); 213 } 214 215 void buildModuleWithCodeAndData() { 216 Module = LLVMModuleCreateWithName("simple_module"); 217 218 LLVMSetTarget(Module, HostTriple.c_str()); 219 220 // build a global int32 variable initialized to 42. 221 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal"); 222 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0)); 223 224 { 225 Function = LLVMAddFunction(Module, "getGlobal", 226 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0)); 227 LLVMSetFunctionCallConv(Function, LLVMCCallConv); 228 229 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry"); 230 LLVMBuilderRef Builder = LLVMCreateBuilder(); 231 LLVMPositionBuilderAtEnd(Builder, Entry); 232 233 LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal"); 234 LLVMBuildRet(Builder, IntVal); 235 236 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 237 LLVMDisposeMessage(Error); 238 239 LLVMDisposeBuilder(Builder); 240 } 241 242 { 243 LLVMTypeRef ParamTypes[] = { LLVMInt32Type() }; 244 Function2 = LLVMAddFunction( 245 Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0)); 246 LLVMSetFunctionCallConv(Function2, LLVMCCallConv); 247 248 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry"); 249 LLVMBuilderRef Builder = LLVMCreateBuilder(); 250 LLVMPositionBuilderAtEnd(Builder, Entry); 251 252 LLVMValueRef Arg = LLVMGetParam(Function2, 0); 253 LLVMBuildStore(Builder, Arg, GlobalVar); 254 LLVMBuildRetVoid(Builder); 255 256 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 257 LLVMDisposeMessage(Error); 258 259 LLVMDisposeBuilder(Builder); 260 } 261 } 262 263 void buildMCJITOptions() { 264 LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options)); 265 Options.OptLevel = 2; 266 267 // Just ensure that this field still exists. 268 Options.NoFramePointerElim = false; 269 } 270 271 void useRoundTripSectionMemoryManager() { 272 Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager( 273 new SectionMemoryManager(), 274 roundTripAllocateCodeSection, 275 roundTripAllocateDataSection, 276 roundTripFinalizeMemory, 277 roundTripDestroy); 278 } 279 280 void buildMCJITEngine() { 281 ASSERT_EQ( 282 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options, 283 sizeof(Options), &Error)); 284 } 285 286 void buildAndRunPasses() { 287 LLVMPassManagerRef pass = LLVMCreatePassManager(); 288 LLVMAddConstantPropagationPass(pass); 289 LLVMAddInstructionCombiningPass(pass); 290 LLVMRunPassManager(pass, Module); 291 LLVMDisposePassManager(pass); 292 } 293 294 void buildAndRunOptPasses() { 295 LLVMPassManagerBuilderRef passBuilder; 296 297 passBuilder = LLVMPassManagerBuilderCreate(); 298 LLVMPassManagerBuilderSetOptLevel(passBuilder, 2); 299 LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0); 300 301 LLVMPassManagerRef functionPasses = 302 LLVMCreateFunctionPassManagerForModule(Module); 303 LLVMPassManagerRef modulePasses = 304 LLVMCreatePassManager(); 305 306 LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder, 307 functionPasses); 308 LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses); 309 310 LLVMPassManagerBuilderDispose(passBuilder); 311 312 LLVMInitializeFunctionPassManager(functionPasses); 313 for (LLVMValueRef value = LLVMGetFirstFunction(Module); 314 value; value = LLVMGetNextFunction(value)) 315 LLVMRunFunctionPassManager(functionPasses, value); 316 LLVMFinalizeFunctionPassManager(functionPasses); 317 318 LLVMRunPassManager(modulePasses, Module); 319 320 LLVMDisposePassManager(functionPasses); 321 LLVMDisposePassManager(modulePasses); 322 } 323 324 LLVMModuleRef Module; 325 LLVMValueRef Function; 326 LLVMValueRef Function2; 327 LLVMMCJITCompilerOptions Options; 328 LLVMExecutionEngineRef Engine; 329 char *Error; 330}; 331} // end anonymous namespace 332 333TEST_F(MCJITCAPITest, simple_function) { 334 SKIP_UNSUPPORTED_PLATFORM; 335 336 buildSimpleFunction(); 337 buildMCJITOptions(); 338 buildMCJITEngine(); 339 buildAndRunPasses(); 340 341 auto *functionPointer = reinterpret_cast<int (*)()>( 342 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function))); 343 344 EXPECT_EQ(42, functionPointer()); 345} 346 347TEST_F(MCJITCAPITest, gva) { 348 SKIP_UNSUPPORTED_PLATFORM; 349 350 Module = LLVMModuleCreateWithName("simple_module"); 351 LLVMSetTarget(Module, HostTriple.c_str()); 352 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "simple_value"); 353 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0)); 354 355 buildMCJITOptions(); 356 buildMCJITEngine(); 357 buildAndRunPasses(); 358 359 uint64_t raw = LLVMGetGlobalValueAddress(Engine, "simple_value"); 360 int32_t *usable = (int32_t *) raw; 361 362 EXPECT_EQ(42, *usable); 363} 364 365TEST_F(MCJITCAPITest, gfa) { 366 SKIP_UNSUPPORTED_PLATFORM; 367 368 buildSimpleFunction(); 369 buildMCJITOptions(); 370 buildMCJITEngine(); 371 buildAndRunPasses(); 372 373 uint64_t raw = LLVMGetFunctionAddress(Engine, "simple_function"); 374 int (*usable)() = (int (*)()) raw; 375 376 EXPECT_EQ(42, usable()); 377} 378 379TEST_F(MCJITCAPITest, custom_memory_manager) { 380 SKIP_UNSUPPORTED_PLATFORM; 381 382 buildSimpleFunction(); 383 buildMCJITOptions(); 384 useRoundTripSectionMemoryManager(); 385 buildMCJITEngine(); 386 buildAndRunPasses(); 387 388 auto *functionPointer = reinterpret_cast<int (*)()>( 389 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function))); 390 391 EXPECT_EQ(42, functionPointer()); 392 EXPECT_TRUE(didCallAllocateCodeSection); 393} 394 395TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) { 396 SKIP_UNSUPPORTED_PLATFORM; 397 398 // This test is also not supported on non-x86 platforms. 399 if (Triple(HostTriple).getArch() != Triple::x86_64) 400 return; 401 402 buildFunctionThatUsesStackmap(); 403 buildMCJITOptions(); 404 useRoundTripSectionMemoryManager(); 405 buildMCJITEngine(); 406 buildAndRunOptPasses(); 407 408 auto *functionPointer = reinterpret_cast<int (*)()>( 409 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function))); 410 411 EXPECT_EQ(42, functionPointer()); 412 EXPECT_TRUE(didCallAllocateCodeSection); 413 414 // Up to this point, the test is specific only to X86-64. But this next 415 // expectation is only valid on Darwin because it assumes that unwind 416 // data is made available only through compact_unwind. It would be 417 // worthwhile to extend this to handle non-Darwin platforms, in which 418 // case you'd want to look for an eh_frame or something. 419 // 420 // FIXME: Currently, MCJIT relies on a configure-time check to determine which 421 // sections to emit. The JIT client should have runtime control over this. 422 EXPECT_TRUE( 423 Triple(HostTriple).getOS() != Triple::Darwin || 424 Triple(HostTriple).isMacOSXVersionLT(10, 7) || 425 didAllocateCompactUnwindSection); 426} 427 428TEST_F(MCJITCAPITest, reserve_allocation_space) { 429 SKIP_UNSUPPORTED_PLATFORM; 430 431 TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager(); 432 433 buildModuleWithCodeAndData(); 434 buildMCJITOptions(); 435 Options.MCJMM = wrap(MM); 436 buildMCJITEngine(); 437 buildAndRunPasses(); 438 439 auto GetGlobalFct = reinterpret_cast<int (*)()>( 440 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function))); 441 442 auto SetGlobalFct = reinterpret_cast<void (*)(int)>( 443 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function2))); 444 445 SetGlobalFct(789); 446 EXPECT_EQ(789, GetGlobalFct()); 447 EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize); 448 EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO); 449 EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW); 450 EXPECT_TRUE(MM->UsedCodeSize > 0); 451 EXPECT_TRUE(MM->UsedDataSizeRW > 0); 452} 453 454TEST_F(MCJITCAPITest, yield) { 455 SKIP_UNSUPPORTED_PLATFORM; 456 457 buildSimpleFunction(); 458 buildMCJITOptions(); 459 buildMCJITEngine(); 460 LLVMContextRef C = LLVMGetGlobalContext(); 461 LLVMContextSetYieldCallback(C, yield, nullptr); 462 buildAndRunPasses(); 463 464 auto *functionPointer = reinterpret_cast<int (*)()>( 465 reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(Engine, Function))); 466 467 EXPECT_EQ(42, functionPointer()); 468 EXPECT_TRUE(didCallYield); 469} 470 471static int localTestFunc() { 472 return 42; 473} 474 475TEST_F(MCJITCAPITest, addGlobalMapping) { 476 SKIP_UNSUPPORTED_PLATFORM; 477 478 Module = LLVMModuleCreateWithName("testModule"); 479 LLVMSetTarget(Module, HostTriple.c_str()); 480 LLVMTypeRef FunctionType = LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0); 481 LLVMValueRef MappedFn = LLVMAddFunction(Module, "mapped_fn", FunctionType); 482 483 Function = LLVMAddFunction(Module, "test_fn", FunctionType); 484 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, ""); 485 LLVMBuilderRef Builder = LLVMCreateBuilder(); 486 LLVMPositionBuilderAtEnd(Builder, Entry); 487 LLVMValueRef RetVal = LLVMBuildCall(Builder, MappedFn, nullptr, 0, ""); 488 LLVMBuildRet(Builder, RetVal); 489 LLVMDisposeBuilder(Builder); 490 491 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 492 LLVMDisposeMessage(Error); 493 494 buildMCJITOptions(); 495 buildMCJITEngine(); 496 497 LLVMAddGlobalMapping( 498 Engine, MappedFn, 499 reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(&localTestFunc))); 500 501 buildAndRunPasses(); 502 503 uint64_t raw = LLVMGetFunctionAddress(Engine, "test_fn"); 504 int (*usable)() = (int (*)()) raw; 505 506 EXPECT_EQ(42, usable()); 507} 508