1 //===- MCJITTest.cpp - Unit tests for the MCJIT ---------------------------===// 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 27 using namespace llvm; 28 29 static bool didCallAllocateCodeSection; 30 static bool didAllocateCompactUnwindSection; 31 static bool didCallYield; 32 33 static 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 42 static 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 53 static 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 64 static void roundTripDestroy(void *object) { 65 delete static_cast<SectionMemoryManager*>(object); 66 } 67 68 static void yield(LLVMContextRef, void *) { 69 didCallYield = true; 70 } 71 72 namespace { 73 74 // memory manager to test reserve allocation space callback 75 class TestReserveAllocationSpaceMemoryManager: public SectionMemoryManager { 76 public: 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 virtual bool needsToReserveAllocationSpace() { 90 return true; 91 } 92 93 virtual void reserveAllocationSpace( 94 uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) { 95 ReservedCodeSize = CodeSize; 96 ReservedDataSizeRO = DataSizeRO; 97 ReservedDataSizeRW = DataSizeRW; 98 } 99 100 void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) { 101 uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment; 102 uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment; 103 *UsedSize = AlignedBegin + AlignedSize; 104 } 105 106 virtual uint8_t* allocateDataSection(uintptr_t Size, unsigned Alignment, 107 unsigned SectionID, StringRef SectionName, bool IsReadOnly) { 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, StringRef SectionName) { 115 useSpace(&UsedCodeSize, Size, Alignment); 116 return SectionMemoryManager::allocateCodeSection(Size, Alignment, 117 SectionID, SectionName); 118 } 119 }; 120 121 class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon { 122 protected: 123 MCJITCAPITest() { 124 // The architectures below are known to be compatible with MCJIT as they 125 // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be 126 // kept in sync. 127 SupportedArchs.push_back(Triple::aarch64); 128 SupportedArchs.push_back(Triple::arm); 129 SupportedArchs.push_back(Triple::mips); 130 SupportedArchs.push_back(Triple::x86); 131 SupportedArchs.push_back(Triple::x86_64); 132 133 // Some architectures have sub-architectures in which tests will fail, like 134 // ARM. These two vectors will define if they do have sub-archs (to avoid 135 // extra work for those who don't), and if so, if they are listed to work 136 HasSubArchs.push_back(Triple::arm); 137 SupportedSubArchs.push_back("armv6"); 138 SupportedSubArchs.push_back("armv7"); 139 140 // The operating systems below are known to be sufficiently incompatible 141 // that they will fail the MCJIT C API tests. 142 UnsupportedOSs.push_back(Triple::Cygwin); 143 144 UnsupportedEnvironments.push_back(Triple::Cygnus); 145 } 146 147 virtual void SetUp() { 148 didCallAllocateCodeSection = false; 149 didAllocateCompactUnwindSection = false; 150 didCallYield = false; 151 Module = nullptr; 152 Function = nullptr; 153 Engine = nullptr; 154 Error = nullptr; 155 } 156 157 virtual void TearDown() { 158 if (Engine) 159 LLVMDisposeExecutionEngine(Engine); 160 else if (Module) 161 LLVMDisposeModule(Module); 162 } 163 164 void buildSimpleFunction() { 165 Module = LLVMModuleCreateWithName("simple_module"); 166 167 LLVMSetTarget(Module, HostTriple.c_str()); 168 169 Function = LLVMAddFunction(Module, "simple_function", 170 LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0)); 171 LLVMSetFunctionCallConv(Function, LLVMCCallConv); 172 173 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry"); 174 LLVMBuilderRef builder = LLVMCreateBuilder(); 175 LLVMPositionBuilderAtEnd(builder, entry); 176 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0)); 177 178 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 179 LLVMDisposeMessage(Error); 180 181 LLVMDisposeBuilder(builder); 182 } 183 184 void buildFunctionThatUsesStackmap() { 185 Module = LLVMModuleCreateWithName("simple_module"); 186 187 LLVMSetTarget(Module, HostTriple.c_str()); 188 189 LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() }; 190 LLVMValueRef stackmap = LLVMAddFunction( 191 Module, "llvm.experimental.stackmap", 192 LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1)); 193 LLVMSetLinkage(stackmap, LLVMExternalLinkage); 194 195 Function = LLVMAddFunction(Module, "simple_function", 196 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0)); 197 198 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry"); 199 LLVMBuilderRef builder = LLVMCreateBuilder(); 200 LLVMPositionBuilderAtEnd(builder, entry); 201 LLVMValueRef stackmapArgs[] = { 202 LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0), 203 LLVMConstInt(LLVMInt32Type(), 42, 0) 204 }; 205 LLVMBuildCall(builder, stackmap, stackmapArgs, 3, ""); 206 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0)); 207 208 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 209 LLVMDisposeMessage(Error); 210 211 LLVMDisposeBuilder(builder); 212 } 213 214 void buildModuleWithCodeAndData() { 215 Module = LLVMModuleCreateWithName("simple_module"); 216 217 LLVMSetTarget(Module, HostTriple.c_str()); 218 219 // build a global int32 variable initialized to 42. 220 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal"); 221 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0)); 222 223 { 224 Function = LLVMAddFunction(Module, "getGlobal", 225 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0)); 226 LLVMSetFunctionCallConv(Function, LLVMCCallConv); 227 228 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry"); 229 LLVMBuilderRef Builder = LLVMCreateBuilder(); 230 LLVMPositionBuilderAtEnd(Builder, Entry); 231 232 LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal"); 233 LLVMBuildRet(Builder, IntVal); 234 235 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 236 LLVMDisposeMessage(Error); 237 238 LLVMDisposeBuilder(Builder); 239 } 240 241 { 242 LLVMTypeRef ParamTypes[] = { LLVMInt32Type() }; 243 Function2 = LLVMAddFunction( 244 Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0)); 245 LLVMSetFunctionCallConv(Function2, LLVMCCallConv); 246 247 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry"); 248 LLVMBuilderRef Builder = LLVMCreateBuilder(); 249 LLVMPositionBuilderAtEnd(Builder, Entry); 250 251 LLVMValueRef Arg = LLVMGetParam(Function2, 0); 252 LLVMBuildStore(Builder, Arg, GlobalVar); 253 LLVMBuildRetVoid(Builder); 254 255 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 256 LLVMDisposeMessage(Error); 257 258 LLVMDisposeBuilder(Builder); 259 } 260 } 261 262 void buildMCJITOptions() { 263 LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options)); 264 Options.OptLevel = 2; 265 266 // Just ensure that this field still exists. 267 Options.NoFramePointerElim = false; 268 } 269 270 void useRoundTripSectionMemoryManager() { 271 Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager( 272 new SectionMemoryManager(), 273 roundTripAllocateCodeSection, 274 roundTripAllocateDataSection, 275 roundTripFinalizeMemory, 276 roundTripDestroy); 277 } 278 279 void buildMCJITEngine() { 280 ASSERT_EQ( 281 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options, 282 sizeof(Options), &Error)); 283 } 284 285 void buildAndRunPasses() { 286 LLVMPassManagerRef pass = LLVMCreatePassManager(); 287 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass); 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 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), modulePasses); 307 308 LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder, 309 functionPasses); 310 LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses); 311 312 LLVMPassManagerBuilderDispose(passBuilder); 313 314 LLVMInitializeFunctionPassManager(functionPasses); 315 for (LLVMValueRef value = LLVMGetFirstFunction(Module); 316 value; value = LLVMGetNextFunction(value)) 317 LLVMRunFunctionPassManager(functionPasses, value); 318 LLVMFinalizeFunctionPassManager(functionPasses); 319 320 LLVMRunPassManager(modulePasses, Module); 321 322 LLVMDisposePassManager(functionPasses); 323 LLVMDisposePassManager(modulePasses); 324 } 325 326 LLVMModuleRef Module; 327 LLVMValueRef Function; 328 LLVMValueRef Function2; 329 LLVMMCJITCompilerOptions Options; 330 LLVMExecutionEngineRef Engine; 331 char *Error; 332 }; 333 } // end anonymous namespace 334 335 TEST_F(MCJITCAPITest, simple_function) { 336 SKIP_UNSUPPORTED_PLATFORM; 337 338 buildSimpleFunction(); 339 buildMCJITOptions(); 340 buildMCJITEngine(); 341 buildAndRunPasses(); 342 343 union { 344 void *raw; 345 int (*usable)(); 346 } functionPointer; 347 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); 348 349 EXPECT_EQ(42, functionPointer.usable()); 350 } 351 352 TEST_F(MCJITCAPITest, custom_memory_manager) { 353 SKIP_UNSUPPORTED_PLATFORM; 354 355 buildSimpleFunction(); 356 buildMCJITOptions(); 357 useRoundTripSectionMemoryManager(); 358 buildMCJITEngine(); 359 buildAndRunPasses(); 360 361 union { 362 void *raw; 363 int (*usable)(); 364 } functionPointer; 365 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); 366 367 EXPECT_EQ(42, functionPointer.usable()); 368 EXPECT_TRUE(didCallAllocateCodeSection); 369 } 370 371 TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) { 372 SKIP_UNSUPPORTED_PLATFORM; 373 374 // This test is also not supported on non-x86 platforms. 375 if (Triple(HostTriple).getArch() != Triple::x86_64) 376 return; 377 378 buildFunctionThatUsesStackmap(); 379 buildMCJITOptions(); 380 useRoundTripSectionMemoryManager(); 381 buildMCJITEngine(); 382 buildAndRunOptPasses(); 383 384 union { 385 void *raw; 386 int (*usable)(); 387 } functionPointer; 388 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); 389 390 EXPECT_EQ(42, functionPointer.usable()); 391 EXPECT_TRUE(didCallAllocateCodeSection); 392 393 // Up to this point, the test is specific only to X86-64. But this next 394 // expectation is only valid on Darwin because it assumes that unwind 395 // data is made available only through compact_unwind. It would be 396 // worthwhile to extend this to handle non-Darwin platforms, in which 397 // case you'd want to look for an eh_frame or something. 398 // 399 // FIXME: Currently, MCJIT relies on a configure-time check to determine which 400 // sections to emit. The JIT client should have runtime control over this. 401 EXPECT_TRUE( 402 Triple(HostTriple).getOS() != Triple::Darwin || 403 Triple(HostTriple).isMacOSXVersionLT(10, 7) || 404 didAllocateCompactUnwindSection); 405 } 406 407 TEST_F(MCJITCAPITest, reserve_allocation_space) { 408 SKIP_UNSUPPORTED_PLATFORM; 409 410 TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager(); 411 412 buildModuleWithCodeAndData(); 413 buildMCJITOptions(); 414 Options.MCJMM = wrap(MM); 415 buildMCJITEngine(); 416 buildAndRunPasses(); 417 418 union { 419 void *raw; 420 int (*usable)(); 421 } GetGlobalFct; 422 GetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function); 423 424 union { 425 void *raw; 426 void (*usable)(int); 427 } SetGlobalFct; 428 SetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function2); 429 430 SetGlobalFct.usable(789); 431 EXPECT_EQ(789, GetGlobalFct.usable()); 432 EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize); 433 EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO); 434 EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW); 435 EXPECT_TRUE(MM->UsedCodeSize > 0); 436 EXPECT_TRUE(MM->UsedDataSizeRW > 0); 437 } 438 439 TEST_F(MCJITCAPITest, yield) { 440 SKIP_UNSUPPORTED_PLATFORM; 441 442 buildSimpleFunction(); 443 buildMCJITOptions(); 444 buildMCJITEngine(); 445 LLVMContextRef C = LLVMGetGlobalContext(); 446 LLVMContextSetYieldCallback(C, yield, nullptr); 447 buildAndRunPasses(); 448 449 union { 450 void *raw; 451 int (*usable)(); 452 } functionPointer; 453 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); 454 455 EXPECT_EQ(42, functionPointer.usable()); 456 EXPECT_TRUE(didCallYield); 457 } 458 459