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 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, uintptr_t DataSizeRO, 92 uintptr_t DataSizeRW) override { 93 ReservedCodeSize = CodeSize; 94 ReservedDataSizeRO = DataSizeRO; 95 ReservedDataSizeRW = DataSizeRW; 96 } 97 98 void useSpace(uintptr_t* UsedSize, uintptr_t Size, unsigned Alignment) { 99 uintptr_t AlignedSize = (Size + Alignment - 1) / Alignment * Alignment; 100 uintptr_t AlignedBegin = (*UsedSize + Alignment - 1) / Alignment * Alignment; 101 *UsedSize = AlignedBegin + AlignedSize; 102 } 103 104 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 105 unsigned SectionID, StringRef SectionName, 106 bool IsReadOnly) override { 107 useSpace(IsReadOnly ? &UsedDataSizeRO : &UsedDataSizeRW, Size, Alignment); 108 return SectionMemoryManager::allocateDataSection(Size, Alignment, 109 SectionID, SectionName, IsReadOnly); 110 } 111 112 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, 113 unsigned SectionID, 114 StringRef SectionName) override { 115 useSpace(&UsedCodeSize, Size, Alignment); 116 return SectionMemoryManager::allocateCodeSection(Size, Alignment, 117 SectionID, SectionName); 118 } 119}; 120 121class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon { 122protected: 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 UnsupportedEnvironments.push_back(Triple::Cygnus); 143 } 144 145 void SetUp() override { 146 didCallAllocateCodeSection = false; 147 didAllocateCompactUnwindSection = false; 148 didCallYield = false; 149 Module = nullptr; 150 Function = nullptr; 151 Engine = nullptr; 152 Error = nullptr; 153 } 154 155 void TearDown() override { 156 if (Engine) 157 LLVMDisposeExecutionEngine(Engine); 158 else if (Module) 159 LLVMDisposeModule(Module); 160 } 161 162 void buildSimpleFunction() { 163 Module = LLVMModuleCreateWithName("simple_module"); 164 165 LLVMSetTarget(Module, HostTriple.c_str()); 166 167 Function = LLVMAddFunction(Module, "simple_function", 168 LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0)); 169 LLVMSetFunctionCallConv(Function, LLVMCCallConv); 170 171 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry"); 172 LLVMBuilderRef builder = LLVMCreateBuilder(); 173 LLVMPositionBuilderAtEnd(builder, entry); 174 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0)); 175 176 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 177 LLVMDisposeMessage(Error); 178 179 LLVMDisposeBuilder(builder); 180 } 181 182 void buildFunctionThatUsesStackmap() { 183 Module = LLVMModuleCreateWithName("simple_module"); 184 185 LLVMSetTarget(Module, HostTriple.c_str()); 186 187 LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() }; 188 LLVMValueRef stackmap = LLVMAddFunction( 189 Module, "llvm.experimental.stackmap", 190 LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1)); 191 LLVMSetLinkage(stackmap, LLVMExternalLinkage); 192 193 Function = LLVMAddFunction(Module, "simple_function", 194 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0)); 195 196 LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry"); 197 LLVMBuilderRef builder = LLVMCreateBuilder(); 198 LLVMPositionBuilderAtEnd(builder, entry); 199 LLVMValueRef stackmapArgs[] = { 200 LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0), 201 LLVMConstInt(LLVMInt32Type(), 42, 0) 202 }; 203 LLVMBuildCall(builder, stackmap, stackmapArgs, 3, ""); 204 LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0)); 205 206 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 207 LLVMDisposeMessage(Error); 208 209 LLVMDisposeBuilder(builder); 210 } 211 212 void buildModuleWithCodeAndData() { 213 Module = LLVMModuleCreateWithName("simple_module"); 214 215 LLVMSetTarget(Module, HostTriple.c_str()); 216 217 // build a global int32 variable initialized to 42. 218 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "intVal"); 219 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0)); 220 221 { 222 Function = LLVMAddFunction(Module, "getGlobal", 223 LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0)); 224 LLVMSetFunctionCallConv(Function, LLVMCCallConv); 225 226 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry"); 227 LLVMBuilderRef Builder = LLVMCreateBuilder(); 228 LLVMPositionBuilderAtEnd(Builder, Entry); 229 230 LLVMValueRef IntVal = LLVMBuildLoad(Builder, GlobalVar, "intVal"); 231 LLVMBuildRet(Builder, IntVal); 232 233 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 234 LLVMDisposeMessage(Error); 235 236 LLVMDisposeBuilder(Builder); 237 } 238 239 { 240 LLVMTypeRef ParamTypes[] = { LLVMInt32Type() }; 241 Function2 = LLVMAddFunction( 242 Module, "setGlobal", LLVMFunctionType(LLVMVoidType(), ParamTypes, 1, 0)); 243 LLVMSetFunctionCallConv(Function2, LLVMCCallConv); 244 245 LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function2, "entry"); 246 LLVMBuilderRef Builder = LLVMCreateBuilder(); 247 LLVMPositionBuilderAtEnd(Builder, Entry); 248 249 LLVMValueRef Arg = LLVMGetParam(Function2, 0); 250 LLVMBuildStore(Builder, Arg, GlobalVar); 251 LLVMBuildRetVoid(Builder); 252 253 LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error); 254 LLVMDisposeMessage(Error); 255 256 LLVMDisposeBuilder(Builder); 257 } 258 } 259 260 void buildMCJITOptions() { 261 LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options)); 262 Options.OptLevel = 2; 263 264 // Just ensure that this field still exists. 265 Options.NoFramePointerElim = false; 266 } 267 268 void useRoundTripSectionMemoryManager() { 269 Options.MCJMM = LLVMCreateSimpleMCJITMemoryManager( 270 new SectionMemoryManager(), 271 roundTripAllocateCodeSection, 272 roundTripAllocateDataSection, 273 roundTripFinalizeMemory, 274 roundTripDestroy); 275 } 276 277 void buildMCJITEngine() { 278 ASSERT_EQ( 279 0, LLVMCreateMCJITCompilerForModule(&Engine, Module, &Options, 280 sizeof(Options), &Error)); 281 } 282 283 void buildAndRunPasses() { 284 LLVMPassManagerRef pass = LLVMCreatePassManager(); 285 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), pass); 286 LLVMAddConstantPropagationPass(pass); 287 LLVMAddInstructionCombiningPass(pass); 288 LLVMRunPassManager(pass, Module); 289 LLVMDisposePassManager(pass); 290 } 291 292 void buildAndRunOptPasses() { 293 LLVMPassManagerBuilderRef passBuilder; 294 295 passBuilder = LLVMPassManagerBuilderCreate(); 296 LLVMPassManagerBuilderSetOptLevel(passBuilder, 2); 297 LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0); 298 299 LLVMPassManagerRef functionPasses = 300 LLVMCreateFunctionPassManagerForModule(Module); 301 LLVMPassManagerRef modulePasses = 302 LLVMCreatePassManager(); 303 304 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), modulePasses); 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 union { 342 void *raw; 343 int (*usable)(); 344 } functionPointer; 345 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); 346 347 EXPECT_EQ(42, functionPointer.usable()); 348} 349 350TEST_F(MCJITCAPITest, gva) { 351 SKIP_UNSUPPORTED_PLATFORM; 352 353 Module = LLVMModuleCreateWithName("simple_module"); 354 LLVMSetTarget(Module, HostTriple.c_str()); 355 LLVMValueRef GlobalVar = LLVMAddGlobal(Module, LLVMInt32Type(), "simple_value"); 356 LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0)); 357 358 buildMCJITOptions(); 359 buildMCJITEngine(); 360 buildAndRunPasses(); 361 362 uint64_t raw = LLVMGetGlobalValueAddress(Engine, "simple_value"); 363 int32_t *usable = (int32_t *) raw; 364 365 EXPECT_EQ(42, *usable); 366} 367 368TEST_F(MCJITCAPITest, gfa) { 369 SKIP_UNSUPPORTED_PLATFORM; 370 371 buildSimpleFunction(); 372 buildMCJITOptions(); 373 buildMCJITEngine(); 374 buildAndRunPasses(); 375 376 uint64_t raw = LLVMGetFunctionAddress(Engine, "simple_function"); 377 int (*usable)() = (int (*)()) raw; 378 379 EXPECT_EQ(42, usable()); 380} 381 382TEST_F(MCJITCAPITest, custom_memory_manager) { 383 SKIP_UNSUPPORTED_PLATFORM; 384 385 buildSimpleFunction(); 386 buildMCJITOptions(); 387 useRoundTripSectionMemoryManager(); 388 buildMCJITEngine(); 389 buildAndRunPasses(); 390 391 union { 392 void *raw; 393 int (*usable)(); 394 } functionPointer; 395 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); 396 397 EXPECT_EQ(42, functionPointer.usable()); 398 EXPECT_TRUE(didCallAllocateCodeSection); 399} 400 401TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) { 402 SKIP_UNSUPPORTED_PLATFORM; 403 404 // This test is also not supported on non-x86 platforms. 405 if (Triple(HostTriple).getArch() != Triple::x86_64) 406 return; 407 408 buildFunctionThatUsesStackmap(); 409 buildMCJITOptions(); 410 useRoundTripSectionMemoryManager(); 411 buildMCJITEngine(); 412 buildAndRunOptPasses(); 413 414 union { 415 void *raw; 416 int (*usable)(); 417 } functionPointer; 418 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); 419 420 EXPECT_EQ(42, functionPointer.usable()); 421 EXPECT_TRUE(didCallAllocateCodeSection); 422 423 // Up to this point, the test is specific only to X86-64. But this next 424 // expectation is only valid on Darwin because it assumes that unwind 425 // data is made available only through compact_unwind. It would be 426 // worthwhile to extend this to handle non-Darwin platforms, in which 427 // case you'd want to look for an eh_frame or something. 428 // 429 // FIXME: Currently, MCJIT relies on a configure-time check to determine which 430 // sections to emit. The JIT client should have runtime control over this. 431 EXPECT_TRUE( 432 Triple(HostTriple).getOS() != Triple::Darwin || 433 Triple(HostTriple).isMacOSXVersionLT(10, 7) || 434 didAllocateCompactUnwindSection); 435} 436 437TEST_F(MCJITCAPITest, reserve_allocation_space) { 438 SKIP_UNSUPPORTED_PLATFORM; 439 440 TestReserveAllocationSpaceMemoryManager* MM = new TestReserveAllocationSpaceMemoryManager(); 441 442 buildModuleWithCodeAndData(); 443 buildMCJITOptions(); 444 Options.MCJMM = wrap(MM); 445 buildMCJITEngine(); 446 buildAndRunPasses(); 447 448 union { 449 void *raw; 450 int (*usable)(); 451 } GetGlobalFct; 452 GetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function); 453 454 union { 455 void *raw; 456 void (*usable)(int); 457 } SetGlobalFct; 458 SetGlobalFct.raw = LLVMGetPointerToGlobal(Engine, Function2); 459 460 SetGlobalFct.usable(789); 461 EXPECT_EQ(789, GetGlobalFct.usable()); 462 EXPECT_LE(MM->UsedCodeSize, MM->ReservedCodeSize); 463 EXPECT_LE(MM->UsedDataSizeRO, MM->ReservedDataSizeRO); 464 EXPECT_LE(MM->UsedDataSizeRW, MM->ReservedDataSizeRW); 465 EXPECT_TRUE(MM->UsedCodeSize > 0); 466 EXPECT_TRUE(MM->UsedDataSizeRW > 0); 467} 468 469TEST_F(MCJITCAPITest, yield) { 470 SKIP_UNSUPPORTED_PLATFORM; 471 472 buildSimpleFunction(); 473 buildMCJITOptions(); 474 buildMCJITEngine(); 475 LLVMContextRef C = LLVMGetGlobalContext(); 476 LLVMContextSetYieldCallback(C, yield, nullptr); 477 buildAndRunPasses(); 478 479 union { 480 void *raw; 481 int (*usable)(); 482 } functionPointer; 483 functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); 484 485 EXPECT_EQ(42, functionPointer.usable()); 486 EXPECT_TRUE(didCallYield); 487} 488 489