1 //===--- OrcCAPITest.cpp - Unit tests for the OrcJIT v2 C API ---*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm-c/Core.h"
10 #include "llvm-c/Error.h"
11 #include "llvm-c/LLJIT.h"
12 #include "llvm-c/Orc.h"
13 #include "gtest/gtest.h"
14 
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
17 #include "llvm/IR/LLVMContext.h"
18 #include "llvm/IR/Module.h"
19 #include "llvm/IRReader/IRReader.h"
20 #include "llvm/Support/Error.h"
21 #include "llvm/Support/SourceMgr.h"
22 #include <string>
23 
24 using namespace llvm;
25 using namespace llvm::orc;
26 
27 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
28 
29 // OrcCAPITestBase contains several helper methods and pointers for unit tests
30 // written for the LLVM-C API. It provides the following helpers:
31 //
32 // 1. Jit: an LLVMOrcLLJIT instance which is freed upon test exit
33 // 2. ExecutionSession: the LLVMOrcExecutionSession for the JIT
34 // 3. MainDylib: the main JITDylib for the LLJIT instance
35 // 4. materializationUnitFn: function pointer to an empty function, used for
36 //                           materialization unit testing
37 // 5. definitionGeneratorFn: function pointer for a basic
38 //                           LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction
39 // 6. createTestModule: helper method for creating a basic thread-safe-module
40 class OrcCAPITestBase : public testing::Test {
41 protected:
42   LLVMOrcLLJITRef Jit = nullptr;
43   LLVMOrcExecutionSessionRef ExecutionSession = nullptr;
44   LLVMOrcJITDylibRef MainDylib = nullptr;
45 
46 public:
47   static void SetUpTestCase() {
48     LLVMInitializeNativeTarget();
49     LLVMInitializeNativeAsmParser();
50     LLVMInitializeNativeAsmPrinter();
51 
52     // Attempt to set up a JIT instance once to verify that we can.
53     LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr;
54     if (LLVMErrorRef E = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB)) {
55       // If setup fails then disable these tests.
56       LLVMConsumeError(E);
57       TargetSupported = false;
58       return;
59     }
60 
61     // Capture the target triple. We'll use it for both verification that
62     // this target is *supposed* to be supported, and error messages in
63     // the case that it fails anyway.
64     char *TT = LLVMOrcJITTargetMachineBuilderGetTargetTriple(JTMB);
65     TargetTriple = TT;
66     LLVMDisposeMessage(TT);
67 
68     if (!isSupported(TargetTriple)) {
69       // If this triple isn't supported then bail out.
70       TargetSupported = false;
71       LLVMOrcDisposeJITTargetMachineBuilder(JTMB);
72       return;
73     }
74 
75     LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder();
76     LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB);
77     LLVMOrcLLJITRef J;
78     if (LLVMErrorRef E = LLVMOrcCreateLLJIT(&J, Builder)) {
79       // If setup fails then disable these tests.
80       TargetSupported = false;
81       LLVMConsumeError(E);
82       return;
83     }
84 
85     LLVMOrcDisposeLLJIT(J);
86     TargetSupported = true;
87   }
88 
89   void SetUp() override {
90     if (!TargetSupported)
91       GTEST_SKIP();
92 
93     LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr;
94     LLVMErrorRef E1 = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB);
95     assert(E1 == LLVMErrorSuccess && "Expected call to detect host to succeed");
96     (void)E1;
97 
98     LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder();
99     LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB);
100     LLVMErrorRef E2 = LLVMOrcCreateLLJIT(&Jit, Builder);
101     assert(E2 == LLVMErrorSuccess &&
102            "Expected call to create LLJIT to succeed");
103     (void)E2;
104     ExecutionSession = LLVMOrcLLJITGetExecutionSession(Jit);
105     MainDylib = LLVMOrcLLJITGetMainJITDylib(Jit);
106   }
107   void TearDown() override {
108     LLVMOrcDisposeLLJIT(Jit);
109     Jit = nullptr;
110   }
111 
112 protected:
113   static bool isSupported(StringRef Triple) {
114     // TODO: Print error messages in failure logs, use them to audit this list.
115     // Some architectures may be unsupportable or missing key components, but
116     // some may just be failing due to bugs in this testcase.
117     if (Triple.startswith("armv7") || Triple.startswith("armv8l"))
118       return false;
119     llvm::Triple T(Triple);
120     if (T.isOSAIX() && T.isPPC64())
121       return false;
122     return true;
123   }
124 
125   static void materializationUnitFn() {}
126 
127   // Stub definition generator, where all Names are materialized from the
128   // materializationUnitFn() test function and defined into the JIT Dylib
129   static LLVMErrorRef
130   definitionGeneratorFn(LLVMOrcDefinitionGeneratorRef G, void *Ctx,
131                         LLVMOrcLookupStateRef *LS, LLVMOrcLookupKind K,
132                         LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags F,
133                         LLVMOrcCLookupSet Names, size_t NamesCount) {
134     for (size_t I = 0; I < NamesCount; I++) {
135       LLVMOrcCLookupSetElement Element = Names[I];
136       LLVMOrcJITTargetAddress Addr =
137           (LLVMOrcJITTargetAddress)(&materializationUnitFn);
138       LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0};
139       LLVMJITEvaluatedSymbol Sym = {Addr, Flags};
140       LLVMOrcRetainSymbolStringPoolEntry(Element.Name);
141       LLVMJITCSymbolMapPair Pair = {Element.Name, Sym};
142       LLVMJITCSymbolMapPair Pairs[] = {Pair};
143       LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1);
144       LLVMErrorRef Err = LLVMOrcJITDylibDefine(JD, MU);
145       if (Err)
146         return Err;
147     }
148     return LLVMErrorSuccess;
149   }
150 
151   static Error createSMDiagnosticError(llvm::SMDiagnostic &Diag) {
152     std::string Msg;
153     {
154       raw_string_ostream OS(Msg);
155       Diag.print("", OS);
156     }
157     return make_error<StringError>(std::move(Msg), inconvertibleErrorCode());
158   }
159 
160   // Create an LLVM IR module from the given StringRef.
161   static Expected<std::unique_ptr<Module>>
162   parseTestModule(LLVMContext &Ctx, StringRef Source, StringRef Name) {
163     assert(TargetSupported &&
164            "Attempted to create module for unsupported target");
165     SMDiagnostic Err;
166     if (auto M = parseIR(MemoryBufferRef(Source, Name), Err, Ctx))
167       return std::move(M);
168     return createSMDiagnosticError(Err);
169   }
170 
171   // returns the sum of its two parameters
172   static LLVMOrcThreadSafeModuleRef createTestModule(StringRef Source,
173                                                      StringRef Name) {
174     auto Ctx = std::make_unique<LLVMContext>();
175     auto M = cantFail(parseTestModule(*Ctx, Source, Name));
176     return wrap(new ThreadSafeModule(std::move(M), std::move(Ctx)));
177   }
178 
179   static LLVMMemoryBufferRef createTestObject(StringRef Source,
180                                               StringRef Name) {
181     auto Ctx = std::make_unique<LLVMContext>();
182     auto M = cantFail(parseTestModule(*Ctx, Source, Name));
183 
184     auto JTMB = cantFail(JITTargetMachineBuilder::detectHost());
185     M->setDataLayout(cantFail(JTMB.getDefaultDataLayoutForTarget()));
186     auto TM = cantFail(JTMB.createTargetMachine());
187 
188     SimpleCompiler SC(*TM);
189     auto ObjBuffer = cantFail(SC(*M));
190     return wrap(ObjBuffer.release());
191   }
192 
193   static std::string TargetTriple;
194   static bool TargetSupported;
195 };
196 
197 std::string OrcCAPITestBase::TargetTriple;
198 bool OrcCAPITestBase::TargetSupported = false;
199 
200 namespace {
201 
202 constexpr StringRef SumExample =
203     R"(
204     define i32 @sum(i32 %x, i32 %y) {
205     entry:
206       %r = add nsw i32 %x, %y
207       ret i32 %r
208     }
209   )";
210 
211 } // end anonymous namespace.
212 
213 // Consumes the given error ref and returns the string error message.
214 static std::string toString(LLVMErrorRef E) {
215   char *ErrMsg = LLVMGetErrorMessage(E);
216   std::string Result(ErrMsg);
217   LLVMDisposeErrorMessage(ErrMsg);
218   return Result;
219 }
220 
221 TEST_F(OrcCAPITestBase, SymbolStringPoolUniquing) {
222   LLVMOrcSymbolStringPoolEntryRef E1 =
223       LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa");
224   LLVMOrcSymbolStringPoolEntryRef E2 =
225       LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa");
226   LLVMOrcSymbolStringPoolEntryRef E3 =
227       LLVMOrcExecutionSessionIntern(ExecutionSession, "bbb");
228   const char *SymbolName = LLVMOrcSymbolStringPoolEntryStr(E1);
229   ASSERT_EQ(E1, E2) << "String pool entries are not unique";
230   ASSERT_NE(E1, E3) << "Unique symbol pool entries are equal";
231   ASSERT_STREQ("aaa", SymbolName) << "String value of symbol is not equal";
232   LLVMOrcReleaseSymbolStringPoolEntry(E1);
233   LLVMOrcReleaseSymbolStringPoolEntry(E2);
234   LLVMOrcReleaseSymbolStringPoolEntry(E3);
235 }
236 
237 TEST_F(OrcCAPITestBase, JITDylibLookup) {
238   LLVMOrcJITDylibRef DoesNotExist =
239       LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test");
240   ASSERT_FALSE(!!DoesNotExist);
241   LLVMOrcJITDylibRef L1 =
242       LLVMOrcExecutionSessionCreateBareJITDylib(ExecutionSession, "test");
243   LLVMOrcJITDylibRef L2 =
244       LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test");
245   ASSERT_EQ(L1, L2) << "Located JIT Dylib is not equal to original";
246 }
247 
248 TEST_F(OrcCAPITestBase, MaterializationUnitCreation) {
249   LLVMOrcSymbolStringPoolEntryRef Name =
250       LLVMOrcLLJITMangleAndIntern(Jit, "test");
251   LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0};
252   LLVMOrcJITTargetAddress Addr =
253       (LLVMOrcJITTargetAddress)(&materializationUnitFn);
254   LLVMJITEvaluatedSymbol Sym = {Addr, Flags};
255   LLVMJITCSymbolMapPair Pair = {Name, Sym};
256   LLVMJITCSymbolMapPair Pairs[] = {Pair};
257   LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1);
258   LLVMOrcJITDylibDefine(MainDylib, MU);
259   LLVMOrcJITTargetAddress OutAddr;
260   if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &OutAddr, "test"))
261     FAIL() << "Failed to look up \"test\" symbol (triple = " << TargetTriple
262            << "): " << toString(E);
263   ASSERT_EQ(Addr, OutAddr);
264 }
265 
266 TEST_F(OrcCAPITestBase, DefinitionGenerators) {
267   LLVMOrcDefinitionGeneratorRef Gen =
268       LLVMOrcCreateCustomCAPIDefinitionGenerator(&definitionGeneratorFn,
269                                                  nullptr);
270   LLVMOrcJITDylibAddGenerator(MainDylib, Gen);
271   LLVMOrcJITTargetAddress OutAddr;
272   if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &OutAddr, "test"))
273     FAIL() << "The DefinitionGenerator did not create symbol \"test\" "
274            << "(triple = " << TargetTriple << "): " << toString(E);
275   LLVMOrcJITTargetAddress ExpectedAddr =
276       (LLVMOrcJITTargetAddress)(&materializationUnitFn);
277   ASSERT_EQ(ExpectedAddr, OutAddr);
278 }
279 
280 TEST_F(OrcCAPITestBase, ResourceTrackerDefinitionLifetime) {
281   // This test case ensures that all symbols loaded into a JITDylib with a
282   // ResourceTracker attached are cleared from the JITDylib once the RT is
283   // removed.
284   LLVMOrcResourceTrackerRef RT =
285       LLVMOrcJITDylibCreateResourceTracker(MainDylib);
286   LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");
287   if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, RT, TSM))
288     FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple
289            << "): " << toString(E);
290   LLVMOrcJITTargetAddress TestFnAddr;
291   if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum"))
292     FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple
293            << "): " << toString(E);
294   ASSERT_TRUE(!!TestFnAddr);
295   LLVMOrcResourceTrackerRemove(RT);
296   LLVMOrcJITTargetAddress OutAddr;
297   LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &OutAddr, "sum");
298   ASSERT_TRUE(Err);
299   LLVMConsumeError(Err);
300 
301   ASSERT_FALSE(OutAddr);
302   LLVMOrcReleaseResourceTracker(RT);
303 }
304 
305 TEST_F(OrcCAPITestBase, ResourceTrackerTransfer) {
306   LLVMOrcResourceTrackerRef DefaultRT =
307       LLVMOrcJITDylibGetDefaultResourceTracker(MainDylib);
308   LLVMOrcResourceTrackerRef RT2 =
309       LLVMOrcJITDylibCreateResourceTracker(MainDylib);
310   LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");
311   if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, DefaultRT, TSM))
312     FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple
313            << "): " << toString(E);
314   LLVMOrcJITTargetAddress Addr;
315   if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &Addr, "sum"))
316     FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple
317            << "): " << toString(E);
318   LLVMOrcResourceTrackerTransferTo(DefaultRT, RT2);
319   LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "sum");
320   ASSERT_FALSE(Err);
321   LLVMOrcReleaseResourceTracker(RT2);
322 }
323 
324 TEST_F(OrcCAPITestBase, AddObjectBuffer) {
325   LLVMOrcObjectLayerRef ObjLinkingLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit);
326   LLVMMemoryBufferRef ObjBuffer = createTestObject(SumExample, "sum.ll");
327 
328   if (LLVMErrorRef E = LLVMOrcObjectLayerAddObjectFile(ObjLinkingLayer,
329                                                        MainDylib, ObjBuffer))
330     FAIL() << "Failed to add object file to ObjLinkingLayer (triple = "
331            << TargetTriple << "): " << toString(E);
332 
333   LLVMOrcJITTargetAddress SumAddr;
334   if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &SumAddr, "sum"))
335     FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple
336            << "): " << toString(E);
337   ASSERT_TRUE(!!SumAddr);
338 }
339 
340 TEST_F(OrcCAPITestBase, ExecutionTest) {
341   using SumFunctionType = int32_t (*)(int32_t, int32_t);
342 
343   // This test performs OrcJIT compilation of a simple sum module
344   LLVMInitializeNativeAsmPrinter();
345   LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");
346   if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModule(Jit, MainDylib, TSM))
347     FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple
348            << ")" << toString(E);
349   LLVMOrcJITTargetAddress TestFnAddr;
350   if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum"))
351     FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple
352            << "): " << toString(E);
353   auto *SumFn = (SumFunctionType)(TestFnAddr);
354   int32_t Result = SumFn(1, 1);
355   ASSERT_EQ(2, Result);
356 }
357 
358 void Destroy(void *Ctx) {}
359 
360 void TargetFn() {}
361 
362 void Materialize(void *Ctx, LLVMOrcMaterializationResponsibilityRef MR) {
363   LLVMOrcJITDylibRef JD =
364       LLVMOrcMaterializationResponsibilityGetTargetDylib(MR);
365   ASSERT_TRUE(!!JD);
366 
367   LLVMOrcExecutionSessionRef ES =
368       LLVMOrcMaterializationResponsibilityGetExecutionSession(MR);
369   ASSERT_TRUE(!!ES);
370 
371   LLVMOrcSymbolStringPoolEntryRef InitSym =
372       LLVMOrcMaterializationResponsibilityGetInitializerSymbol(MR);
373   ASSERT_TRUE(!InitSym);
374 
375   size_t NumSymbols;
376   LLVMOrcCSymbolFlagsMapPairs Symbols =
377       LLVMOrcMaterializationResponsibilityGetSymbols(MR, &NumSymbols);
378 
379   ASSERT_TRUE(!!Symbols);
380   ASSERT_EQ(NumSymbols, (size_t)1);
381 
382   LLVMOrcSymbolStringPoolEntryRef *RequestedSymbols =
383       LLVMOrcMaterializationResponsibilityGetRequestedSymbols(MR, &NumSymbols);
384 
385   ASSERT_TRUE(!!RequestedSymbols);
386   ASSERT_EQ(NumSymbols, (size_t)1);
387 
388   LLVMOrcCSymbolFlagsMapPair TargetSym = Symbols[0];
389 
390   ASSERT_EQ(RequestedSymbols[0], TargetSym.Name);
391   LLVMOrcRetainSymbolStringPoolEntry(TargetSym.Name);
392 
393   LLVMOrcDisposeCSymbolFlagsMap(Symbols);
394   LLVMOrcDisposeSymbols(RequestedSymbols);
395 
396   LLVMOrcJITTargetAddress Addr = (LLVMOrcJITTargetAddress)(&TargetFn);
397 
398   LLVMJITSymbolFlags Flags = {
399       LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};
400   ASSERT_EQ(TargetSym.Flags.GenericFlags, Flags.GenericFlags);
401   ASSERT_EQ(TargetSym.Flags.TargetFlags, Flags.TargetFlags);
402 
403   LLVMJITEvaluatedSymbol Sym = {Addr, Flags};
404 
405   LLVMOrcLLJITRef J = (LLVMOrcLLJITRef)Ctx;
406 
407   LLVMOrcSymbolStringPoolEntryRef OtherSymbol =
408       LLVMOrcLLJITMangleAndIntern(J, "other");
409   LLVMOrcSymbolStringPoolEntryRef DependencySymbol =
410       LLVMOrcLLJITMangleAndIntern(J, "dependency");
411 
412   LLVMOrcRetainSymbolStringPoolEntry(OtherSymbol);
413   LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol);
414   LLVMOrcCSymbolFlagsMapPair NewSymbols[] = {
415       {OtherSymbol, Flags},
416       {DependencySymbol, Flags},
417   };
418   LLVMOrcMaterializationResponsibilityDefineMaterializing(MR, NewSymbols, 2);
419 
420   LLVMOrcRetainSymbolStringPoolEntry(OtherSymbol);
421   LLVMOrcMaterializationResponsibilityRef OtherMR = NULL;
422   {
423     LLVMErrorRef Err = LLVMOrcMaterializationResponsibilityDelegate(
424         MR, &OtherSymbol, 1, &OtherMR);
425     if (Err) {
426       char *ErrMsg = LLVMGetErrorMessage(Err);
427       fprintf(stderr, "Error: %s\n", ErrMsg);
428       LLVMDisposeErrorMessage(ErrMsg);
429       LLVMOrcMaterializationResponsibilityFailMaterialization(MR);
430       LLVMOrcDisposeMaterializationResponsibility(MR);
431       return;
432     }
433   }
434   assert(OtherMR);
435 
436   LLVMJITCSymbolMapPair OtherPair = {OtherSymbol, Sym};
437   LLVMOrcMaterializationUnitRef OtherMU = LLVMOrcAbsoluteSymbols(&OtherPair, 1);
438   // OtherSymbol is no longer owned by us
439   {
440     LLVMErrorRef Err =
441         LLVMOrcMaterializationResponsibilityReplace(OtherMR, OtherMU);
442     if (Err) {
443       char *ErrMsg = LLVMGetErrorMessage(Err);
444       fprintf(stderr, "Error: %s\n", ErrMsg);
445       LLVMDisposeErrorMessage(ErrMsg);
446 
447       LLVMOrcMaterializationResponsibilityFailMaterialization(OtherMR);
448       LLVMOrcMaterializationResponsibilityFailMaterialization(MR);
449 
450       LLVMOrcDisposeMaterializationResponsibility(OtherMR);
451       LLVMOrcDisposeMaterializationResponsibility(MR);
452       LLVMOrcDisposeMaterializationUnit(OtherMU);
453       return;
454     }
455   }
456   LLVMOrcDisposeMaterializationResponsibility(OtherMR);
457 
458   // FIXME: Implement async lookup
459   // A real test of the dependence tracking in the success case would require
460   // async lookups. You could:
461   // 1. Materialize foo, making foo depend on other.
462   // 2. In the caller, verify that the lookup callback for foo has not run (due
463   // to the dependence)
464   // 3. Materialize other by looking it up.
465   // 4. In the caller, verify that the lookup callback for foo has now run.
466 
467   LLVMOrcRetainSymbolStringPoolEntry(TargetSym.Name);
468   LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol);
469   LLVMOrcCDependenceMapPair Dependency = {JD, {&DependencySymbol, 1}};
470   LLVMOrcMaterializationResponsibilityAddDependencies(MR, TargetSym.Name,
471                                                       &Dependency, 1);
472 
473   LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol);
474   LLVMOrcMaterializationResponsibilityAddDependenciesForAll(MR, &Dependency, 1);
475 
476   // See FIXME above
477   LLVMJITCSymbolMapPair Pair = {DependencySymbol, Sym};
478   LLVMOrcMaterializationResponsibilityNotifyResolved(MR, &Pair, 1);
479   // DependencySymbol no longer owned by us
480 
481   Pair = {TargetSym.Name, Sym};
482   LLVMOrcMaterializationResponsibilityNotifyResolved(MR, &Pair, 1);
483 
484   LLVMOrcMaterializationResponsibilityNotifyEmitted(MR);
485   LLVMOrcDisposeMaterializationResponsibility(MR);
486   return;
487 }
488 
489 TEST_F(OrcCAPITestBase, MaterializationResponsibility) {
490   LLVMJITSymbolFlags Flags = {
491       LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};
492   LLVMOrcCSymbolFlagsMapPair Sym = {LLVMOrcLLJITMangleAndIntern(Jit, "foo"),
493                                     Flags};
494 
495   LLVMOrcMaterializationUnitRef MU = LLVMOrcCreateCustomMaterializationUnit(
496       "MU", (void *)Jit, &Sym, 1, NULL, &Materialize, NULL, &Destroy);
497   LLVMOrcJITDylibRef JD = LLVMOrcLLJITGetMainJITDylib(Jit);
498   LLVMOrcJITDylibDefine(JD, MU);
499 
500   LLVMOrcJITTargetAddress Addr;
501   if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "foo")) {
502     FAIL() << "foo was not materialized " << toString(Err);
503   }
504   ASSERT_TRUE(!!Addr);
505   ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn);
506 
507   if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "other")) {
508     FAIL() << "other was not materialized " << toString(Err);
509   }
510   ASSERT_TRUE(!!Addr);
511   ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn);
512 
513   if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "dependency")) {
514     FAIL() << "dependency was not materialized " << toString(Err);
515   }
516   ASSERT_TRUE(!!Addr);
517   ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn);
518 }
519