xref: /llvm-project/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp (revision 9f73c69e5aa2d1112f72b2e18d4ae0462a6a2042)
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