1 //===--- OrcCAPITest.cpp - Unit tests for the OrcJIT v2 C API ---*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm-c/Core.h" 10 #include "llvm-c/Error.h" 11 #include "llvm-c/LLJIT.h" 12 #include "llvm-c/LLJITUtils.h" 13 #include "llvm-c/Orc.h" 14 #include "gtest/gtest.h" 15 16 #include "llvm/Analysis/TargetLibraryInfo.h" 17 #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 18 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" 19 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" 20 #include "llvm/IR/LLVMContext.h" 21 #include "llvm/IR/Module.h" 22 #include "llvm/IRReader/IRReader.h" 23 #include "llvm/Support/Error.h" 24 #include "llvm/Support/FormatVariadic.h" 25 #include "llvm/Support/SourceMgr.h" 26 #include "llvm/TargetParser/Triple.h" 27 #include "llvm/Testing/Support/Error.h" 28 #include <string> 29 30 using namespace llvm; 31 using namespace llvm::orc; 32 33 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectLayer, LLVMOrcObjectLayerRef) 34 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef) 35 36 // A class that sets strings for extension attributes by querying 37 // TargetLibraryInfo. 38 struct TargetI32ArgExtensions { 39 std::string Ret; 40 std::string Arg; 41 TargetI32ArgExtensions(std::string TargetTriple, bool Signed = true) { 42 Triple T(TargetTriple); 43 if (auto AK = TargetLibraryInfo::getExtAttrForI32Return(T, Signed)) 44 Ret = Attribute::getNameFromAttrKind(AK).str() + " "; 45 if (auto AK = TargetLibraryInfo::getExtAttrForI32Param(T, Signed)) 46 Arg = Attribute::getNameFromAttrKind(AK).str() + " "; 47 } 48 }; 49 50 // OrcCAPITestBase contains several helper methods and pointers for unit tests 51 // written for the LLVM-C API. It provides the following helpers: 52 // 53 // 1. Jit: an LLVMOrcLLJIT instance which is freed upon test exit 54 // 2. ExecutionSession: the LLVMOrcExecutionSession for the JIT 55 // 3. MainDylib: the main JITDylib for the LLJIT instance 56 // 4. materializationUnitFn: function pointer to an empty function, used for 57 // materialization unit testing 58 // 5. definitionGeneratorFn: function pointer for a basic 59 // LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction 60 // 6. createTestModule: helper method for creating a basic thread-safe-module 61 class OrcCAPITestBase : public testing::Test { 62 protected: 63 LLVMOrcLLJITRef Jit = nullptr; 64 LLVMOrcExecutionSessionRef ExecutionSession = nullptr; 65 LLVMOrcJITDylibRef MainDylib = nullptr; 66 67 public: 68 static void SetUpTestCase() { 69 LLVMInitializeNativeTarget(); 70 LLVMInitializeNativeAsmParser(); 71 LLVMInitializeNativeAsmPrinter(); 72 73 // Attempt to set up a JIT instance once to verify that we can. 74 LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr; 75 if (LLVMErrorRef E = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB)) { 76 // If setup fails then disable these tests. 77 LLVMConsumeError(E); 78 TargetSupported = false; 79 return; 80 } 81 82 // Capture the target triple. We'll use it for both verification that 83 // this target is *supposed* to be supported, and error messages in 84 // the case that it fails anyway. 85 char *TT = LLVMOrcJITTargetMachineBuilderGetTargetTriple(JTMB); 86 TargetTriple = TT; 87 LLVMDisposeMessage(TT); 88 89 if (!isSupported(TargetTriple)) { 90 // If this triple isn't supported then bail out. 91 TargetSupported = false; 92 LLVMOrcDisposeJITTargetMachineBuilder(JTMB); 93 return; 94 } 95 96 LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder(); 97 LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB); 98 LLVMOrcLLJITRef J; 99 if (LLVMErrorRef E = LLVMOrcCreateLLJIT(&J, Builder)) { 100 // If setup fails then disable these tests. 101 TargetSupported = false; 102 LLVMConsumeError(E); 103 return; 104 } 105 106 LLVMOrcDisposeLLJIT(J); 107 TargetSupported = true; 108 109 // Create test functions in text format, with the proper extension 110 // attributes. 111 if (SumExample.empty()) { 112 TargetI32ArgExtensions ArgExt(TargetTriple); 113 std::ostringstream OS; 114 OS << "define " << ArgExt.Ret << "i32 " 115 << "@sum(i32 " << ArgExt.Arg << "%x, i32 " << ArgExt.Arg << "%y)" 116 << R"( { 117 entry: 118 %r = add nsw i32 %x, %y 119 ret i32 %r 120 } 121 )"; 122 SumExample = OS.str(); 123 124 OS << R"( 125 !llvm.module.flags = !{!0} 126 !llvm.dbg.cu = !{!1} 127 !0 = !{i32 2, !"Debug Info Version", i32 3} 128 !1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, emissionKind: FullDebug) 129 !2 = !DIFile(filename: "sum.c", directory: "/tmp") 130 )"; 131 SumDebugExample = OS.str(); 132 } 133 } 134 135 void SetUp() override { 136 if (!TargetSupported) 137 GTEST_SKIP(); 138 139 LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr; 140 LLVMErrorRef E1 = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB); 141 assert(E1 == LLVMErrorSuccess && "Expected call to detect host to succeed"); 142 (void)E1; 143 144 LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder(); 145 LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB); 146 LLVMErrorRef E2 = LLVMOrcCreateLLJIT(&Jit, Builder); 147 assert(E2 == LLVMErrorSuccess && 148 "Expected call to create LLJIT to succeed"); 149 (void)E2; 150 ExecutionSession = LLVMOrcLLJITGetExecutionSession(Jit); 151 MainDylib = LLVMOrcLLJITGetMainJITDylib(Jit); 152 } 153 void TearDown() override { 154 // Check whether Jit has already been torn down -- we allow clients to do 155 // this manually to check teardown behavior. 156 if (Jit) { 157 LLVMOrcDisposeLLJIT(Jit); 158 Jit = nullptr; 159 } 160 } 161 162 protected: 163 static bool isSupported(StringRef Triple) { 164 // TODO: Print error messages in failure logs, use them to audit this list. 165 // Some architectures may be unsupportable or missing key components, but 166 // some may just be failing due to bugs in this testcase. 167 if (Triple.starts_with("armv7") || Triple.starts_with("armv8l")) 168 return false; 169 return true; 170 } 171 172 static void materializationUnitFn() {} 173 174 // Stub definition generator, where all Names are materialized from the 175 // materializationUnitFn() test function and defined into the JIT Dylib 176 static LLVMErrorRef 177 definitionGeneratorFn(LLVMOrcDefinitionGeneratorRef G, void *Ctx, 178 LLVMOrcLookupStateRef *LS, LLVMOrcLookupKind K, 179 LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags F, 180 LLVMOrcCLookupSet Names, size_t NamesCount) { 181 for (size_t I = 0; I < NamesCount; I++) { 182 LLVMOrcCLookupSetElement Element = Names[I]; 183 LLVMOrcJITTargetAddress Addr = 184 (LLVMOrcJITTargetAddress)(&materializationUnitFn); 185 LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0}; 186 LLVMJITEvaluatedSymbol Sym = {Addr, Flags}; 187 LLVMOrcRetainSymbolStringPoolEntry(Element.Name); 188 LLVMOrcCSymbolMapPair Pair = {Element.Name, Sym}; 189 LLVMOrcCSymbolMapPair Pairs[] = {Pair}; 190 LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1); 191 LLVMErrorRef Err = LLVMOrcJITDylibDefine(JD, MU); 192 if (Err) 193 return Err; 194 } 195 return LLVMErrorSuccess; 196 } 197 198 static Error createSMDiagnosticError(llvm::SMDiagnostic &Diag) { 199 std::string Msg; 200 { 201 raw_string_ostream OS(Msg); 202 Diag.print("", OS); 203 } 204 return make_error<StringError>(std::move(Msg), inconvertibleErrorCode()); 205 } 206 207 // Create an LLVM IR module from the given StringRef. 208 static Expected<std::unique_ptr<Module>> 209 parseTestModule(LLVMContext &Ctx, StringRef Source, StringRef Name) { 210 assert(TargetSupported && 211 "Attempted to create module for unsupported target"); 212 SMDiagnostic Err; 213 if (auto M = parseIR(MemoryBufferRef(Source, Name), Err, Ctx)) 214 return std::move(M); 215 return createSMDiagnosticError(Err); 216 } 217 218 // returns the sum of its two parameters 219 static LLVMOrcThreadSafeModuleRef createTestModule(StringRef Source, 220 StringRef Name) { 221 auto Ctx = std::make_unique<LLVMContext>(); 222 auto M = cantFail(parseTestModule(*Ctx, Source, Name)); 223 return wrap(new ThreadSafeModule(std::move(M), std::move(Ctx))); 224 } 225 226 static LLVMMemoryBufferRef createTestObject(StringRef Source, 227 StringRef Name) { 228 auto Ctx = std::make_unique<LLVMContext>(); 229 auto M = cantFail(parseTestModule(*Ctx, Source, Name)); 230 231 auto JTMB = cantFail(JITTargetMachineBuilder::detectHost()); 232 M->setDataLayout(cantFail(JTMB.getDefaultDataLayoutForTarget())); 233 auto TM = cantFail(JTMB.createTargetMachine()); 234 235 SimpleCompiler SC(*TM); 236 auto ObjBuffer = cantFail(SC(*M)); 237 return wrap(ObjBuffer.release()); 238 } 239 240 static std::string TargetTriple; 241 static bool TargetSupported; 242 243 static std::string SumExample; 244 static std::string SumDebugExample; 245 }; 246 247 std::string OrcCAPITestBase::TargetTriple; 248 bool OrcCAPITestBase::TargetSupported = false; 249 250 std::string OrcCAPITestBase::SumExample; 251 std::string OrcCAPITestBase::SumDebugExample; 252 253 // Consumes the given error ref and returns the string error message. 254 static std::string toString(LLVMErrorRef E) { 255 char *ErrMsg = LLVMGetErrorMessage(E); 256 std::string Result(ErrMsg); 257 LLVMDisposeErrorMessage(ErrMsg); 258 return Result; 259 } 260 261 TEST_F(OrcCAPITestBase, SymbolStringPoolUniquing) { 262 LLVMOrcSymbolStringPoolEntryRef E1 = 263 LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa"); 264 LLVMOrcSymbolStringPoolEntryRef E2 = 265 LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa"); 266 LLVMOrcSymbolStringPoolEntryRef E3 = 267 LLVMOrcExecutionSessionIntern(ExecutionSession, "bbb"); 268 const char *SymbolName = LLVMOrcSymbolStringPoolEntryStr(E1); 269 ASSERT_EQ(E1, E2) << "String pool entries are not unique"; 270 ASSERT_NE(E1, E3) << "Unique symbol pool entries are equal"; 271 ASSERT_STREQ("aaa", SymbolName) << "String value of symbol is not equal"; 272 LLVMOrcReleaseSymbolStringPoolEntry(E1); 273 LLVMOrcReleaseSymbolStringPoolEntry(E2); 274 LLVMOrcReleaseSymbolStringPoolEntry(E3); 275 } 276 277 TEST_F(OrcCAPITestBase, JITDylibLookup) { 278 LLVMOrcJITDylibRef DoesNotExist = 279 LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test"); 280 ASSERT_FALSE(!!DoesNotExist); 281 LLVMOrcJITDylibRef L1 = 282 LLVMOrcExecutionSessionCreateBareJITDylib(ExecutionSession, "test"); 283 LLVMOrcJITDylibRef L2 = 284 LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test"); 285 ASSERT_EQ(L1, L2) << "Located JIT Dylib is not equal to original"; 286 } 287 288 TEST_F(OrcCAPITestBase, MaterializationUnitCreation) { 289 LLVMOrcSymbolStringPoolEntryRef Name = 290 LLVMOrcLLJITMangleAndIntern(Jit, "test"); 291 LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0}; 292 LLVMOrcJITTargetAddress Addr = 293 (LLVMOrcJITTargetAddress)(&materializationUnitFn); 294 LLVMJITEvaluatedSymbol Sym = {Addr, Flags}; 295 LLVMOrcCSymbolMapPair Pair = {Name, Sym}; 296 LLVMOrcCSymbolMapPair Pairs[] = {Pair}; 297 LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1); 298 if (LLVMErrorRef E = LLVMOrcJITDylibDefine(MainDylib, MU)) 299 FAIL() << "Unexpected error while adding \"test\" symbol (triple = " 300 << TargetTriple << "): " << toString(E); 301 LLVMOrcJITTargetAddress OutAddr; 302 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &OutAddr, "test")) 303 FAIL() << "Failed to look up \"test\" symbol (triple = " << TargetTriple 304 << "): " << toString(E); 305 ASSERT_EQ(Addr, OutAddr); 306 } 307 308 struct ExecutionSessionLookupHelper { 309 bool ExpectSuccess = true; 310 bool CallbackReceived = false; 311 size_t NumExpectedPairs; 312 LLVMOrcCSymbolMapPair *ExpectedMapping; 313 }; 314 315 static void executionSessionLookupHandlerCallback(LLVMErrorRef Err, 316 LLVMOrcCSymbolMapPairs Result, 317 size_t NumPairs, 318 void *RawCtx) { 319 auto *Ctx = static_cast<ExecutionSessionLookupHelper *>(RawCtx); 320 Ctx->CallbackReceived = true; 321 if (Ctx->ExpectSuccess) { 322 EXPECT_THAT_ERROR(unwrap(Err), Succeeded()); 323 EXPECT_EQ(NumPairs, Ctx->NumExpectedPairs) 324 << "Expected " << Ctx->NumExpectedPairs << " entries in result, got " 325 << NumPairs; 326 auto ExpectedMappingEnd = Ctx->ExpectedMapping + Ctx->NumExpectedPairs; 327 for (unsigned I = 0; I != NumPairs; ++I) { 328 auto J = 329 std::find_if(Ctx->ExpectedMapping, ExpectedMappingEnd, 330 [N = Result[I].Name](const LLVMOrcCSymbolMapPair &Val) { 331 return Val.Name == N; 332 }); 333 EXPECT_NE(J, ExpectedMappingEnd) 334 << "Missing symbol \"" 335 << LLVMOrcSymbolStringPoolEntryStr(Result[I].Name) << "\""; 336 if (J != ExpectedMappingEnd) { 337 EXPECT_EQ(Result[I].Sym.Address, J->Sym.Address) 338 << "Result map for \"" << Result[I].Name 339 << "\" differs from expected value: " 340 << formatv("{0:x} vs {1:x}", Result[I].Sym.Address, J->Sym.Address); 341 } 342 } 343 } else 344 EXPECT_THAT_ERROR(unwrap(Err), Failed()); 345 } 346 347 TEST_F(OrcCAPITestBase, ExecutionSessionLookup_Success) { 348 // Test a successful generic lookup. We will look up three symbols over two 349 // JITDylibs: { "Foo" (Required), "Bar" (Weakly-ref), "Baz" (Required) } over 350 // { MainJITDylib (Exported-only), ExtraJD (All symbols) }. 351 // 352 // Foo will be defined as exported in MainJD. 353 // Bar will be defined as non-exported in MainJD. 354 // Baz will be defined as non-exported in ExtraJD. 355 // 356 // This will require (1) that we find the regular exported symbol Foo in 357 // MainJD, (2) that we *don't* find the non-exported symbol Bar in MainJD 358 // but also don't error (since it's weakly referenced), and (3) that we 359 // find the non-exported symbol Baz in ExtraJD (since we're searching all 360 // symbols in ExtraJD). 361 362 ExecutionSessionLookupHelper H; 363 LLVMOrcSymbolStringPoolEntryRef Foo = LLVMOrcLLJITMangleAndIntern(Jit, "Foo"); 364 LLVMOrcSymbolStringPoolEntryRef Bar = LLVMOrcLLJITMangleAndIntern(Jit, "Bar"); 365 LLVMOrcSymbolStringPoolEntryRef Baz = LLVMOrcLLJITMangleAndIntern(Jit, "Baz"); 366 367 // Create ExtraJD. 368 LLVMOrcJITDylibRef ExtraJD = nullptr; 369 if (auto E = LLVMOrcExecutionSessionCreateJITDylib(ExecutionSession, &ExtraJD, 370 "ExtraJD")) { 371 FAIL() << "Unexpected error while creating JITDylib \"ExtraJD\" (triple = " 372 << TargetTriple << "): " << toString(E); 373 return; 374 } 375 376 // Add exported symbols "Foo" and "Bar" to Main JITDylib. 377 LLVMOrcRetainSymbolStringPoolEntry(Foo); 378 LLVMOrcRetainSymbolStringPoolEntry(Bar); 379 LLVMOrcCSymbolMapPair MainJDPairs[] = { 380 {Foo, {0x1, {LLVMJITSymbolGenericFlagsExported, 0}}}, 381 {Bar, {0x2, {LLVMJITSymbolGenericFlagsNone, 0}}}}; 382 LLVMOrcMaterializationUnitRef MainJDMU = 383 LLVMOrcAbsoluteSymbols(MainJDPairs, 2); 384 if (LLVMErrorRef E = LLVMOrcJITDylibDefine(MainDylib, MainJDMU)) 385 FAIL() << "Unexpected error while adding MainDylib symbols (triple = " 386 << TargetTriple << "): " << toString(E); 387 388 // Add non-exported symbol "Baz" to ExtraJD. 389 LLVMOrcRetainSymbolStringPoolEntry(Baz); 390 LLVMOrcCSymbolMapPair ExtraJDPairs[] = { 391 {Baz, {0x3, {LLVMJITSymbolGenericFlagsNone, 0}}}}; 392 LLVMOrcMaterializationUnitRef ExtraJDMU = 393 LLVMOrcAbsoluteSymbols(ExtraJDPairs, 1); 394 if (LLVMErrorRef E = LLVMOrcJITDylibDefine(ExtraJD, ExtraJDMU)) 395 FAIL() << "Unexpected error while adding ExtraJD symbols (triple = " 396 << TargetTriple << "): " << toString(E); 397 398 // Create expected mapping for result: 399 LLVMOrcCSymbolMapPair ExpectedMapping[] = { 400 {Foo, {0x1, {LLVMJITSymbolGenericFlagsExported, 0}}}, 401 {Baz, {0x3, {LLVMJITSymbolGenericFlagsNone, 0}}}}; 402 H.ExpectedMapping = ExpectedMapping; 403 H.NumExpectedPairs = 2; 404 405 // Issue the lookup. We're using the default same-thread dispatch, so the 406 // handler should have run by the time we return from this call. 407 LLVMOrcCJITDylibSearchOrderElement SO[] = { 408 {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly}, 409 {ExtraJD, LLVMOrcJITDylibLookupFlagsMatchAllSymbols}}; 410 411 LLVMOrcRetainSymbolStringPoolEntry(Foo); 412 LLVMOrcRetainSymbolStringPoolEntry(Bar); 413 LLVMOrcRetainSymbolStringPoolEntry(Baz); 414 LLVMOrcCLookupSetElement LS[] = { 415 {Foo, LLVMOrcSymbolLookupFlagsRequiredSymbol}, 416 {Bar, LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol}, 417 {Baz, LLVMOrcSymbolLookupFlagsRequiredSymbol}}; 418 LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO, 419 2, LS, 3, executionSessionLookupHandlerCallback, 420 &H); 421 422 EXPECT_TRUE(H.CallbackReceived) << "Lookup callback never received"; 423 424 // Release our local string ptrs. 425 LLVMOrcReleaseSymbolStringPoolEntry(Baz); 426 LLVMOrcReleaseSymbolStringPoolEntry(Bar); 427 LLVMOrcReleaseSymbolStringPoolEntry(Foo); 428 } 429 430 TEST_F(OrcCAPITestBase, ExecutionSessionLookup_Failure) { 431 // Test generic lookup failure case. We will look up a symbol in MainDylib 432 // without defining it. We expect this to result in a symbol-not-found error. 433 434 ExecutionSessionLookupHelper H; 435 H.ExpectSuccess = false; 436 437 LLVMOrcCJITDylibSearchOrderElement SO[] = { 438 {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly}}; 439 LLVMOrcCLookupSetElement LS[] = {{LLVMOrcLLJITMangleAndIntern(Jit, "Foo"), 440 LLVMOrcSymbolLookupFlagsRequiredSymbol}}; 441 LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO, 442 1, LS, 1, executionSessionLookupHandlerCallback, 443 &H); 444 445 EXPECT_TRUE(H.CallbackReceived) << "Lookup callback never received"; 446 } 447 448 TEST_F(OrcCAPITestBase, DefinitionGenerators) { 449 LLVMOrcDefinitionGeneratorRef Gen = 450 LLVMOrcCreateCustomCAPIDefinitionGenerator(&definitionGeneratorFn, 451 nullptr, nullptr); 452 LLVMOrcJITDylibAddGenerator(MainDylib, Gen); 453 LLVMOrcJITTargetAddress OutAddr; 454 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &OutAddr, "test")) 455 FAIL() << "The DefinitionGenerator did not create symbol \"test\" " 456 << "(triple = " << TargetTriple << "): " << toString(E); 457 LLVMOrcJITTargetAddress ExpectedAddr = 458 (LLVMOrcJITTargetAddress)(&materializationUnitFn); 459 ASSERT_EQ(ExpectedAddr, OutAddr); 460 } 461 462 #if defined(_AIX) 463 TEST_F(OrcCAPITestBase, DISABLED_ResourceTrackerDefinitionLifetime) { 464 #else 465 TEST_F(OrcCAPITestBase, ResourceTrackerDefinitionLifetime) { 466 #endif 467 // This test case ensures that all symbols loaded into a JITDylib with a 468 // ResourceTracker attached are cleared from the JITDylib once the RT is 469 // removed. 470 LLVMOrcResourceTrackerRef RT = 471 LLVMOrcJITDylibCreateResourceTracker(MainDylib); 472 LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll"); 473 if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, RT, TSM)) 474 FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple 475 << "): " << toString(E); 476 LLVMOrcJITTargetAddress TestFnAddr; 477 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum")) 478 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple 479 << "): " << toString(E); 480 ASSERT_TRUE(!!TestFnAddr); 481 LLVMOrcResourceTrackerRemove(RT); 482 LLVMOrcJITTargetAddress OutAddr; 483 LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &OutAddr, "sum"); 484 ASSERT_TRUE(Err); 485 LLVMConsumeError(Err); 486 487 ASSERT_FALSE(OutAddr); 488 LLVMOrcReleaseResourceTracker(RT); 489 } 490 491 #if defined(_AIX) 492 TEST_F(OrcCAPITestBase, DISABLED_ResourceTrackerTransfer) { 493 #else 494 TEST_F(OrcCAPITestBase, ResourceTrackerTransfer) { 495 #endif 496 LLVMOrcResourceTrackerRef DefaultRT = 497 LLVMOrcJITDylibGetDefaultResourceTracker(MainDylib); 498 LLVMOrcResourceTrackerRef RT2 = 499 LLVMOrcJITDylibCreateResourceTracker(MainDylib); 500 LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll"); 501 if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, DefaultRT, TSM)) 502 FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple 503 << "): " << toString(E); 504 LLVMOrcJITTargetAddress Addr; 505 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &Addr, "sum")) 506 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple 507 << "): " << toString(E); 508 LLVMOrcResourceTrackerTransferTo(DefaultRT, RT2); 509 LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "sum"); 510 ASSERT_FALSE(Err); 511 LLVMOrcReleaseResourceTracker(RT2); 512 } 513 514 #if defined(_AIX) 515 TEST_F(OrcCAPITestBase, DISABLED_AddObjectBuffer) { 516 #else 517 TEST_F(OrcCAPITestBase, AddObjectBuffer) { 518 #endif 519 LLVMOrcObjectLayerRef ObjLinkingLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit); 520 LLVMMemoryBufferRef ObjBuffer = createTestObject(SumExample, "sum.ll"); 521 522 if (LLVMErrorRef E = LLVMOrcObjectLayerAddObjectFile(ObjLinkingLayer, 523 MainDylib, ObjBuffer)) 524 FAIL() << "Failed to add object file to ObjLinkingLayer (triple = " 525 << TargetTriple << "): " << toString(E); 526 527 LLVMOrcJITTargetAddress SumAddr; 528 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &SumAddr, "sum")) 529 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple 530 << "): " << toString(E); 531 ASSERT_TRUE(!!SumAddr); 532 } 533 534 // JITLink debug support plugins put information about JITed code in this GDB 535 // JIT Interface global from OrcTargetProcess. 536 extern "C" struct jit_descriptor __jit_debug_descriptor; 537 538 static void *findLastDebugDescriptorEntryPtr() { 539 struct jit_code_entry *Last = __jit_debug_descriptor.first_entry; 540 while (Last && Last->next_entry) 541 Last = Last->next_entry; 542 return Last; 543 } 544 545 #if defined(_AIX) or not(defined(__ELF__) or defined(__MACH__)) 546 TEST_F(OrcCAPITestBase, DISABLED_EnableDebugSupport) { 547 #else 548 static LLVM_ATTRIBUTE_USED void linkComponents() { 549 errs() << "Linking in runtime functions\n" 550 << (void *)&llvm_orc_registerJITLoaderGDBWrapper << '\n' 551 << (void *)&llvm_orc_registerJITLoaderGDBAllocAction << '\n'; 552 } 553 TEST_F(OrcCAPITestBase, EnableDebugSupport) { 554 #endif 555 void *Before = findLastDebugDescriptorEntryPtr(); 556 LLVMMemoryBufferRef ObjBuffer = createTestObject(SumDebugExample, "sum.ll"); 557 LLVMOrcObjectLayerRef ObjLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit); 558 559 if (LLVMErrorRef E = LLVMOrcLLJITEnableDebugSupport(Jit)) { 560 EXPECT_FALSE(isa<ObjectLinkingLayer>(unwrap(ObjLayer))) 561 << "Error testing LLJIT debug support " 562 << "(triple = " << TargetTriple << "): " << toString(E); 563 GTEST_SKIP() << "LLJIT C bindings provide debug support only for JITLink"; 564 } 565 566 if (LLVMErrorRef E = 567 LLVMOrcObjectLayerAddObjectFile(ObjLayer, MainDylib, ObjBuffer)) 568 FAIL() << "Failed to add object file to ObjLinkingLayer (triple = " 569 << TargetTriple << "): " << toString(E); 570 571 LLVMOrcJITTargetAddress SumAddr; 572 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &SumAddr, "sum")) 573 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple 574 << "): " << toString(E); 575 576 void *After = findLastDebugDescriptorEntryPtr(); 577 ASSERT_NE(Before, After); 578 } 579 580 #if defined(_AIX) 581 TEST_F(OrcCAPITestBase, DISABLED_ExecutionTest) { 582 #else 583 TEST_F(OrcCAPITestBase, ExecutionTest) { 584 #endif 585 using SumFunctionType = int32_t (*)(int32_t, int32_t); 586 587 // This test performs OrcJIT compilation of a simple sum module 588 LLVMInitializeNativeAsmPrinter(); 589 LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll"); 590 if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModule(Jit, MainDylib, TSM)) 591 FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple 592 << ")" << toString(E); 593 LLVMOrcJITTargetAddress TestFnAddr; 594 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum")) 595 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple 596 << "): " << toString(E); 597 auto *SumFn = (SumFunctionType)(TestFnAddr); 598 int32_t Result = SumFn(1, 1); 599 ASSERT_EQ(2, Result); 600 } 601 602 void Destroy(void *Ctx) {} 603 604 void TargetFn() {} 605 606 void Materialize(void *Ctx, LLVMOrcMaterializationResponsibilityRef MR) { 607 LLVMOrcJITDylibRef JD = 608 LLVMOrcMaterializationResponsibilityGetTargetDylib(MR); 609 ASSERT_TRUE(!!JD); 610 611 LLVMOrcExecutionSessionRef ES = 612 LLVMOrcMaterializationResponsibilityGetExecutionSession(MR); 613 ASSERT_TRUE(!!ES); 614 615 LLVMOrcSymbolStringPoolEntryRef InitSym = 616 LLVMOrcMaterializationResponsibilityGetInitializerSymbol(MR); 617 ASSERT_TRUE(!InitSym); 618 619 size_t NumSymbols; 620 LLVMOrcCSymbolFlagsMapPairs Symbols = 621 LLVMOrcMaterializationResponsibilityGetSymbols(MR, &NumSymbols); 622 623 ASSERT_TRUE(!!Symbols); 624 ASSERT_EQ(NumSymbols, (size_t)1); 625 626 LLVMOrcSymbolStringPoolEntryRef *RequestedSymbols = 627 LLVMOrcMaterializationResponsibilityGetRequestedSymbols(MR, &NumSymbols); 628 629 ASSERT_TRUE(!!RequestedSymbols); 630 ASSERT_EQ(NumSymbols, (size_t)1); 631 632 LLVMOrcCSymbolFlagsMapPair TargetSym = Symbols[0]; 633 634 ASSERT_EQ(RequestedSymbols[0], TargetSym.Name); 635 LLVMOrcRetainSymbolStringPoolEntry(TargetSym.Name); 636 637 LLVMOrcDisposeCSymbolFlagsMap(Symbols); 638 LLVMOrcDisposeSymbols(RequestedSymbols); 639 640 LLVMOrcJITTargetAddress Addr = (LLVMOrcJITTargetAddress)(&TargetFn); 641 642 LLVMJITSymbolFlags Flags = { 643 LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0}; 644 ASSERT_EQ(TargetSym.Flags.GenericFlags, Flags.GenericFlags); 645 ASSERT_EQ(TargetSym.Flags.TargetFlags, Flags.TargetFlags); 646 647 LLVMJITEvaluatedSymbol Sym = {Addr, Flags}; 648 649 LLVMOrcLLJITRef J = (LLVMOrcLLJITRef)Ctx; 650 651 LLVMOrcSymbolStringPoolEntryRef OtherSymbol = 652 LLVMOrcLLJITMangleAndIntern(J, "other"); 653 LLVMOrcSymbolStringPoolEntryRef DependencySymbol = 654 LLVMOrcLLJITMangleAndIntern(J, "dependency"); 655 656 LLVMOrcRetainSymbolStringPoolEntry(OtherSymbol); 657 LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol); 658 LLVMOrcCSymbolFlagsMapPair NewSymbols[] = { 659 {OtherSymbol, Flags}, 660 {DependencySymbol, Flags}, 661 }; 662 LLVMOrcMaterializationResponsibilityDefineMaterializing(MR, NewSymbols, 2); 663 664 LLVMOrcRetainSymbolStringPoolEntry(OtherSymbol); 665 LLVMOrcMaterializationResponsibilityRef OtherMR = NULL; 666 { 667 LLVMErrorRef Err = LLVMOrcMaterializationResponsibilityDelegate( 668 MR, &OtherSymbol, 1, &OtherMR); 669 if (Err) { 670 char *ErrMsg = LLVMGetErrorMessage(Err); 671 fprintf(stderr, "Error: %s\n", ErrMsg); 672 LLVMDisposeErrorMessage(ErrMsg); 673 LLVMOrcMaterializationResponsibilityFailMaterialization(MR); 674 LLVMOrcDisposeMaterializationResponsibility(MR); 675 return; 676 } 677 } 678 assert(OtherMR); 679 680 LLVMOrcCSymbolMapPair OtherPair = {OtherSymbol, Sym}; 681 LLVMOrcMaterializationUnitRef OtherMU = LLVMOrcAbsoluteSymbols(&OtherPair, 1); 682 // OtherSymbol is no longer owned by us 683 { 684 LLVMErrorRef Err = 685 LLVMOrcMaterializationResponsibilityReplace(OtherMR, OtherMU); 686 if (Err) { 687 char *ErrMsg = LLVMGetErrorMessage(Err); 688 fprintf(stderr, "Error: %s\n", ErrMsg); 689 LLVMDisposeErrorMessage(ErrMsg); 690 691 LLVMOrcMaterializationResponsibilityFailMaterialization(OtherMR); 692 LLVMOrcMaterializationResponsibilityFailMaterialization(MR); 693 694 LLVMOrcDisposeMaterializationResponsibility(OtherMR); 695 LLVMOrcDisposeMaterializationResponsibility(MR); 696 LLVMOrcDisposeMaterializationUnit(OtherMU); 697 return; 698 } 699 } 700 LLVMOrcDisposeMaterializationResponsibility(OtherMR); 701 702 // FIXME: Implement async lookup 703 LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol); 704 LLVMOrcCSymbolMapPair Pair = {DependencySymbol, Sym}; 705 LLVMOrcMaterializationResponsibilityNotifyResolved(MR, &Pair, 1); 706 // DependencySymbol no longer owned by us 707 708 Pair = {TargetSym.Name, Sym}; 709 LLVMOrcMaterializationResponsibilityNotifyResolved(MR, &Pair, 1); 710 711 LLVMOrcRetainSymbolStringPoolEntry(TargetSym.Name); 712 LLVMOrcCDependenceMapPair Dependency = {JD, {&DependencySymbol, 1}}; 713 LLVMOrcCSymbolDependenceGroup DependenceSet = { 714 /*.Symbols = */ {/*.Symbols = */ &TargetSym.Name, /* .Length = */ 1}, 715 /* .Dependencies = */ &Dependency, 716 /* .NumDependencies = */ 1}; 717 718 LLVMOrcMaterializationResponsibilityNotifyEmitted(MR, &DependenceSet, 1); 719 LLVMOrcDisposeMaterializationResponsibility(MR); 720 } 721 722 TEST_F(OrcCAPITestBase, MaterializationResponsibility) { 723 LLVMJITSymbolFlags Flags = { 724 LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0}; 725 LLVMOrcCSymbolFlagsMapPair Sym = {LLVMOrcLLJITMangleAndIntern(Jit, "foo"), 726 Flags}; 727 728 LLVMOrcMaterializationUnitRef MU = LLVMOrcCreateCustomMaterializationUnit( 729 "MU", (void *)Jit, &Sym, 1, NULL, &Materialize, NULL, &Destroy); 730 LLVMOrcJITDylibRef JD = LLVMOrcLLJITGetMainJITDylib(Jit); 731 LLVMOrcJITDylibDefine(JD, MU); 732 733 LLVMOrcJITTargetAddress Addr; 734 if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "foo")) { 735 FAIL() << "foo was not materialized " << toString(Err); 736 } 737 ASSERT_TRUE(!!Addr); 738 ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn); 739 740 if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "other")) { 741 FAIL() << "other was not materialized " << toString(Err); 742 } 743 ASSERT_TRUE(!!Addr); 744 ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn); 745 746 if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "dependency")) { 747 FAIL() << "dependency was not materialized " << toString(Err); 748 } 749 ASSERT_TRUE(!!Addr); 750 ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn); 751 } 752 753 struct SuspendedLookupContext { 754 std::function<void()> AsyncWork; 755 LLVMOrcSymbolStringPoolEntryRef NameToGenerate; 756 JITTargetAddress AddrToGenerate; 757 758 bool Disposed = false; 759 bool QueryCompleted = true; 760 }; 761 762 static LLVMErrorRef TryToGenerateWithSuspendedLookup( 763 LLVMOrcDefinitionGeneratorRef GeneratorObj, void *RawCtx, 764 LLVMOrcLookupStateRef *LookupState, LLVMOrcLookupKind Kind, 765 LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags JDLookupFlags, 766 LLVMOrcCLookupSet LookupSet, size_t LookupSetSize) { 767 768 auto *Ctx = static_cast<SuspendedLookupContext *>(RawCtx); 769 770 assert(LookupSetSize == 1); 771 assert(LookupSet[0].Name == Ctx->NameToGenerate); 772 773 LLVMJITEvaluatedSymbol Sym = {0x1234, {LLVMJITSymbolGenericFlagsExported, 0}}; 774 LLVMOrcRetainSymbolStringPoolEntry(LookupSet[0].Name); 775 LLVMOrcCSymbolMapPair Pair = {LookupSet[0].Name, Sym}; 776 LLVMOrcCSymbolMapPair Pairs[] = {Pair}; 777 LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1); 778 779 // Capture and reset LookupState to suspend the lookup. We'll continue it in 780 // the SuspendedLookup testcase below. 781 Ctx->AsyncWork = [LS = *LookupState, JD, MU]() { 782 LLVMErrorRef Err = LLVMOrcJITDylibDefine(JD, MU); 783 LLVMOrcLookupStateContinueLookup(LS, Err); 784 }; 785 *LookupState = nullptr; 786 return LLVMErrorSuccess; 787 } 788 789 static void DisposeSuspendedLookupContext(void *Ctx) { 790 static_cast<SuspendedLookupContext *>(Ctx)->Disposed = true; 791 } 792 793 static void 794 suspendLookupTestLookupHandlerCallback(LLVMErrorRef Err, 795 LLVMOrcCSymbolMapPairs Result, 796 size_t NumPairs, void *RawCtx) { 797 if (Err) { 798 FAIL() << "Suspended DefinitionGenerator did not create symbol \"foo\": " 799 << toString(Err); 800 return; 801 } 802 803 EXPECT_EQ(NumPairs, 1U) 804 << "Unexpected number of result entries: expected 1, got " << NumPairs; 805 806 auto *Ctx = static_cast<SuspendedLookupContext *>(RawCtx); 807 EXPECT_EQ(Result[0].Name, Ctx->NameToGenerate); 808 EXPECT_EQ(Result[0].Sym.Address, Ctx->AddrToGenerate); 809 810 Ctx->QueryCompleted = true; 811 } 812 813 TEST_F(OrcCAPITestBase, SuspendedLookup) { 814 // Test that we can suspend lookup in a custom generator. 815 SuspendedLookupContext Ctx; 816 Ctx.NameToGenerate = LLVMOrcLLJITMangleAndIntern(Jit, "foo"); 817 Ctx.AddrToGenerate = 0x1234; 818 819 // Add generator. 820 LLVMOrcJITDylibAddGenerator(MainDylib, 821 LLVMOrcCreateCustomCAPIDefinitionGenerator( 822 &TryToGenerateWithSuspendedLookup, &Ctx, 823 DisposeSuspendedLookupContext)); 824 825 // Expect no work to do before the lookup. 826 EXPECT_FALSE(Ctx.AsyncWork) << "Unexpected generator work before lookup"; 827 828 // Issue lookup. This should trigger the generator, but generation should 829 // be suspended. 830 LLVMOrcCJITDylibSearchOrderElement SO[] = { 831 {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly}}; 832 LLVMOrcRetainSymbolStringPoolEntry(Ctx.NameToGenerate); 833 LLVMOrcCLookupSetElement LS[] = { 834 {Ctx.NameToGenerate, LLVMOrcSymbolLookupFlagsRequiredSymbol}}; 835 LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO, 836 1, LS, 1, 837 suspendLookupTestLookupHandlerCallback, &Ctx); 838 839 // Expect that we now have generator work to do. 840 EXPECT_TRUE(Ctx.AsyncWork) 841 << "Failed to generator (or failed to suspend generator)"; 842 843 // Do the work. This should allow the query to complete. 844 Ctx.AsyncWork(); 845 846 // Check that the query completed. 847 EXPECT_TRUE(Ctx.QueryCompleted); 848 849 // Release our local copy of the string. 850 LLVMOrcReleaseSymbolStringPoolEntry(Ctx.NameToGenerate); 851 852 // Explicitly tear down the JIT. 853 LLVMOrcDisposeLLJIT(Jit); 854 Jit = nullptr; 855 856 // Check that the generator context was "destroyed". 857 EXPECT_TRUE(Ctx.Disposed); 858 } 859