1f2018d6cSLang Hames //===--- OrcCAPITest.cpp - Unit tests for the OrcJIT v2 C API ---*- C++ -*-===// 2f2018d6cSLang Hames // 3f2018d6cSLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f2018d6cSLang Hames // See https://llvm.org/LICENSE.txt for license information. 5f2018d6cSLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f2018d6cSLang Hames // 7f2018d6cSLang Hames //===----------------------------------------------------------------------===// 8f2018d6cSLang Hames 9f2018d6cSLang Hames #include "llvm-c/Core.h" 10f2018d6cSLang Hames #include "llvm-c/Error.h" 11f2018d6cSLang Hames #include "llvm-c/LLJIT.h" 1254397f9aSStefan Gränitz #include "llvm-c/LLJITUtils.h" 13f2018d6cSLang Hames #include "llvm-c/Orc.h" 14f2018d6cSLang Hames #include "gtest/gtest.h" 15f2018d6cSLang Hames 16*9f73c69eSJonas Paulsson #include "llvm/Analysis/TargetLibraryInfo.h" 177b73cd68SLang Hames #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 18e00ade11SStefan Gränitz #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" 1954397f9aSStefan Gränitz #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" 207b73cd68SLang Hames #include "llvm/IR/LLVMContext.h" 217b73cd68SLang Hames #include "llvm/IR/Module.h" 227b73cd68SLang Hames #include "llvm/IRReader/IRReader.h" 237b73cd68SLang Hames #include "llvm/Support/Error.h" 24803c770eSLang Hames #include "llvm/Support/FormatVariadic.h" 257b73cd68SLang Hames #include "llvm/Support/SourceMgr.h" 2662c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.h" 27803c770eSLang Hames #include "llvm/Testing/Support/Error.h" 28f2018d6cSLang Hames #include <string> 29f2018d6cSLang Hames 30f2018d6cSLang Hames using namespace llvm; 317b73cd68SLang Hames using namespace llvm::orc; 327b73cd68SLang Hames 33e00ade11SStefan Gränitz DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectLayer, LLVMOrcObjectLayerRef) 347b73cd68SLang Hames DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef) 35f2018d6cSLang Hames 36*9f73c69eSJonas Paulsson // A class that sets strings for extension attributes by querying 37*9f73c69eSJonas Paulsson // TargetLibraryInfo. 38*9f73c69eSJonas Paulsson struct TargetI32ArgExtensions { 39*9f73c69eSJonas Paulsson std::string Ret; 40*9f73c69eSJonas Paulsson std::string Arg; 41*9f73c69eSJonas Paulsson TargetI32ArgExtensions(std::string TargetTriple, bool Signed = true) { 42*9f73c69eSJonas Paulsson Triple T(TargetTriple); 43*9f73c69eSJonas Paulsson if (auto AK = TargetLibraryInfo::getExtAttrForI32Return(T, Signed)) 44*9f73c69eSJonas Paulsson Ret = Attribute::getNameFromAttrKind(AK).str() + " "; 45*9f73c69eSJonas Paulsson if (auto AK = TargetLibraryInfo::getExtAttrForI32Param(T, Signed)) 46*9f73c69eSJonas Paulsson Arg = Attribute::getNameFromAttrKind(AK).str() + " "; 47*9f73c69eSJonas Paulsson } 48*9f73c69eSJonas Paulsson }; 49*9f73c69eSJonas Paulsson 50f2018d6cSLang Hames // OrcCAPITestBase contains several helper methods and pointers for unit tests 51f2018d6cSLang Hames // written for the LLVM-C API. It provides the following helpers: 52f2018d6cSLang Hames // 53f2018d6cSLang Hames // 1. Jit: an LLVMOrcLLJIT instance which is freed upon test exit 54f2018d6cSLang Hames // 2. ExecutionSession: the LLVMOrcExecutionSession for the JIT 55f2018d6cSLang Hames // 3. MainDylib: the main JITDylib for the LLJIT instance 56f2018d6cSLang Hames // 4. materializationUnitFn: function pointer to an empty function, used for 57f2018d6cSLang Hames // materialization unit testing 58f2018d6cSLang Hames // 5. definitionGeneratorFn: function pointer for a basic 59f2018d6cSLang Hames // LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction 60f2018d6cSLang Hames // 6. createTestModule: helper method for creating a basic thread-safe-module 61f2018d6cSLang Hames class OrcCAPITestBase : public testing::Test { 62f2018d6cSLang Hames protected: 63f2018d6cSLang Hames LLVMOrcLLJITRef Jit = nullptr; 64f2018d6cSLang Hames LLVMOrcExecutionSessionRef ExecutionSession = nullptr; 65f2018d6cSLang Hames LLVMOrcJITDylibRef MainDylib = nullptr; 66f2018d6cSLang Hames 67f2018d6cSLang Hames public: 68f2018d6cSLang Hames static void SetUpTestCase() { 69f2018d6cSLang Hames LLVMInitializeNativeTarget(); 70f2018d6cSLang Hames LLVMInitializeNativeAsmParser(); 71f2018d6cSLang Hames LLVMInitializeNativeAsmPrinter(); 72f2018d6cSLang Hames 73f2018d6cSLang Hames // Attempt to set up a JIT instance once to verify that we can. 74f2018d6cSLang Hames LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr; 75f2018d6cSLang Hames if (LLVMErrorRef E = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB)) { 76f2018d6cSLang Hames // If setup fails then disable these tests. 77f2018d6cSLang Hames LLVMConsumeError(E); 78f2018d6cSLang Hames TargetSupported = false; 79f2018d6cSLang Hames return; 80f2018d6cSLang Hames } 81f2018d6cSLang Hames 82f2018d6cSLang Hames // Capture the target triple. We'll use it for both verification that 83f2018d6cSLang Hames // this target is *supposed* to be supported, and error messages in 84f2018d6cSLang Hames // the case that it fails anyway. 85f2018d6cSLang Hames char *TT = LLVMOrcJITTargetMachineBuilderGetTargetTriple(JTMB); 86f2018d6cSLang Hames TargetTriple = TT; 8740df1b15SLang Hames LLVMDisposeMessage(TT); 88f2018d6cSLang Hames 89f2018d6cSLang Hames if (!isSupported(TargetTriple)) { 90f2018d6cSLang Hames // If this triple isn't supported then bail out. 91f2018d6cSLang Hames TargetSupported = false; 92f2018d6cSLang Hames LLVMOrcDisposeJITTargetMachineBuilder(JTMB); 93f2018d6cSLang Hames return; 94f2018d6cSLang Hames } 95f2018d6cSLang Hames 96f2018d6cSLang Hames LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder(); 97f2018d6cSLang Hames LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB); 98f2018d6cSLang Hames LLVMOrcLLJITRef J; 99f2018d6cSLang Hames if (LLVMErrorRef E = LLVMOrcCreateLLJIT(&J, Builder)) { 100f2018d6cSLang Hames // If setup fails then disable these tests. 101f2018d6cSLang Hames TargetSupported = false; 102f2018d6cSLang Hames LLVMConsumeError(E); 103f2018d6cSLang Hames return; 104f2018d6cSLang Hames } 105f2018d6cSLang Hames 106f2018d6cSLang Hames LLVMOrcDisposeLLJIT(J); 107f2018d6cSLang Hames TargetSupported = true; 108*9f73c69eSJonas Paulsson 109*9f73c69eSJonas Paulsson // Create test functions in text format, with the proper extension 110*9f73c69eSJonas Paulsson // attributes. 111*9f73c69eSJonas Paulsson if (SumExample.empty()) { 112*9f73c69eSJonas Paulsson TargetI32ArgExtensions ArgExt(TargetTriple); 113*9f73c69eSJonas Paulsson std::ostringstream OS; 114*9f73c69eSJonas Paulsson OS << "define " << ArgExt.Ret << "i32 " 115*9f73c69eSJonas Paulsson << "@sum(i32 " << ArgExt.Arg << "%x, i32 " << ArgExt.Arg << "%y)" 116*9f73c69eSJonas Paulsson << R"( { 117*9f73c69eSJonas Paulsson entry: 118*9f73c69eSJonas Paulsson %r = add nsw i32 %x, %y 119*9f73c69eSJonas Paulsson ret i32 %r 120*9f73c69eSJonas Paulsson } 121*9f73c69eSJonas Paulsson )"; 122*9f73c69eSJonas Paulsson SumExample = OS.str(); 123*9f73c69eSJonas Paulsson 124*9f73c69eSJonas Paulsson OS << R"( 125*9f73c69eSJonas Paulsson !llvm.module.flags = !{!0} 126*9f73c69eSJonas Paulsson !llvm.dbg.cu = !{!1} 127*9f73c69eSJonas Paulsson !0 = !{i32 2, !"Debug Info Version", i32 3} 128*9f73c69eSJonas Paulsson !1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, emissionKind: FullDebug) 129*9f73c69eSJonas Paulsson !2 = !DIFile(filename: "sum.c", directory: "/tmp") 130*9f73c69eSJonas Paulsson )"; 131*9f73c69eSJonas Paulsson SumDebugExample = OS.str(); 132*9f73c69eSJonas Paulsson } 133f2018d6cSLang Hames } 134f2018d6cSLang Hames 135f2018d6cSLang Hames void SetUp() override { 136f2018d6cSLang Hames if (!TargetSupported) 13795612afcSLang Hames GTEST_SKIP(); 138f2018d6cSLang Hames 139f2018d6cSLang Hames LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr; 140f2018d6cSLang Hames LLVMErrorRef E1 = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB); 141f2018d6cSLang Hames assert(E1 == LLVMErrorSuccess && "Expected call to detect host to succeed"); 1423d746962SBenjamin Kramer (void)E1; 143f2018d6cSLang Hames 144f2018d6cSLang Hames LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder(); 145f2018d6cSLang Hames LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB); 146f2018d6cSLang Hames LLVMErrorRef E2 = LLVMOrcCreateLLJIT(&Jit, Builder); 147f2018d6cSLang Hames assert(E2 == LLVMErrorSuccess && 148f2018d6cSLang Hames "Expected call to create LLJIT to succeed"); 1493d746962SBenjamin Kramer (void)E2; 150f2018d6cSLang Hames ExecutionSession = LLVMOrcLLJITGetExecutionSession(Jit); 151f2018d6cSLang Hames MainDylib = LLVMOrcLLJITGetMainJITDylib(Jit); 152f2018d6cSLang Hames } 153f2018d6cSLang Hames void TearDown() override { 15414b7c108SLang Hames // Check whether Jit has already been torn down -- we allow clients to do 15514b7c108SLang Hames // this manually to check teardown behavior. 15614b7c108SLang Hames if (Jit) { 157f2018d6cSLang Hames LLVMOrcDisposeLLJIT(Jit); 158f2018d6cSLang Hames Jit = nullptr; 159f2018d6cSLang Hames } 16014b7c108SLang Hames } 161f2018d6cSLang Hames 162f2018d6cSLang Hames protected: 163f2018d6cSLang Hames static bool isSupported(StringRef Triple) { 164f2018d6cSLang Hames // TODO: Print error messages in failure logs, use them to audit this list. 165f2018d6cSLang Hames // Some architectures may be unsupportable or missing key components, but 166f2018d6cSLang Hames // some may just be failing due to bugs in this testcase. 1675c9d82deSKazu Hirata if (Triple.starts_with("armv7") || Triple.starts_with("armv8l")) 168f2018d6cSLang Hames return false; 169f2018d6cSLang Hames return true; 170f2018d6cSLang Hames } 171f2018d6cSLang Hames 172f2018d6cSLang Hames static void materializationUnitFn() {} 1737b73cd68SLang Hames 174f2018d6cSLang Hames // Stub definition generator, where all Names are materialized from the 175f2018d6cSLang Hames // materializationUnitFn() test function and defined into the JIT Dylib 176f2018d6cSLang Hames static LLVMErrorRef 177f2018d6cSLang Hames definitionGeneratorFn(LLVMOrcDefinitionGeneratorRef G, void *Ctx, 178f2018d6cSLang Hames LLVMOrcLookupStateRef *LS, LLVMOrcLookupKind K, 179f2018d6cSLang Hames LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags F, 180f2018d6cSLang Hames LLVMOrcCLookupSet Names, size_t NamesCount) { 181f2018d6cSLang Hames for (size_t I = 0; I < NamesCount; I++) { 182f2018d6cSLang Hames LLVMOrcCLookupSetElement Element = Names[I]; 183f2018d6cSLang Hames LLVMOrcJITTargetAddress Addr = 184f2018d6cSLang Hames (LLVMOrcJITTargetAddress)(&materializationUnitFn); 185f2018d6cSLang Hames LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0}; 186f2018d6cSLang Hames LLVMJITEvaluatedSymbol Sym = {Addr, Flags}; 187f2018d6cSLang Hames LLVMOrcRetainSymbolStringPoolEntry(Element.Name); 188b425f556SLang Hames LLVMOrcCSymbolMapPair Pair = {Element.Name, Sym}; 189b425f556SLang Hames LLVMOrcCSymbolMapPair Pairs[] = {Pair}; 190f2018d6cSLang Hames LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1); 191f2018d6cSLang Hames LLVMErrorRef Err = LLVMOrcJITDylibDefine(JD, MU); 192f2018d6cSLang Hames if (Err) 193f2018d6cSLang Hames return Err; 194f2018d6cSLang Hames } 195f2018d6cSLang Hames return LLVMErrorSuccess; 196f2018d6cSLang Hames } 1977b73cd68SLang Hames 1987b73cd68SLang Hames static Error createSMDiagnosticError(llvm::SMDiagnostic &Diag) { 1997b73cd68SLang Hames std::string Msg; 200f2018d6cSLang Hames { 2017b73cd68SLang Hames raw_string_ostream OS(Msg); 2027b73cd68SLang Hames Diag.print("", OS); 203f2018d6cSLang Hames } 2047b73cd68SLang Hames return make_error<StringError>(std::move(Msg), inconvertibleErrorCode()); 2057b73cd68SLang Hames } 2067b73cd68SLang Hames 2077b73cd68SLang Hames // Create an LLVM IR module from the given StringRef. 2087b73cd68SLang Hames static Expected<std::unique_ptr<Module>> 2097b73cd68SLang Hames parseTestModule(LLVMContext &Ctx, StringRef Source, StringRef Name) { 2107b73cd68SLang Hames assert(TargetSupported && 2117b73cd68SLang Hames "Attempted to create module for unsupported target"); 2127b73cd68SLang Hames SMDiagnostic Err; 2137b73cd68SLang Hames if (auto M = parseIR(MemoryBufferRef(Source, Name), Err, Ctx)) 2147b73cd68SLang Hames return std::move(M); 2157b73cd68SLang Hames return createSMDiagnosticError(Err); 2167b73cd68SLang Hames } 2177b73cd68SLang Hames 2187b73cd68SLang Hames // returns the sum of its two parameters 2197b73cd68SLang Hames static LLVMOrcThreadSafeModuleRef createTestModule(StringRef Source, 2207b73cd68SLang Hames StringRef Name) { 2217b73cd68SLang Hames auto Ctx = std::make_unique<LLVMContext>(); 2227b73cd68SLang Hames auto M = cantFail(parseTestModule(*Ctx, Source, Name)); 2237b73cd68SLang Hames return wrap(new ThreadSafeModule(std::move(M), std::move(Ctx))); 2247b73cd68SLang Hames } 2257b73cd68SLang Hames 2267b73cd68SLang Hames static LLVMMemoryBufferRef createTestObject(StringRef Source, 2277b73cd68SLang Hames StringRef Name) { 2287b73cd68SLang Hames auto Ctx = std::make_unique<LLVMContext>(); 2297b73cd68SLang Hames auto M = cantFail(parseTestModule(*Ctx, Source, Name)); 2307b73cd68SLang Hames 2317b73cd68SLang Hames auto JTMB = cantFail(JITTargetMachineBuilder::detectHost()); 2327b73cd68SLang Hames M->setDataLayout(cantFail(JTMB.getDefaultDataLayoutForTarget())); 2337b73cd68SLang Hames auto TM = cantFail(JTMB.createTargetMachine()); 2347b73cd68SLang Hames 2357b73cd68SLang Hames SimpleCompiler SC(*TM); 2367b73cd68SLang Hames auto ObjBuffer = cantFail(SC(*M)); 2377b73cd68SLang Hames return wrap(ObjBuffer.release()); 238f2018d6cSLang Hames } 239f2018d6cSLang Hames 240f2018d6cSLang Hames static std::string TargetTriple; 241f2018d6cSLang Hames static bool TargetSupported; 242*9f73c69eSJonas Paulsson 243*9f73c69eSJonas Paulsson static std::string SumExample; 244*9f73c69eSJonas Paulsson static std::string SumDebugExample; 245f2018d6cSLang Hames }; 246f2018d6cSLang Hames 247f2018d6cSLang Hames std::string OrcCAPITestBase::TargetTriple; 248f2018d6cSLang Hames bool OrcCAPITestBase::TargetSupported = false; 249f2018d6cSLang Hames 250*9f73c69eSJonas Paulsson std::string OrcCAPITestBase::SumExample; 251*9f73c69eSJonas Paulsson std::string OrcCAPITestBase::SumDebugExample; 2527b73cd68SLang Hames 253f2018d6cSLang Hames // Consumes the given error ref and returns the string error message. 254f2018d6cSLang Hames static std::string toString(LLVMErrorRef E) { 255f2018d6cSLang Hames char *ErrMsg = LLVMGetErrorMessage(E); 256f2018d6cSLang Hames std::string Result(ErrMsg); 257f2018d6cSLang Hames LLVMDisposeErrorMessage(ErrMsg); 258f2018d6cSLang Hames return Result; 259f2018d6cSLang Hames } 260f2018d6cSLang Hames 261f2018d6cSLang Hames TEST_F(OrcCAPITestBase, SymbolStringPoolUniquing) { 262f2018d6cSLang Hames LLVMOrcSymbolStringPoolEntryRef E1 = 263f2018d6cSLang Hames LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa"); 264f2018d6cSLang Hames LLVMOrcSymbolStringPoolEntryRef E2 = 265f2018d6cSLang Hames LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa"); 266f2018d6cSLang Hames LLVMOrcSymbolStringPoolEntryRef E3 = 267f2018d6cSLang Hames LLVMOrcExecutionSessionIntern(ExecutionSession, "bbb"); 268f2018d6cSLang Hames const char *SymbolName = LLVMOrcSymbolStringPoolEntryStr(E1); 269f2018d6cSLang Hames ASSERT_EQ(E1, E2) << "String pool entries are not unique"; 270f2018d6cSLang Hames ASSERT_NE(E1, E3) << "Unique symbol pool entries are equal"; 271f2018d6cSLang Hames ASSERT_STREQ("aaa", SymbolName) << "String value of symbol is not equal"; 272f2018d6cSLang Hames LLVMOrcReleaseSymbolStringPoolEntry(E1); 273f2018d6cSLang Hames LLVMOrcReleaseSymbolStringPoolEntry(E2); 274f2018d6cSLang Hames LLVMOrcReleaseSymbolStringPoolEntry(E3); 275f2018d6cSLang Hames } 276f2018d6cSLang Hames 277f2018d6cSLang Hames TEST_F(OrcCAPITestBase, JITDylibLookup) { 278f2018d6cSLang Hames LLVMOrcJITDylibRef DoesNotExist = 279f2018d6cSLang Hames LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test"); 280f2018d6cSLang Hames ASSERT_FALSE(!!DoesNotExist); 281f2018d6cSLang Hames LLVMOrcJITDylibRef L1 = 282f2018d6cSLang Hames LLVMOrcExecutionSessionCreateBareJITDylib(ExecutionSession, "test"); 283f2018d6cSLang Hames LLVMOrcJITDylibRef L2 = 284f2018d6cSLang Hames LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test"); 285f2018d6cSLang Hames ASSERT_EQ(L1, L2) << "Located JIT Dylib is not equal to original"; 286f2018d6cSLang Hames } 287f2018d6cSLang Hames 288f2018d6cSLang Hames TEST_F(OrcCAPITestBase, MaterializationUnitCreation) { 289f2018d6cSLang Hames LLVMOrcSymbolStringPoolEntryRef Name = 290f2018d6cSLang Hames LLVMOrcLLJITMangleAndIntern(Jit, "test"); 291f2018d6cSLang Hames LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0}; 292f2018d6cSLang Hames LLVMOrcJITTargetAddress Addr = 293f2018d6cSLang Hames (LLVMOrcJITTargetAddress)(&materializationUnitFn); 294f2018d6cSLang Hames LLVMJITEvaluatedSymbol Sym = {Addr, Flags}; 295b425f556SLang Hames LLVMOrcCSymbolMapPair Pair = {Name, Sym}; 296b425f556SLang Hames LLVMOrcCSymbolMapPair Pairs[] = {Pair}; 297f2018d6cSLang Hames LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1); 29899a7e307SLang Hames if (LLVMErrorRef E = LLVMOrcJITDylibDefine(MainDylib, MU)) 29999a7e307SLang Hames FAIL() << "Unexpected error while adding \"test\" symbol (triple = " 30099a7e307SLang Hames << TargetTriple << "): " << toString(E); 301f2018d6cSLang Hames LLVMOrcJITTargetAddress OutAddr; 302f2018d6cSLang Hames if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &OutAddr, "test")) 303f2018d6cSLang Hames FAIL() << "Failed to look up \"test\" symbol (triple = " << TargetTriple 304f2018d6cSLang Hames << "): " << toString(E); 305f2018d6cSLang Hames ASSERT_EQ(Addr, OutAddr); 306f2018d6cSLang Hames } 307f2018d6cSLang Hames 308803c770eSLang Hames struct ExecutionSessionLookupHelper { 309803c770eSLang Hames bool ExpectSuccess = true; 310803c770eSLang Hames bool CallbackReceived = false; 311803c770eSLang Hames size_t NumExpectedPairs; 312803c770eSLang Hames LLVMOrcCSymbolMapPair *ExpectedMapping; 313803c770eSLang Hames }; 314803c770eSLang Hames 315803c770eSLang Hames static void executionSessionLookupHandlerCallback(LLVMErrorRef Err, 316803c770eSLang Hames LLVMOrcCSymbolMapPairs Result, 317803c770eSLang Hames size_t NumPairs, 318803c770eSLang Hames void *RawCtx) { 319803c770eSLang Hames auto *Ctx = static_cast<ExecutionSessionLookupHelper *>(RawCtx); 320803c770eSLang Hames Ctx->CallbackReceived = true; 321803c770eSLang Hames if (Ctx->ExpectSuccess) { 322803c770eSLang Hames EXPECT_THAT_ERROR(unwrap(Err), Succeeded()); 323803c770eSLang Hames EXPECT_EQ(NumPairs, Ctx->NumExpectedPairs) 324803c770eSLang Hames << "Expected " << Ctx->NumExpectedPairs << " entries in result, got " 325803c770eSLang Hames << NumPairs; 326803c770eSLang Hames auto ExpectedMappingEnd = Ctx->ExpectedMapping + Ctx->NumExpectedPairs; 327803c770eSLang Hames for (unsigned I = 0; I != NumPairs; ++I) { 328803c770eSLang Hames auto J = 329803c770eSLang Hames std::find_if(Ctx->ExpectedMapping, ExpectedMappingEnd, 330803c770eSLang Hames [N = Result[I].Name](const LLVMOrcCSymbolMapPair &Val) { 331803c770eSLang Hames return Val.Name == N; 332803c770eSLang Hames }); 333803c770eSLang Hames EXPECT_NE(J, ExpectedMappingEnd) 334803c770eSLang Hames << "Missing symbol \"" 335803c770eSLang Hames << LLVMOrcSymbolStringPoolEntryStr(Result[I].Name) << "\""; 336803c770eSLang Hames if (J != ExpectedMappingEnd) { 337803c770eSLang Hames EXPECT_EQ(Result[I].Sym.Address, J->Sym.Address) 338803c770eSLang Hames << "Result map for \"" << Result[I].Name 339803c770eSLang Hames << "\" differs from expected value: " 340803c770eSLang Hames << formatv("{0:x} vs {1:x}", Result[I].Sym.Address, J->Sym.Address); 341803c770eSLang Hames } 342803c770eSLang Hames } 343803c770eSLang Hames } else 344803c770eSLang Hames EXPECT_THAT_ERROR(unwrap(Err), Failed()); 345803c770eSLang Hames } 346803c770eSLang Hames 347803c770eSLang Hames TEST_F(OrcCAPITestBase, ExecutionSessionLookup_Success) { 348803c770eSLang Hames // Test a successful generic lookup. We will look up three symbols over two 349803c770eSLang Hames // JITDylibs: { "Foo" (Required), "Bar" (Weakly-ref), "Baz" (Required) } over 350803c770eSLang Hames // { MainJITDylib (Exported-only), ExtraJD (All symbols) }. 351803c770eSLang Hames // 352803c770eSLang Hames // Foo will be defined as exported in MainJD. 353803c770eSLang Hames // Bar will be defined as non-exported in MainJD. 354803c770eSLang Hames // Baz will be defined as non-exported in ExtraJD. 355803c770eSLang Hames // 356803c770eSLang Hames // This will require (1) that we find the regular exported symbol Foo in 357803c770eSLang Hames // MainJD, (2) that we *don't* find the non-exported symbol Bar in MainJD 358803c770eSLang Hames // but also don't error (since it's weakly referenced), and (3) that we 359803c770eSLang Hames // find the non-exported symbol Baz in ExtraJD (since we're searching all 360803c770eSLang Hames // symbols in ExtraJD). 361803c770eSLang Hames 362803c770eSLang Hames ExecutionSessionLookupHelper H; 363803c770eSLang Hames LLVMOrcSymbolStringPoolEntryRef Foo = LLVMOrcLLJITMangleAndIntern(Jit, "Foo"); 364803c770eSLang Hames LLVMOrcSymbolStringPoolEntryRef Bar = LLVMOrcLLJITMangleAndIntern(Jit, "Bar"); 365803c770eSLang Hames LLVMOrcSymbolStringPoolEntryRef Baz = LLVMOrcLLJITMangleAndIntern(Jit, "Baz"); 366803c770eSLang Hames 367803c770eSLang Hames // Create ExtraJD. 368803c770eSLang Hames LLVMOrcJITDylibRef ExtraJD = nullptr; 369803c770eSLang Hames if (auto E = LLVMOrcExecutionSessionCreateJITDylib(ExecutionSession, &ExtraJD, 370803c770eSLang Hames "ExtraJD")) { 371803c770eSLang Hames FAIL() << "Unexpected error while creating JITDylib \"ExtraJD\" (triple = " 372803c770eSLang Hames << TargetTriple << "): " << toString(E); 373803c770eSLang Hames return; 374803c770eSLang Hames } 375803c770eSLang Hames 376803c770eSLang Hames // Add exported symbols "Foo" and "Bar" to Main JITDylib. 377803c770eSLang Hames LLVMOrcRetainSymbolStringPoolEntry(Foo); 378803c770eSLang Hames LLVMOrcRetainSymbolStringPoolEntry(Bar); 379803c770eSLang Hames LLVMOrcCSymbolMapPair MainJDPairs[] = { 380803c770eSLang Hames {Foo, {0x1, {LLVMJITSymbolGenericFlagsExported, 0}}}, 381803c770eSLang Hames {Bar, {0x2, {LLVMJITSymbolGenericFlagsNone, 0}}}}; 382803c770eSLang Hames LLVMOrcMaterializationUnitRef MainJDMU = 383803c770eSLang Hames LLVMOrcAbsoluteSymbols(MainJDPairs, 2); 384803c770eSLang Hames if (LLVMErrorRef E = LLVMOrcJITDylibDefine(MainDylib, MainJDMU)) 385803c770eSLang Hames FAIL() << "Unexpected error while adding MainDylib symbols (triple = " 386803c770eSLang Hames << TargetTriple << "): " << toString(E); 387803c770eSLang Hames 388803c770eSLang Hames // Add non-exported symbol "Baz" to ExtraJD. 389803c770eSLang Hames LLVMOrcRetainSymbolStringPoolEntry(Baz); 390803c770eSLang Hames LLVMOrcCSymbolMapPair ExtraJDPairs[] = { 391803c770eSLang Hames {Baz, {0x3, {LLVMJITSymbolGenericFlagsNone, 0}}}}; 392803c770eSLang Hames LLVMOrcMaterializationUnitRef ExtraJDMU = 393803c770eSLang Hames LLVMOrcAbsoluteSymbols(ExtraJDPairs, 1); 394803c770eSLang Hames if (LLVMErrorRef E = LLVMOrcJITDylibDefine(ExtraJD, ExtraJDMU)) 395803c770eSLang Hames FAIL() << "Unexpected error while adding ExtraJD symbols (triple = " 396803c770eSLang Hames << TargetTriple << "): " << toString(E); 397803c770eSLang Hames 398803c770eSLang Hames // Create expected mapping for result: 399803c770eSLang Hames LLVMOrcCSymbolMapPair ExpectedMapping[] = { 400803c770eSLang Hames {Foo, {0x1, {LLVMJITSymbolGenericFlagsExported, 0}}}, 401803c770eSLang Hames {Baz, {0x3, {LLVMJITSymbolGenericFlagsNone, 0}}}}; 402803c770eSLang Hames H.ExpectedMapping = ExpectedMapping; 403803c770eSLang Hames H.NumExpectedPairs = 2; 404803c770eSLang Hames 405803c770eSLang Hames // Issue the lookup. We're using the default same-thread dispatch, so the 406803c770eSLang Hames // handler should have run by the time we return from this call. 407803c770eSLang Hames LLVMOrcCJITDylibSearchOrderElement SO[] = { 408803c770eSLang Hames {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly}, 409803c770eSLang Hames {ExtraJD, LLVMOrcJITDylibLookupFlagsMatchAllSymbols}}; 410803c770eSLang Hames 411803c770eSLang Hames LLVMOrcRetainSymbolStringPoolEntry(Foo); 412803c770eSLang Hames LLVMOrcRetainSymbolStringPoolEntry(Bar); 413803c770eSLang Hames LLVMOrcRetainSymbolStringPoolEntry(Baz); 414803c770eSLang Hames LLVMOrcCLookupSetElement LS[] = { 415803c770eSLang Hames {Foo, LLVMOrcSymbolLookupFlagsRequiredSymbol}, 416803c770eSLang Hames {Bar, LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol}, 417803c770eSLang Hames {Baz, LLVMOrcSymbolLookupFlagsRequiredSymbol}}; 418803c770eSLang Hames LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO, 419803c770eSLang Hames 2, LS, 3, executionSessionLookupHandlerCallback, 420803c770eSLang Hames &H); 421803c770eSLang Hames 422803c770eSLang Hames EXPECT_TRUE(H.CallbackReceived) << "Lookup callback never received"; 423803c770eSLang Hames 424803c770eSLang Hames // Release our local string ptrs. 425803c770eSLang Hames LLVMOrcReleaseSymbolStringPoolEntry(Baz); 426803c770eSLang Hames LLVMOrcReleaseSymbolStringPoolEntry(Bar); 427803c770eSLang Hames LLVMOrcReleaseSymbolStringPoolEntry(Foo); 428803c770eSLang Hames } 429803c770eSLang Hames 430803c770eSLang Hames TEST_F(OrcCAPITestBase, ExecutionSessionLookup_Failure) { 431803c770eSLang Hames // Test generic lookup failure case. We will look up a symbol in MainDylib 432803c770eSLang Hames // without defining it. We expect this to result in a symbol-not-found error. 433803c770eSLang Hames 434803c770eSLang Hames ExecutionSessionLookupHelper H; 435803c770eSLang Hames H.ExpectSuccess = false; 436803c770eSLang Hames 437803c770eSLang Hames LLVMOrcCJITDylibSearchOrderElement SO[] = { 438803c770eSLang Hames {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly}}; 439803c770eSLang Hames LLVMOrcCLookupSetElement LS[] = {{LLVMOrcLLJITMangleAndIntern(Jit, "Foo"), 440803c770eSLang Hames LLVMOrcSymbolLookupFlagsRequiredSymbol}}; 441803c770eSLang Hames LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO, 442803c770eSLang Hames 1, LS, 1, executionSessionLookupHandlerCallback, 443803c770eSLang Hames &H); 444803c770eSLang Hames 445803c770eSLang Hames EXPECT_TRUE(H.CallbackReceived) << "Lookup callback never received"; 446803c770eSLang Hames } 447803c770eSLang Hames 448f2018d6cSLang Hames TEST_F(OrcCAPITestBase, DefinitionGenerators) { 449f2018d6cSLang Hames LLVMOrcDefinitionGeneratorRef Gen = 450f2018d6cSLang Hames LLVMOrcCreateCustomCAPIDefinitionGenerator(&definitionGeneratorFn, 45114b7c108SLang Hames nullptr, nullptr); 452f2018d6cSLang Hames LLVMOrcJITDylibAddGenerator(MainDylib, Gen); 453f2018d6cSLang Hames LLVMOrcJITTargetAddress OutAddr; 454f2018d6cSLang Hames if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &OutAddr, "test")) 455f2018d6cSLang Hames FAIL() << "The DefinitionGenerator did not create symbol \"test\" " 456f2018d6cSLang Hames << "(triple = " << TargetTriple << "): " << toString(E); 457f2018d6cSLang Hames LLVMOrcJITTargetAddress ExpectedAddr = 458f2018d6cSLang Hames (LLVMOrcJITTargetAddress)(&materializationUnitFn); 459f2018d6cSLang Hames ASSERT_EQ(ExpectedAddr, OutAddr); 460f2018d6cSLang Hames } 461f2018d6cSLang Hames 4629a35c0cbSChen Zheng #if defined(_AIX) 4639a35c0cbSChen Zheng TEST_F(OrcCAPITestBase, DISABLED_ResourceTrackerDefinitionLifetime) { 4649a35c0cbSChen Zheng #else 465f2018d6cSLang Hames TEST_F(OrcCAPITestBase, ResourceTrackerDefinitionLifetime) { 4669a35c0cbSChen Zheng #endif 467f2018d6cSLang Hames // This test case ensures that all symbols loaded into a JITDylib with a 468f2018d6cSLang Hames // ResourceTracker attached are cleared from the JITDylib once the RT is 469f2018d6cSLang Hames // removed. 470f2018d6cSLang Hames LLVMOrcResourceTrackerRef RT = 471f2018d6cSLang Hames LLVMOrcJITDylibCreateResourceTracker(MainDylib); 4727b73cd68SLang Hames LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll"); 473f2018d6cSLang Hames if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, RT, TSM)) 474f2018d6cSLang Hames FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple 475f2018d6cSLang Hames << "): " << toString(E); 476f2018d6cSLang Hames LLVMOrcJITTargetAddress TestFnAddr; 477f2018d6cSLang Hames if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum")) 478f2018d6cSLang Hames FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple 479f2018d6cSLang Hames << "): " << toString(E); 480f2018d6cSLang Hames ASSERT_TRUE(!!TestFnAddr); 481f2018d6cSLang Hames LLVMOrcResourceTrackerRemove(RT); 482f2018d6cSLang Hames LLVMOrcJITTargetAddress OutAddr; 483f2018d6cSLang Hames LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &OutAddr, "sum"); 484f2018d6cSLang Hames ASSERT_TRUE(Err); 485f2018d6cSLang Hames LLVMConsumeError(Err); 486f2018d6cSLang Hames 487f2018d6cSLang Hames ASSERT_FALSE(OutAddr); 488f2018d6cSLang Hames LLVMOrcReleaseResourceTracker(RT); 489f2018d6cSLang Hames } 490f2018d6cSLang Hames 4919a35c0cbSChen Zheng #if defined(_AIX) 4929a35c0cbSChen Zheng TEST_F(OrcCAPITestBase, DISABLED_ResourceTrackerTransfer) { 4939a35c0cbSChen Zheng #else 494f2018d6cSLang Hames TEST_F(OrcCAPITestBase, ResourceTrackerTransfer) { 4959a35c0cbSChen Zheng #endif 496f2018d6cSLang Hames LLVMOrcResourceTrackerRef DefaultRT = 497f2018d6cSLang Hames LLVMOrcJITDylibGetDefaultResourceTracker(MainDylib); 498f2018d6cSLang Hames LLVMOrcResourceTrackerRef RT2 = 499f2018d6cSLang Hames LLVMOrcJITDylibCreateResourceTracker(MainDylib); 5007b73cd68SLang Hames LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll"); 501f2018d6cSLang Hames if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, DefaultRT, TSM)) 502f2018d6cSLang Hames FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple 503f2018d6cSLang Hames << "): " << toString(E); 504f2018d6cSLang Hames LLVMOrcJITTargetAddress Addr; 505f2018d6cSLang Hames if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &Addr, "sum")) 506f2018d6cSLang Hames FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple 507f2018d6cSLang Hames << "): " << toString(E); 508f2018d6cSLang Hames LLVMOrcResourceTrackerTransferTo(DefaultRT, RT2); 509f2018d6cSLang Hames LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "sum"); 510f2018d6cSLang Hames ASSERT_FALSE(Err); 511f2018d6cSLang Hames LLVMOrcReleaseResourceTracker(RT2); 512f2018d6cSLang Hames } 513f2018d6cSLang Hames 5149a35c0cbSChen Zheng #if defined(_AIX) 5159a35c0cbSChen Zheng TEST_F(OrcCAPITestBase, DISABLED_AddObjectBuffer) { 5169a35c0cbSChen Zheng #else 5177b73cd68SLang Hames TEST_F(OrcCAPITestBase, AddObjectBuffer) { 5189a35c0cbSChen Zheng #endif 5197b73cd68SLang Hames LLVMOrcObjectLayerRef ObjLinkingLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit); 5207b73cd68SLang Hames LLVMMemoryBufferRef ObjBuffer = createTestObject(SumExample, "sum.ll"); 5217b73cd68SLang Hames 5227b73cd68SLang Hames if (LLVMErrorRef E = LLVMOrcObjectLayerAddObjectFile(ObjLinkingLayer, 5237b73cd68SLang Hames MainDylib, ObjBuffer)) 5247b73cd68SLang Hames FAIL() << "Failed to add object file to ObjLinkingLayer (triple = " 5257b73cd68SLang Hames << TargetTriple << "): " << toString(E); 5267b73cd68SLang Hames 5277b73cd68SLang Hames LLVMOrcJITTargetAddress SumAddr; 5287b73cd68SLang Hames if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &SumAddr, "sum")) 5297b73cd68SLang Hames FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple 5307b73cd68SLang Hames << "): " << toString(E); 5317b73cd68SLang Hames ASSERT_TRUE(!!SumAddr); 5327b73cd68SLang Hames } 5337b73cd68SLang Hames 53440236257SStefan Gränitz // JITLink debug support plugins put information about JITed code in this GDB 53540236257SStefan Gränitz // JIT Interface global from OrcTargetProcess. 53640236257SStefan Gränitz extern "C" struct jit_descriptor __jit_debug_descriptor; 53754397f9aSStefan Gränitz 53854397f9aSStefan Gränitz static void *findLastDebugDescriptorEntryPtr() { 53954397f9aSStefan Gränitz struct jit_code_entry *Last = __jit_debug_descriptor.first_entry; 54054397f9aSStefan Gränitz while (Last && Last->next_entry) 54154397f9aSStefan Gränitz Last = Last->next_entry; 54254397f9aSStefan Gränitz return Last; 54354397f9aSStefan Gränitz } 54454397f9aSStefan Gränitz 54554397f9aSStefan Gränitz #if defined(_AIX) or not(defined(__ELF__) or defined(__MACH__)) 54654397f9aSStefan Gränitz TEST_F(OrcCAPITestBase, DISABLED_EnableDebugSupport) { 54754397f9aSStefan Gränitz #else 54854397f9aSStefan Gränitz static LLVM_ATTRIBUTE_USED void linkComponents() { 54954397f9aSStefan Gränitz errs() << "Linking in runtime functions\n" 55054397f9aSStefan Gränitz << (void *)&llvm_orc_registerJITLoaderGDBWrapper << '\n' 55154397f9aSStefan Gränitz << (void *)&llvm_orc_registerJITLoaderGDBAllocAction << '\n'; 55254397f9aSStefan Gränitz } 55354397f9aSStefan Gränitz TEST_F(OrcCAPITestBase, EnableDebugSupport) { 55454397f9aSStefan Gränitz #endif 55554397f9aSStefan Gränitz void *Before = findLastDebugDescriptorEntryPtr(); 55654397f9aSStefan Gränitz LLVMMemoryBufferRef ObjBuffer = createTestObject(SumDebugExample, "sum.ll"); 55754397f9aSStefan Gränitz LLVMOrcObjectLayerRef ObjLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit); 558e00ade11SStefan Gränitz 559e00ade11SStefan Gränitz if (LLVMErrorRef E = LLVMOrcLLJITEnableDebugSupport(Jit)) { 560e00ade11SStefan Gränitz EXPECT_FALSE(isa<ObjectLinkingLayer>(unwrap(ObjLayer))) 561e00ade11SStefan Gränitz << "Error testing LLJIT debug support " 562e00ade11SStefan Gränitz << "(triple = " << TargetTriple << "): " << toString(E); 563e00ade11SStefan Gränitz GTEST_SKIP() << "LLJIT C bindings provide debug support only for JITLink"; 564e00ade11SStefan Gränitz } 565e00ade11SStefan Gränitz 56654397f9aSStefan Gränitz if (LLVMErrorRef E = 56754397f9aSStefan Gränitz LLVMOrcObjectLayerAddObjectFile(ObjLayer, MainDylib, ObjBuffer)) 56854397f9aSStefan Gränitz FAIL() << "Failed to add object file to ObjLinkingLayer (triple = " 56954397f9aSStefan Gränitz << TargetTriple << "): " << toString(E); 57054397f9aSStefan Gränitz 57154397f9aSStefan Gränitz LLVMOrcJITTargetAddress SumAddr; 57254397f9aSStefan Gränitz if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &SumAddr, "sum")) 57354397f9aSStefan Gränitz FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple 57454397f9aSStefan Gränitz << "): " << toString(E); 57554397f9aSStefan Gränitz 57654397f9aSStefan Gränitz void *After = findLastDebugDescriptorEntryPtr(); 57754397f9aSStefan Gränitz ASSERT_NE(Before, After); 57854397f9aSStefan Gränitz } 57954397f9aSStefan Gränitz 5809a35c0cbSChen Zheng #if defined(_AIX) 5819a35c0cbSChen Zheng TEST_F(OrcCAPITestBase, DISABLED_ExecutionTest) { 5829a35c0cbSChen Zheng #else 583f2018d6cSLang Hames TEST_F(OrcCAPITestBase, ExecutionTest) { 5849a35c0cbSChen Zheng #endif 585f2018d6cSLang Hames using SumFunctionType = int32_t (*)(int32_t, int32_t); 586f2018d6cSLang Hames 587f2018d6cSLang Hames // This test performs OrcJIT compilation of a simple sum module 588f2018d6cSLang Hames LLVMInitializeNativeAsmPrinter(); 5897b73cd68SLang Hames LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll"); 590f2018d6cSLang Hames if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModule(Jit, MainDylib, TSM)) 591f2018d6cSLang Hames FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple 592f2018d6cSLang Hames << ")" << toString(E); 593f2018d6cSLang Hames LLVMOrcJITTargetAddress TestFnAddr; 594f2018d6cSLang Hames if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum")) 595f2018d6cSLang Hames FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple 596f2018d6cSLang Hames << "): " << toString(E); 597f2018d6cSLang Hames auto *SumFn = (SumFunctionType)(TestFnAddr); 598f2018d6cSLang Hames int32_t Result = SumFn(1, 1); 599f2018d6cSLang Hames ASSERT_EQ(2, Result); 600f2018d6cSLang Hames } 6013321f482SValentin Churavy 6023321f482SValentin Churavy void Destroy(void *Ctx) {} 6033321f482SValentin Churavy 6043321f482SValentin Churavy void TargetFn() {} 6053321f482SValentin Churavy 6063321f482SValentin Churavy void Materialize(void *Ctx, LLVMOrcMaterializationResponsibilityRef MR) { 6073321f482SValentin Churavy LLVMOrcJITDylibRef JD = 6083321f482SValentin Churavy LLVMOrcMaterializationResponsibilityGetTargetDylib(MR); 6093321f482SValentin Churavy ASSERT_TRUE(!!JD); 6103321f482SValentin Churavy 6113321f482SValentin Churavy LLVMOrcExecutionSessionRef ES = 6123321f482SValentin Churavy LLVMOrcMaterializationResponsibilityGetExecutionSession(MR); 6133321f482SValentin Churavy ASSERT_TRUE(!!ES); 6143321f482SValentin Churavy 6153321f482SValentin Churavy LLVMOrcSymbolStringPoolEntryRef InitSym = 6163321f482SValentin Churavy LLVMOrcMaterializationResponsibilityGetInitializerSymbol(MR); 6173321f482SValentin Churavy ASSERT_TRUE(!InitSym); 6183321f482SValentin Churavy 6193321f482SValentin Churavy size_t NumSymbols; 6203321f482SValentin Churavy LLVMOrcCSymbolFlagsMapPairs Symbols = 6213321f482SValentin Churavy LLVMOrcMaterializationResponsibilityGetSymbols(MR, &NumSymbols); 6223321f482SValentin Churavy 6233321f482SValentin Churavy ASSERT_TRUE(!!Symbols); 6243321f482SValentin Churavy ASSERT_EQ(NumSymbols, (size_t)1); 6253321f482SValentin Churavy 6263321f482SValentin Churavy LLVMOrcSymbolStringPoolEntryRef *RequestedSymbols = 6273321f482SValentin Churavy LLVMOrcMaterializationResponsibilityGetRequestedSymbols(MR, &NumSymbols); 6283321f482SValentin Churavy 6293321f482SValentin Churavy ASSERT_TRUE(!!RequestedSymbols); 6303321f482SValentin Churavy ASSERT_EQ(NumSymbols, (size_t)1); 6313321f482SValentin Churavy 6323321f482SValentin Churavy LLVMOrcCSymbolFlagsMapPair TargetSym = Symbols[0]; 6333321f482SValentin Churavy 6343321f482SValentin Churavy ASSERT_EQ(RequestedSymbols[0], TargetSym.Name); 6353321f482SValentin Churavy LLVMOrcRetainSymbolStringPoolEntry(TargetSym.Name); 6363321f482SValentin Churavy 6373321f482SValentin Churavy LLVMOrcDisposeCSymbolFlagsMap(Symbols); 6383321f482SValentin Churavy LLVMOrcDisposeSymbols(RequestedSymbols); 6393321f482SValentin Churavy 6403321f482SValentin Churavy LLVMOrcJITTargetAddress Addr = (LLVMOrcJITTargetAddress)(&TargetFn); 6413321f482SValentin Churavy 6423321f482SValentin Churavy LLVMJITSymbolFlags Flags = { 6433321f482SValentin Churavy LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0}; 6443321f482SValentin Churavy ASSERT_EQ(TargetSym.Flags.GenericFlags, Flags.GenericFlags); 6453321f482SValentin Churavy ASSERT_EQ(TargetSym.Flags.TargetFlags, Flags.TargetFlags); 6463321f482SValentin Churavy 6473321f482SValentin Churavy LLVMJITEvaluatedSymbol Sym = {Addr, Flags}; 6483321f482SValentin Churavy 6493321f482SValentin Churavy LLVMOrcLLJITRef J = (LLVMOrcLLJITRef)Ctx; 6503321f482SValentin Churavy 6513321f482SValentin Churavy LLVMOrcSymbolStringPoolEntryRef OtherSymbol = 6523321f482SValentin Churavy LLVMOrcLLJITMangleAndIntern(J, "other"); 6533321f482SValentin Churavy LLVMOrcSymbolStringPoolEntryRef DependencySymbol = 6543321f482SValentin Churavy LLVMOrcLLJITMangleAndIntern(J, "dependency"); 6553321f482SValentin Churavy 6563321f482SValentin Churavy LLVMOrcRetainSymbolStringPoolEntry(OtherSymbol); 6573321f482SValentin Churavy LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol); 6583321f482SValentin Churavy LLVMOrcCSymbolFlagsMapPair NewSymbols[] = { 6593321f482SValentin Churavy {OtherSymbol, Flags}, 6603321f482SValentin Churavy {DependencySymbol, Flags}, 6613321f482SValentin Churavy }; 6623321f482SValentin Churavy LLVMOrcMaterializationResponsibilityDefineMaterializing(MR, NewSymbols, 2); 6633321f482SValentin Churavy 6643321f482SValentin Churavy LLVMOrcRetainSymbolStringPoolEntry(OtherSymbol); 6653321f482SValentin Churavy LLVMOrcMaterializationResponsibilityRef OtherMR = NULL; 6663321f482SValentin Churavy { 6673321f482SValentin Churavy LLVMErrorRef Err = LLVMOrcMaterializationResponsibilityDelegate( 6683321f482SValentin Churavy MR, &OtherSymbol, 1, &OtherMR); 6693321f482SValentin Churavy if (Err) { 6703321f482SValentin Churavy char *ErrMsg = LLVMGetErrorMessage(Err); 6713321f482SValentin Churavy fprintf(stderr, "Error: %s\n", ErrMsg); 6723321f482SValentin Churavy LLVMDisposeErrorMessage(ErrMsg); 6733321f482SValentin Churavy LLVMOrcMaterializationResponsibilityFailMaterialization(MR); 6743321f482SValentin Churavy LLVMOrcDisposeMaterializationResponsibility(MR); 6753321f482SValentin Churavy return; 6763321f482SValentin Churavy } 6773321f482SValentin Churavy } 6783321f482SValentin Churavy assert(OtherMR); 6793321f482SValentin Churavy 680b425f556SLang Hames LLVMOrcCSymbolMapPair OtherPair = {OtherSymbol, Sym}; 6813321f482SValentin Churavy LLVMOrcMaterializationUnitRef OtherMU = LLVMOrcAbsoluteSymbols(&OtherPair, 1); 6823321f482SValentin Churavy // OtherSymbol is no longer owned by us 6833321f482SValentin Churavy { 6843321f482SValentin Churavy LLVMErrorRef Err = 6853321f482SValentin Churavy LLVMOrcMaterializationResponsibilityReplace(OtherMR, OtherMU); 6863321f482SValentin Churavy if (Err) { 6873321f482SValentin Churavy char *ErrMsg = LLVMGetErrorMessage(Err); 6883321f482SValentin Churavy fprintf(stderr, "Error: %s\n", ErrMsg); 6893321f482SValentin Churavy LLVMDisposeErrorMessage(ErrMsg); 6903321f482SValentin Churavy 6913321f482SValentin Churavy LLVMOrcMaterializationResponsibilityFailMaterialization(OtherMR); 6923321f482SValentin Churavy LLVMOrcMaterializationResponsibilityFailMaterialization(MR); 6933321f482SValentin Churavy 6943321f482SValentin Churavy LLVMOrcDisposeMaterializationResponsibility(OtherMR); 6953321f482SValentin Churavy LLVMOrcDisposeMaterializationResponsibility(MR); 6963321f482SValentin Churavy LLVMOrcDisposeMaterializationUnit(OtherMU); 6973321f482SValentin Churavy return; 6983321f482SValentin Churavy } 6993321f482SValentin Churavy } 7003321f482SValentin Churavy LLVMOrcDisposeMaterializationResponsibility(OtherMR); 7013321f482SValentin Churavy 7023321f482SValentin Churavy // FIXME: Implement async lookup 7033321f482SValentin Churavy LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol); 704b425f556SLang Hames LLVMOrcCSymbolMapPair Pair = {DependencySymbol, Sym}; 7053321f482SValentin Churavy LLVMOrcMaterializationResponsibilityNotifyResolved(MR, &Pair, 1); 7063321f482SValentin Churavy // DependencySymbol no longer owned by us 7073321f482SValentin Churavy 7083321f482SValentin Churavy Pair = {TargetSym.Name, Sym}; 7093321f482SValentin Churavy LLVMOrcMaterializationResponsibilityNotifyResolved(MR, &Pair, 1); 7103321f482SValentin Churavy 711ebe8733aSlhames LLVMOrcRetainSymbolStringPoolEntry(TargetSym.Name); 712ebe8733aSlhames LLVMOrcCDependenceMapPair Dependency = {JD, {&DependencySymbol, 1}}; 713ebe8733aSlhames LLVMOrcCSymbolDependenceGroup DependenceSet = { 714ebe8733aSlhames /*.Symbols = */ {/*.Symbols = */ &TargetSym.Name, /* .Length = */ 1}, 715ebe8733aSlhames /* .Dependencies = */ &Dependency, 716ebe8733aSlhames /* .NumDependencies = */ 1}; 717ebe8733aSlhames 718ebe8733aSlhames LLVMOrcMaterializationResponsibilityNotifyEmitted(MR, &DependenceSet, 1); 7193321f482SValentin Churavy LLVMOrcDisposeMaterializationResponsibility(MR); 7203321f482SValentin Churavy } 7213321f482SValentin Churavy 7223321f482SValentin Churavy TEST_F(OrcCAPITestBase, MaterializationResponsibility) { 7233321f482SValentin Churavy LLVMJITSymbolFlags Flags = { 7243321f482SValentin Churavy LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0}; 7253321f482SValentin Churavy LLVMOrcCSymbolFlagsMapPair Sym = {LLVMOrcLLJITMangleAndIntern(Jit, "foo"), 7263321f482SValentin Churavy Flags}; 7273321f482SValentin Churavy 7283321f482SValentin Churavy LLVMOrcMaterializationUnitRef MU = LLVMOrcCreateCustomMaterializationUnit( 7293321f482SValentin Churavy "MU", (void *)Jit, &Sym, 1, NULL, &Materialize, NULL, &Destroy); 7303321f482SValentin Churavy LLVMOrcJITDylibRef JD = LLVMOrcLLJITGetMainJITDylib(Jit); 7313321f482SValentin Churavy LLVMOrcJITDylibDefine(JD, MU); 7323321f482SValentin Churavy 7333321f482SValentin Churavy LLVMOrcJITTargetAddress Addr; 7343321f482SValentin Churavy if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "foo")) { 7353321f482SValentin Churavy FAIL() << "foo was not materialized " << toString(Err); 7363321f482SValentin Churavy } 7373321f482SValentin Churavy ASSERT_TRUE(!!Addr); 7383321f482SValentin Churavy ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn); 7393321f482SValentin Churavy 7403321f482SValentin Churavy if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "other")) { 7413321f482SValentin Churavy FAIL() << "other was not materialized " << toString(Err); 7423321f482SValentin Churavy } 7433321f482SValentin Churavy ASSERT_TRUE(!!Addr); 7443321f482SValentin Churavy ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn); 7453321f482SValentin Churavy 7463321f482SValentin Churavy if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "dependency")) { 7473321f482SValentin Churavy FAIL() << "dependency was not materialized " << toString(Err); 7483321f482SValentin Churavy } 7493321f482SValentin Churavy ASSERT_TRUE(!!Addr); 7503321f482SValentin Churavy ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn); 7513321f482SValentin Churavy } 75214b7c108SLang Hames 75314b7c108SLang Hames struct SuspendedLookupContext { 75414b7c108SLang Hames std::function<void()> AsyncWork; 75514b7c108SLang Hames LLVMOrcSymbolStringPoolEntryRef NameToGenerate; 75614b7c108SLang Hames JITTargetAddress AddrToGenerate; 75714b7c108SLang Hames 75814b7c108SLang Hames bool Disposed = false; 75914b7c108SLang Hames bool QueryCompleted = true; 76014b7c108SLang Hames }; 76114b7c108SLang Hames 76214b7c108SLang Hames static LLVMErrorRef TryToGenerateWithSuspendedLookup( 76314b7c108SLang Hames LLVMOrcDefinitionGeneratorRef GeneratorObj, void *RawCtx, 76414b7c108SLang Hames LLVMOrcLookupStateRef *LookupState, LLVMOrcLookupKind Kind, 76514b7c108SLang Hames LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags JDLookupFlags, 76614b7c108SLang Hames LLVMOrcCLookupSet LookupSet, size_t LookupSetSize) { 76714b7c108SLang Hames 76814b7c108SLang Hames auto *Ctx = static_cast<SuspendedLookupContext *>(RawCtx); 76914b7c108SLang Hames 77014b7c108SLang Hames assert(LookupSetSize == 1); 77114b7c108SLang Hames assert(LookupSet[0].Name == Ctx->NameToGenerate); 77214b7c108SLang Hames 77314b7c108SLang Hames LLVMJITEvaluatedSymbol Sym = {0x1234, {LLVMJITSymbolGenericFlagsExported, 0}}; 77414b7c108SLang Hames LLVMOrcRetainSymbolStringPoolEntry(LookupSet[0].Name); 77514b7c108SLang Hames LLVMOrcCSymbolMapPair Pair = {LookupSet[0].Name, Sym}; 77614b7c108SLang Hames LLVMOrcCSymbolMapPair Pairs[] = {Pair}; 77714b7c108SLang Hames LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1); 77814b7c108SLang Hames 77914b7c108SLang Hames // Capture and reset LookupState to suspend the lookup. We'll continue it in 78014b7c108SLang Hames // the SuspendedLookup testcase below. 78114b7c108SLang Hames Ctx->AsyncWork = [LS = *LookupState, JD, MU]() { 78214b7c108SLang Hames LLVMErrorRef Err = LLVMOrcJITDylibDefine(JD, MU); 78314b7c108SLang Hames LLVMOrcLookupStateContinueLookup(LS, Err); 78414b7c108SLang Hames }; 78514b7c108SLang Hames *LookupState = nullptr; 78614b7c108SLang Hames return LLVMErrorSuccess; 78714b7c108SLang Hames } 78814b7c108SLang Hames 78914b7c108SLang Hames static void DisposeSuspendedLookupContext(void *Ctx) { 79014b7c108SLang Hames static_cast<SuspendedLookupContext *>(Ctx)->Disposed = true; 79114b7c108SLang Hames } 79214b7c108SLang Hames 79314b7c108SLang Hames static void 79414b7c108SLang Hames suspendLookupTestLookupHandlerCallback(LLVMErrorRef Err, 79514b7c108SLang Hames LLVMOrcCSymbolMapPairs Result, 79614b7c108SLang Hames size_t NumPairs, void *RawCtx) { 79714b7c108SLang Hames if (Err) { 79814b7c108SLang Hames FAIL() << "Suspended DefinitionGenerator did not create symbol \"foo\": " 79914b7c108SLang Hames << toString(Err); 80014b7c108SLang Hames return; 80114b7c108SLang Hames } 80214b7c108SLang Hames 80314b7c108SLang Hames EXPECT_EQ(NumPairs, 1U) 80414b7c108SLang Hames << "Unexpected number of result entries: expected 1, got " << NumPairs; 80514b7c108SLang Hames 80614b7c108SLang Hames auto *Ctx = static_cast<SuspendedLookupContext *>(RawCtx); 80714b7c108SLang Hames EXPECT_EQ(Result[0].Name, Ctx->NameToGenerate); 80814b7c108SLang Hames EXPECT_EQ(Result[0].Sym.Address, Ctx->AddrToGenerate); 80914b7c108SLang Hames 81014b7c108SLang Hames Ctx->QueryCompleted = true; 81114b7c108SLang Hames } 81214b7c108SLang Hames 81314b7c108SLang Hames TEST_F(OrcCAPITestBase, SuspendedLookup) { 81414b7c108SLang Hames // Test that we can suspend lookup in a custom generator. 81514b7c108SLang Hames SuspendedLookupContext Ctx; 81614b7c108SLang Hames Ctx.NameToGenerate = LLVMOrcLLJITMangleAndIntern(Jit, "foo"); 81714b7c108SLang Hames Ctx.AddrToGenerate = 0x1234; 81814b7c108SLang Hames 81914b7c108SLang Hames // Add generator. 82014b7c108SLang Hames LLVMOrcJITDylibAddGenerator(MainDylib, 82114b7c108SLang Hames LLVMOrcCreateCustomCAPIDefinitionGenerator( 82214b7c108SLang Hames &TryToGenerateWithSuspendedLookup, &Ctx, 82314b7c108SLang Hames DisposeSuspendedLookupContext)); 82414b7c108SLang Hames 82514b7c108SLang Hames // Expect no work to do before the lookup. 82614b7c108SLang Hames EXPECT_FALSE(Ctx.AsyncWork) << "Unexpected generator work before lookup"; 82714b7c108SLang Hames 82814b7c108SLang Hames // Issue lookup. This should trigger the generator, but generation should 82914b7c108SLang Hames // be suspended. 83014b7c108SLang Hames LLVMOrcCJITDylibSearchOrderElement SO[] = { 83114b7c108SLang Hames {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly}}; 83214b7c108SLang Hames LLVMOrcRetainSymbolStringPoolEntry(Ctx.NameToGenerate); 83314b7c108SLang Hames LLVMOrcCLookupSetElement LS[] = { 83414b7c108SLang Hames {Ctx.NameToGenerate, LLVMOrcSymbolLookupFlagsRequiredSymbol}}; 83514b7c108SLang Hames LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO, 83614b7c108SLang Hames 1, LS, 1, 83714b7c108SLang Hames suspendLookupTestLookupHandlerCallback, &Ctx); 83814b7c108SLang Hames 83914b7c108SLang Hames // Expect that we now have generator work to do. 84014b7c108SLang Hames EXPECT_TRUE(Ctx.AsyncWork) 84114b7c108SLang Hames << "Failed to generator (or failed to suspend generator)"; 84214b7c108SLang Hames 84314b7c108SLang Hames // Do the work. This should allow the query to complete. 84414b7c108SLang Hames Ctx.AsyncWork(); 84514b7c108SLang Hames 84614b7c108SLang Hames // Check that the query completed. 84714b7c108SLang Hames EXPECT_TRUE(Ctx.QueryCompleted); 84814b7c108SLang Hames 84914b7c108SLang Hames // Release our local copy of the string. 85014b7c108SLang Hames LLVMOrcReleaseSymbolStringPoolEntry(Ctx.NameToGenerate); 85114b7c108SLang Hames 85214b7c108SLang Hames // Explicitly tear down the JIT. 85314b7c108SLang Hames LLVMOrcDisposeLLJIT(Jit); 85414b7c108SLang Hames Jit = nullptr; 85514b7c108SLang Hames 85614b7c108SLang Hames // Check that the generator context was "destroyed". 85714b7c108SLang Hames EXPECT_TRUE(Ctx.Disposed); 85814b7c108SLang Hames } 859