Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / unittests / ExecutionEngine / Orc / OrcCAPITest.cpp
blobcbdd4af47e1d47da5d4d53147676111c3b98efe2
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 //===----------------------------------------------------------------------===//
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"
15 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
16 #include "llvm/IR/LLVMContext.h"
17 #include "llvm/IR/Module.h"
18 #include "llvm/IRReader/IRReader.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/FormatVariadic.h"
21 #include "llvm/Support/SourceMgr.h"
22 #include "llvm/TargetParser/Triple.h"
23 #include "llvm/Testing/Support/Error.h"
24 #include <string>
26 using namespace llvm;
27 using namespace llvm::orc;
29 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
31 // OrcCAPITestBase contains several helper methods and pointers for unit tests
32 // written for the LLVM-C API. It provides the following helpers:
34 // 1. Jit: an LLVMOrcLLJIT instance which is freed upon test exit
35 // 2. ExecutionSession: the LLVMOrcExecutionSession for the JIT
36 // 3. MainDylib: the main JITDylib for the LLJIT instance
37 // 4. materializationUnitFn: function pointer to an empty function, used for
38 // materialization unit testing
39 // 5. definitionGeneratorFn: function pointer for a basic
40 // LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction
41 // 6. createTestModule: helper method for creating a basic thread-safe-module
42 class OrcCAPITestBase : public testing::Test {
43 protected:
44 LLVMOrcLLJITRef Jit = nullptr;
45 LLVMOrcExecutionSessionRef ExecutionSession = nullptr;
46 LLVMOrcJITDylibRef MainDylib = nullptr;
48 public:
49 static void SetUpTestCase() {
50 LLVMInitializeNativeTarget();
51 LLVMInitializeNativeAsmParser();
52 LLVMInitializeNativeAsmPrinter();
54 // Attempt to set up a JIT instance once to verify that we can.
55 LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr;
56 if (LLVMErrorRef E = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB)) {
57 // If setup fails then disable these tests.
58 LLVMConsumeError(E);
59 TargetSupported = false;
60 return;
63 // Capture the target triple. We'll use it for both verification that
64 // this target is *supposed* to be supported, and error messages in
65 // the case that it fails anyway.
66 char *TT = LLVMOrcJITTargetMachineBuilderGetTargetTriple(JTMB);
67 TargetTriple = TT;
68 LLVMDisposeMessage(TT);
70 if (!isSupported(TargetTriple)) {
71 // If this triple isn't supported then bail out.
72 TargetSupported = false;
73 LLVMOrcDisposeJITTargetMachineBuilder(JTMB);
74 return;
77 LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder();
78 LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB);
79 LLVMOrcLLJITRef J;
80 if (LLVMErrorRef E = LLVMOrcCreateLLJIT(&J, Builder)) {
81 // If setup fails then disable these tests.
82 TargetSupported = false;
83 LLVMConsumeError(E);
84 return;
87 LLVMOrcDisposeLLJIT(J);
88 TargetSupported = true;
91 void SetUp() override {
92 if (!TargetSupported)
93 GTEST_SKIP();
95 LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr;
96 LLVMErrorRef E1 = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB);
97 assert(E1 == LLVMErrorSuccess && "Expected call to detect host to succeed");
98 (void)E1;
100 LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder();
101 LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB);
102 LLVMErrorRef E2 = LLVMOrcCreateLLJIT(&Jit, Builder);
103 assert(E2 == LLVMErrorSuccess &&
104 "Expected call to create LLJIT to succeed");
105 (void)E2;
106 ExecutionSession = LLVMOrcLLJITGetExecutionSession(Jit);
107 MainDylib = LLVMOrcLLJITGetMainJITDylib(Jit);
109 void TearDown() override {
110 // Check whether Jit has already been torn down -- we allow clients to do
111 // this manually to check teardown behavior.
112 if (Jit) {
113 LLVMOrcDisposeLLJIT(Jit);
114 Jit = nullptr;
118 protected:
119 static bool isSupported(StringRef Triple) {
120 // TODO: Print error messages in failure logs, use them to audit this list.
121 // Some architectures may be unsupportable or missing key components, but
122 // some may just be failing due to bugs in this testcase.
123 if (Triple.startswith("armv7") || Triple.startswith("armv8l"))
124 return false;
125 return true;
128 static void materializationUnitFn() {}
130 // Stub definition generator, where all Names are materialized from the
131 // materializationUnitFn() test function and defined into the JIT Dylib
132 static LLVMErrorRef
133 definitionGeneratorFn(LLVMOrcDefinitionGeneratorRef G, void *Ctx,
134 LLVMOrcLookupStateRef *LS, LLVMOrcLookupKind K,
135 LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags F,
136 LLVMOrcCLookupSet Names, size_t NamesCount) {
137 for (size_t I = 0; I < NamesCount; I++) {
138 LLVMOrcCLookupSetElement Element = Names[I];
139 LLVMOrcJITTargetAddress Addr =
140 (LLVMOrcJITTargetAddress)(&materializationUnitFn);
141 LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0};
142 LLVMJITEvaluatedSymbol Sym = {Addr, Flags};
143 LLVMOrcRetainSymbolStringPoolEntry(Element.Name);
144 LLVMOrcCSymbolMapPair Pair = {Element.Name, Sym};
145 LLVMOrcCSymbolMapPair Pairs[] = {Pair};
146 LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1);
147 LLVMErrorRef Err = LLVMOrcJITDylibDefine(JD, MU);
148 if (Err)
149 return Err;
151 return LLVMErrorSuccess;
154 static Error createSMDiagnosticError(llvm::SMDiagnostic &Diag) {
155 std::string Msg;
157 raw_string_ostream OS(Msg);
158 Diag.print("", OS);
160 return make_error<StringError>(std::move(Msg), inconvertibleErrorCode());
163 // Create an LLVM IR module from the given StringRef.
164 static Expected<std::unique_ptr<Module>>
165 parseTestModule(LLVMContext &Ctx, StringRef Source, StringRef Name) {
166 assert(TargetSupported &&
167 "Attempted to create module for unsupported target");
168 SMDiagnostic Err;
169 if (auto M = parseIR(MemoryBufferRef(Source, Name), Err, Ctx))
170 return std::move(M);
171 return createSMDiagnosticError(Err);
174 // returns the sum of its two parameters
175 static LLVMOrcThreadSafeModuleRef createTestModule(StringRef Source,
176 StringRef Name) {
177 auto Ctx = std::make_unique<LLVMContext>();
178 auto M = cantFail(parseTestModule(*Ctx, Source, Name));
179 return wrap(new ThreadSafeModule(std::move(M), std::move(Ctx)));
182 static LLVMMemoryBufferRef createTestObject(StringRef Source,
183 StringRef Name) {
184 auto Ctx = std::make_unique<LLVMContext>();
185 auto M = cantFail(parseTestModule(*Ctx, Source, Name));
187 auto JTMB = cantFail(JITTargetMachineBuilder::detectHost());
188 M->setDataLayout(cantFail(JTMB.getDefaultDataLayoutForTarget()));
189 auto TM = cantFail(JTMB.createTargetMachine());
191 SimpleCompiler SC(*TM);
192 auto ObjBuffer = cantFail(SC(*M));
193 return wrap(ObjBuffer.release());
196 static std::string TargetTriple;
197 static bool TargetSupported;
200 std::string OrcCAPITestBase::TargetTriple;
201 bool OrcCAPITestBase::TargetSupported = false;
203 namespace {
205 constexpr StringRef SumExample =
207 define i32 @sum(i32 %x, i32 %y) {
208 entry:
209 %r = add nsw i32 %x, %y
210 ret i32 %r
214 } // end anonymous namespace.
216 // Consumes the given error ref and returns the string error message.
217 static std::string toString(LLVMErrorRef E) {
218 char *ErrMsg = LLVMGetErrorMessage(E);
219 std::string Result(ErrMsg);
220 LLVMDisposeErrorMessage(ErrMsg);
221 return Result;
224 TEST_F(OrcCAPITestBase, SymbolStringPoolUniquing) {
225 LLVMOrcSymbolStringPoolEntryRef E1 =
226 LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa");
227 LLVMOrcSymbolStringPoolEntryRef E2 =
228 LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa");
229 LLVMOrcSymbolStringPoolEntryRef E3 =
230 LLVMOrcExecutionSessionIntern(ExecutionSession, "bbb");
231 const char *SymbolName = LLVMOrcSymbolStringPoolEntryStr(E1);
232 ASSERT_EQ(E1, E2) << "String pool entries are not unique";
233 ASSERT_NE(E1, E3) << "Unique symbol pool entries are equal";
234 ASSERT_STREQ("aaa", SymbolName) << "String value of symbol is not equal";
235 LLVMOrcReleaseSymbolStringPoolEntry(E1);
236 LLVMOrcReleaseSymbolStringPoolEntry(E2);
237 LLVMOrcReleaseSymbolStringPoolEntry(E3);
240 TEST_F(OrcCAPITestBase, JITDylibLookup) {
241 LLVMOrcJITDylibRef DoesNotExist =
242 LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test");
243 ASSERT_FALSE(!!DoesNotExist);
244 LLVMOrcJITDylibRef L1 =
245 LLVMOrcExecutionSessionCreateBareJITDylib(ExecutionSession, "test");
246 LLVMOrcJITDylibRef L2 =
247 LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test");
248 ASSERT_EQ(L1, L2) << "Located JIT Dylib is not equal to original";
251 TEST_F(OrcCAPITestBase, MaterializationUnitCreation) {
252 LLVMOrcSymbolStringPoolEntryRef Name =
253 LLVMOrcLLJITMangleAndIntern(Jit, "test");
254 LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0};
255 LLVMOrcJITTargetAddress Addr =
256 (LLVMOrcJITTargetAddress)(&materializationUnitFn);
257 LLVMJITEvaluatedSymbol Sym = {Addr, Flags};
258 LLVMOrcCSymbolMapPair Pair = {Name, Sym};
259 LLVMOrcCSymbolMapPair Pairs[] = {Pair};
260 LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1);
261 if (LLVMErrorRef E = LLVMOrcJITDylibDefine(MainDylib, MU))
262 FAIL() << "Unexpected error while adding \"test\" symbol (triple = "
263 << TargetTriple << "): " << toString(E);
264 LLVMOrcJITTargetAddress OutAddr;
265 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &OutAddr, "test"))
266 FAIL() << "Failed to look up \"test\" symbol (triple = " << TargetTriple
267 << "): " << toString(E);
268 ASSERT_EQ(Addr, OutAddr);
271 struct ExecutionSessionLookupHelper {
272 bool ExpectSuccess = true;
273 bool CallbackReceived = false;
274 size_t NumExpectedPairs;
275 LLVMOrcCSymbolMapPair *ExpectedMapping;
278 static void executionSessionLookupHandlerCallback(LLVMErrorRef Err,
279 LLVMOrcCSymbolMapPairs Result,
280 size_t NumPairs,
281 void *RawCtx) {
282 auto *Ctx = static_cast<ExecutionSessionLookupHelper *>(RawCtx);
283 Ctx->CallbackReceived = true;
284 if (Ctx->ExpectSuccess) {
285 EXPECT_THAT_ERROR(unwrap(Err), Succeeded());
286 EXPECT_EQ(NumPairs, Ctx->NumExpectedPairs)
287 << "Expected " << Ctx->NumExpectedPairs << " entries in result, got "
288 << NumPairs;
289 auto ExpectedMappingEnd = Ctx->ExpectedMapping + Ctx->NumExpectedPairs;
290 for (unsigned I = 0; I != NumPairs; ++I) {
291 auto J =
292 std::find_if(Ctx->ExpectedMapping, ExpectedMappingEnd,
293 [N = Result[I].Name](const LLVMOrcCSymbolMapPair &Val) {
294 return Val.Name == N;
296 EXPECT_NE(J, ExpectedMappingEnd)
297 << "Missing symbol \""
298 << LLVMOrcSymbolStringPoolEntryStr(Result[I].Name) << "\"";
299 if (J != ExpectedMappingEnd) {
300 EXPECT_EQ(Result[I].Sym.Address, J->Sym.Address)
301 << "Result map for \"" << Result[I].Name
302 << "\" differs from expected value: "
303 << formatv("{0:x} vs {1:x}", Result[I].Sym.Address, J->Sym.Address);
306 } else
307 EXPECT_THAT_ERROR(unwrap(Err), Failed());
310 TEST_F(OrcCAPITestBase, ExecutionSessionLookup_Success) {
311 // Test a successful generic lookup. We will look up three symbols over two
312 // JITDylibs: { "Foo" (Required), "Bar" (Weakly-ref), "Baz" (Required) } over
313 // { MainJITDylib (Exported-only), ExtraJD (All symbols) }.
315 // Foo will be defined as exported in MainJD.
316 // Bar will be defined as non-exported in MainJD.
317 // Baz will be defined as non-exported in ExtraJD.
319 // This will require (1) that we find the regular exported symbol Foo in
320 // MainJD, (2) that we *don't* find the non-exported symbol Bar in MainJD
321 // but also don't error (since it's weakly referenced), and (3) that we
322 // find the non-exported symbol Baz in ExtraJD (since we're searching all
323 // symbols in ExtraJD).
325 ExecutionSessionLookupHelper H;
326 LLVMOrcSymbolStringPoolEntryRef Foo = LLVMOrcLLJITMangleAndIntern(Jit, "Foo");
327 LLVMOrcSymbolStringPoolEntryRef Bar = LLVMOrcLLJITMangleAndIntern(Jit, "Bar");
328 LLVMOrcSymbolStringPoolEntryRef Baz = LLVMOrcLLJITMangleAndIntern(Jit, "Baz");
330 // Create ExtraJD.
331 LLVMOrcJITDylibRef ExtraJD = nullptr;
332 if (auto E = LLVMOrcExecutionSessionCreateJITDylib(ExecutionSession, &ExtraJD,
333 "ExtraJD")) {
334 FAIL() << "Unexpected error while creating JITDylib \"ExtraJD\" (triple = "
335 << TargetTriple << "): " << toString(E);
336 return;
339 // Add exported symbols "Foo" and "Bar" to Main JITDylib.
340 LLVMOrcRetainSymbolStringPoolEntry(Foo);
341 LLVMOrcRetainSymbolStringPoolEntry(Bar);
342 LLVMOrcCSymbolMapPair MainJDPairs[] = {
343 {Foo, {0x1, {LLVMJITSymbolGenericFlagsExported, 0}}},
344 {Bar, {0x2, {LLVMJITSymbolGenericFlagsNone, 0}}}};
345 LLVMOrcMaterializationUnitRef MainJDMU =
346 LLVMOrcAbsoluteSymbols(MainJDPairs, 2);
347 if (LLVMErrorRef E = LLVMOrcJITDylibDefine(MainDylib, MainJDMU))
348 FAIL() << "Unexpected error while adding MainDylib symbols (triple = "
349 << TargetTriple << "): " << toString(E);
351 // Add non-exported symbol "Baz" to ExtraJD.
352 LLVMOrcRetainSymbolStringPoolEntry(Baz);
353 LLVMOrcCSymbolMapPair ExtraJDPairs[] = {
354 {Baz, {0x3, {LLVMJITSymbolGenericFlagsNone, 0}}}};
355 LLVMOrcMaterializationUnitRef ExtraJDMU =
356 LLVMOrcAbsoluteSymbols(ExtraJDPairs, 1);
357 if (LLVMErrorRef E = LLVMOrcJITDylibDefine(ExtraJD, ExtraJDMU))
358 FAIL() << "Unexpected error while adding ExtraJD symbols (triple = "
359 << TargetTriple << "): " << toString(E);
361 // Create expected mapping for result:
362 LLVMOrcCSymbolMapPair ExpectedMapping[] = {
363 {Foo, {0x1, {LLVMJITSymbolGenericFlagsExported, 0}}},
364 {Baz, {0x3, {LLVMJITSymbolGenericFlagsNone, 0}}}};
365 H.ExpectedMapping = ExpectedMapping;
366 H.NumExpectedPairs = 2;
368 // Issue the lookup. We're using the default same-thread dispatch, so the
369 // handler should have run by the time we return from this call.
370 LLVMOrcCJITDylibSearchOrderElement SO[] = {
371 {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly},
372 {ExtraJD, LLVMOrcJITDylibLookupFlagsMatchAllSymbols}};
374 LLVMOrcRetainSymbolStringPoolEntry(Foo);
375 LLVMOrcRetainSymbolStringPoolEntry(Bar);
376 LLVMOrcRetainSymbolStringPoolEntry(Baz);
377 LLVMOrcCLookupSetElement LS[] = {
378 {Foo, LLVMOrcSymbolLookupFlagsRequiredSymbol},
379 {Bar, LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol},
380 {Baz, LLVMOrcSymbolLookupFlagsRequiredSymbol}};
381 LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO,
382 2, LS, 3, executionSessionLookupHandlerCallback,
383 &H);
385 EXPECT_TRUE(H.CallbackReceived) << "Lookup callback never received";
387 // Release our local string ptrs.
388 LLVMOrcReleaseSymbolStringPoolEntry(Baz);
389 LLVMOrcReleaseSymbolStringPoolEntry(Bar);
390 LLVMOrcReleaseSymbolStringPoolEntry(Foo);
393 TEST_F(OrcCAPITestBase, ExecutionSessionLookup_Failure) {
394 // Test generic lookup failure case. We will look up a symbol in MainDylib
395 // without defining it. We expect this to result in a symbol-not-found error.
397 ExecutionSessionLookupHelper H;
398 H.ExpectSuccess = false;
400 LLVMOrcCJITDylibSearchOrderElement SO[] = {
401 {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly}};
402 LLVMOrcCLookupSetElement LS[] = {{LLVMOrcLLJITMangleAndIntern(Jit, "Foo"),
403 LLVMOrcSymbolLookupFlagsRequiredSymbol}};
404 LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO,
405 1, LS, 1, executionSessionLookupHandlerCallback,
406 &H);
408 EXPECT_TRUE(H.CallbackReceived) << "Lookup callback never received";
411 TEST_F(OrcCAPITestBase, DefinitionGenerators) {
412 LLVMOrcDefinitionGeneratorRef Gen =
413 LLVMOrcCreateCustomCAPIDefinitionGenerator(&definitionGeneratorFn,
414 nullptr, nullptr);
415 LLVMOrcJITDylibAddGenerator(MainDylib, Gen);
416 LLVMOrcJITTargetAddress OutAddr;
417 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &OutAddr, "test"))
418 FAIL() << "The DefinitionGenerator did not create symbol \"test\" "
419 << "(triple = " << TargetTriple << "): " << toString(E);
420 LLVMOrcJITTargetAddress ExpectedAddr =
421 (LLVMOrcJITTargetAddress)(&materializationUnitFn);
422 ASSERT_EQ(ExpectedAddr, OutAddr);
425 #if defined(_AIX)
426 TEST_F(OrcCAPITestBase, DISABLED_ResourceTrackerDefinitionLifetime) {
427 #else
428 TEST_F(OrcCAPITestBase, ResourceTrackerDefinitionLifetime) {
429 #endif
430 // This test case ensures that all symbols loaded into a JITDylib with a
431 // ResourceTracker attached are cleared from the JITDylib once the RT is
432 // removed.
433 LLVMOrcResourceTrackerRef RT =
434 LLVMOrcJITDylibCreateResourceTracker(MainDylib);
435 LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");
436 if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, RT, TSM))
437 FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple
438 << "): " << toString(E);
439 LLVMOrcJITTargetAddress TestFnAddr;
440 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum"))
441 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple
442 << "): " << toString(E);
443 ASSERT_TRUE(!!TestFnAddr);
444 LLVMOrcResourceTrackerRemove(RT);
445 LLVMOrcJITTargetAddress OutAddr;
446 LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &OutAddr, "sum");
447 ASSERT_TRUE(Err);
448 LLVMConsumeError(Err);
450 ASSERT_FALSE(OutAddr);
451 LLVMOrcReleaseResourceTracker(RT);
454 #if defined(_AIX)
455 TEST_F(OrcCAPITestBase, DISABLED_ResourceTrackerTransfer) {
456 #else
457 TEST_F(OrcCAPITestBase, ResourceTrackerTransfer) {
458 #endif
459 LLVMOrcResourceTrackerRef DefaultRT =
460 LLVMOrcJITDylibGetDefaultResourceTracker(MainDylib);
461 LLVMOrcResourceTrackerRef RT2 =
462 LLVMOrcJITDylibCreateResourceTracker(MainDylib);
463 LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");
464 if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, DefaultRT, TSM))
465 FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple
466 << "): " << toString(E);
467 LLVMOrcJITTargetAddress Addr;
468 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &Addr, "sum"))
469 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple
470 << "): " << toString(E);
471 LLVMOrcResourceTrackerTransferTo(DefaultRT, RT2);
472 LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "sum");
473 ASSERT_FALSE(Err);
474 LLVMOrcReleaseResourceTracker(RT2);
477 #if defined(_AIX)
478 TEST_F(OrcCAPITestBase, DISABLED_AddObjectBuffer) {
479 #else
480 TEST_F(OrcCAPITestBase, AddObjectBuffer) {
481 #endif
482 LLVMOrcObjectLayerRef ObjLinkingLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit);
483 LLVMMemoryBufferRef ObjBuffer = createTestObject(SumExample, "sum.ll");
485 if (LLVMErrorRef E = LLVMOrcObjectLayerAddObjectFile(ObjLinkingLayer,
486 MainDylib, ObjBuffer))
487 FAIL() << "Failed to add object file to ObjLinkingLayer (triple = "
488 << TargetTriple << "): " << toString(E);
490 LLVMOrcJITTargetAddress SumAddr;
491 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &SumAddr, "sum"))
492 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple
493 << "): " << toString(E);
494 ASSERT_TRUE(!!SumAddr);
497 #if defined(_AIX)
498 TEST_F(OrcCAPITestBase, DISABLED_ExecutionTest) {
499 #else
500 TEST_F(OrcCAPITestBase, ExecutionTest) {
501 #endif
502 using SumFunctionType = int32_t (*)(int32_t, int32_t);
504 // This test performs OrcJIT compilation of a simple sum module
505 LLVMInitializeNativeAsmPrinter();
506 LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");
507 if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModule(Jit, MainDylib, TSM))
508 FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple
509 << ")" << toString(E);
510 LLVMOrcJITTargetAddress TestFnAddr;
511 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum"))
512 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple
513 << "): " << toString(E);
514 auto *SumFn = (SumFunctionType)(TestFnAddr);
515 int32_t Result = SumFn(1, 1);
516 ASSERT_EQ(2, Result);
519 void Destroy(void *Ctx) {}
521 void TargetFn() {}
523 void Materialize(void *Ctx, LLVMOrcMaterializationResponsibilityRef MR) {
524 LLVMOrcJITDylibRef JD =
525 LLVMOrcMaterializationResponsibilityGetTargetDylib(MR);
526 ASSERT_TRUE(!!JD);
528 LLVMOrcExecutionSessionRef ES =
529 LLVMOrcMaterializationResponsibilityGetExecutionSession(MR);
530 ASSERT_TRUE(!!ES);
532 LLVMOrcSymbolStringPoolEntryRef InitSym =
533 LLVMOrcMaterializationResponsibilityGetInitializerSymbol(MR);
534 ASSERT_TRUE(!InitSym);
536 size_t NumSymbols;
537 LLVMOrcCSymbolFlagsMapPairs Symbols =
538 LLVMOrcMaterializationResponsibilityGetSymbols(MR, &NumSymbols);
540 ASSERT_TRUE(!!Symbols);
541 ASSERT_EQ(NumSymbols, (size_t)1);
543 LLVMOrcSymbolStringPoolEntryRef *RequestedSymbols =
544 LLVMOrcMaterializationResponsibilityGetRequestedSymbols(MR, &NumSymbols);
546 ASSERT_TRUE(!!RequestedSymbols);
547 ASSERT_EQ(NumSymbols, (size_t)1);
549 LLVMOrcCSymbolFlagsMapPair TargetSym = Symbols[0];
551 ASSERT_EQ(RequestedSymbols[0], TargetSym.Name);
552 LLVMOrcRetainSymbolStringPoolEntry(TargetSym.Name);
554 LLVMOrcDisposeCSymbolFlagsMap(Symbols);
555 LLVMOrcDisposeSymbols(RequestedSymbols);
557 LLVMOrcJITTargetAddress Addr = (LLVMOrcJITTargetAddress)(&TargetFn);
559 LLVMJITSymbolFlags Flags = {
560 LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};
561 ASSERT_EQ(TargetSym.Flags.GenericFlags, Flags.GenericFlags);
562 ASSERT_EQ(TargetSym.Flags.TargetFlags, Flags.TargetFlags);
564 LLVMJITEvaluatedSymbol Sym = {Addr, Flags};
566 LLVMOrcLLJITRef J = (LLVMOrcLLJITRef)Ctx;
568 LLVMOrcSymbolStringPoolEntryRef OtherSymbol =
569 LLVMOrcLLJITMangleAndIntern(J, "other");
570 LLVMOrcSymbolStringPoolEntryRef DependencySymbol =
571 LLVMOrcLLJITMangleAndIntern(J, "dependency");
573 LLVMOrcRetainSymbolStringPoolEntry(OtherSymbol);
574 LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol);
575 LLVMOrcCSymbolFlagsMapPair NewSymbols[] = {
576 {OtherSymbol, Flags},
577 {DependencySymbol, Flags},
579 LLVMOrcMaterializationResponsibilityDefineMaterializing(MR, NewSymbols, 2);
581 LLVMOrcRetainSymbolStringPoolEntry(OtherSymbol);
582 LLVMOrcMaterializationResponsibilityRef OtherMR = NULL;
584 LLVMErrorRef Err = LLVMOrcMaterializationResponsibilityDelegate(
585 MR, &OtherSymbol, 1, &OtherMR);
586 if (Err) {
587 char *ErrMsg = LLVMGetErrorMessage(Err);
588 fprintf(stderr, "Error: %s\n", ErrMsg);
589 LLVMDisposeErrorMessage(ErrMsg);
590 LLVMOrcMaterializationResponsibilityFailMaterialization(MR);
591 LLVMOrcDisposeMaterializationResponsibility(MR);
592 return;
595 assert(OtherMR);
597 LLVMOrcCSymbolMapPair OtherPair = {OtherSymbol, Sym};
598 LLVMOrcMaterializationUnitRef OtherMU = LLVMOrcAbsoluteSymbols(&OtherPair, 1);
599 // OtherSymbol is no longer owned by us
601 LLVMErrorRef Err =
602 LLVMOrcMaterializationResponsibilityReplace(OtherMR, OtherMU);
603 if (Err) {
604 char *ErrMsg = LLVMGetErrorMessage(Err);
605 fprintf(stderr, "Error: %s\n", ErrMsg);
606 LLVMDisposeErrorMessage(ErrMsg);
608 LLVMOrcMaterializationResponsibilityFailMaterialization(OtherMR);
609 LLVMOrcMaterializationResponsibilityFailMaterialization(MR);
611 LLVMOrcDisposeMaterializationResponsibility(OtherMR);
612 LLVMOrcDisposeMaterializationResponsibility(MR);
613 LLVMOrcDisposeMaterializationUnit(OtherMU);
614 return;
617 LLVMOrcDisposeMaterializationResponsibility(OtherMR);
619 // FIXME: Implement async lookup
620 // A real test of the dependence tracking in the success case would require
621 // async lookups. You could:
622 // 1. Materialize foo, making foo depend on other.
623 // 2. In the caller, verify that the lookup callback for foo has not run (due
624 // to the dependence)
625 // 3. Materialize other by looking it up.
626 // 4. In the caller, verify that the lookup callback for foo has now run.
628 LLVMOrcRetainSymbolStringPoolEntry(TargetSym.Name);
629 LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol);
630 LLVMOrcCDependenceMapPair Dependency = {JD, {&DependencySymbol, 1}};
631 LLVMOrcMaterializationResponsibilityAddDependencies(MR, TargetSym.Name,
632 &Dependency, 1);
634 LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol);
635 LLVMOrcMaterializationResponsibilityAddDependenciesForAll(MR, &Dependency, 1);
637 // See FIXME above
638 LLVMOrcCSymbolMapPair Pair = {DependencySymbol, Sym};
639 LLVMOrcMaterializationResponsibilityNotifyResolved(MR, &Pair, 1);
640 // DependencySymbol no longer owned by us
642 Pair = {TargetSym.Name, Sym};
643 LLVMOrcMaterializationResponsibilityNotifyResolved(MR, &Pair, 1);
645 LLVMOrcMaterializationResponsibilityNotifyEmitted(MR);
646 LLVMOrcDisposeMaterializationResponsibility(MR);
649 TEST_F(OrcCAPITestBase, MaterializationResponsibility) {
650 LLVMJITSymbolFlags Flags = {
651 LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};
652 LLVMOrcCSymbolFlagsMapPair Sym = {LLVMOrcLLJITMangleAndIntern(Jit, "foo"),
653 Flags};
655 LLVMOrcMaterializationUnitRef MU = LLVMOrcCreateCustomMaterializationUnit(
656 "MU", (void *)Jit, &Sym, 1, NULL, &Materialize, NULL, &Destroy);
657 LLVMOrcJITDylibRef JD = LLVMOrcLLJITGetMainJITDylib(Jit);
658 LLVMOrcJITDylibDefine(JD, MU);
660 LLVMOrcJITTargetAddress Addr;
661 if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "foo")) {
662 FAIL() << "foo was not materialized " << toString(Err);
664 ASSERT_TRUE(!!Addr);
665 ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn);
667 if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "other")) {
668 FAIL() << "other was not materialized " << toString(Err);
670 ASSERT_TRUE(!!Addr);
671 ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn);
673 if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "dependency")) {
674 FAIL() << "dependency was not materialized " << toString(Err);
676 ASSERT_TRUE(!!Addr);
677 ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn);
680 struct SuspendedLookupContext {
681 std::function<void()> AsyncWork;
682 LLVMOrcSymbolStringPoolEntryRef NameToGenerate;
683 JITTargetAddress AddrToGenerate;
685 bool Disposed = false;
686 bool QueryCompleted = true;
689 static LLVMErrorRef TryToGenerateWithSuspendedLookup(
690 LLVMOrcDefinitionGeneratorRef GeneratorObj, void *RawCtx,
691 LLVMOrcLookupStateRef *LookupState, LLVMOrcLookupKind Kind,
692 LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags JDLookupFlags,
693 LLVMOrcCLookupSet LookupSet, size_t LookupSetSize) {
695 auto *Ctx = static_cast<SuspendedLookupContext *>(RawCtx);
697 assert(LookupSetSize == 1);
698 assert(LookupSet[0].Name == Ctx->NameToGenerate);
700 LLVMJITEvaluatedSymbol Sym = {0x1234, {LLVMJITSymbolGenericFlagsExported, 0}};
701 LLVMOrcRetainSymbolStringPoolEntry(LookupSet[0].Name);
702 LLVMOrcCSymbolMapPair Pair = {LookupSet[0].Name, Sym};
703 LLVMOrcCSymbolMapPair Pairs[] = {Pair};
704 LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1);
706 // Capture and reset LookupState to suspend the lookup. We'll continue it in
707 // the SuspendedLookup testcase below.
708 Ctx->AsyncWork = [LS = *LookupState, JD, MU]() {
709 LLVMErrorRef Err = LLVMOrcJITDylibDefine(JD, MU);
710 LLVMOrcLookupStateContinueLookup(LS, Err);
712 *LookupState = nullptr;
713 return LLVMErrorSuccess;
716 static void DisposeSuspendedLookupContext(void *Ctx) {
717 static_cast<SuspendedLookupContext *>(Ctx)->Disposed = true;
720 static void
721 suspendLookupTestLookupHandlerCallback(LLVMErrorRef Err,
722 LLVMOrcCSymbolMapPairs Result,
723 size_t NumPairs, void *RawCtx) {
724 if (Err) {
725 FAIL() << "Suspended DefinitionGenerator did not create symbol \"foo\": "
726 << toString(Err);
727 return;
730 EXPECT_EQ(NumPairs, 1U)
731 << "Unexpected number of result entries: expected 1, got " << NumPairs;
733 auto *Ctx = static_cast<SuspendedLookupContext *>(RawCtx);
734 EXPECT_EQ(Result[0].Name, Ctx->NameToGenerate);
735 EXPECT_EQ(Result[0].Sym.Address, Ctx->AddrToGenerate);
737 Ctx->QueryCompleted = true;
740 TEST_F(OrcCAPITestBase, SuspendedLookup) {
741 // Test that we can suspend lookup in a custom generator.
742 SuspendedLookupContext Ctx;
743 Ctx.NameToGenerate = LLVMOrcLLJITMangleAndIntern(Jit, "foo");
744 Ctx.AddrToGenerate = 0x1234;
746 // Add generator.
747 LLVMOrcJITDylibAddGenerator(MainDylib,
748 LLVMOrcCreateCustomCAPIDefinitionGenerator(
749 &TryToGenerateWithSuspendedLookup, &Ctx,
750 DisposeSuspendedLookupContext));
752 // Expect no work to do before the lookup.
753 EXPECT_FALSE(Ctx.AsyncWork) << "Unexpected generator work before lookup";
755 // Issue lookup. This should trigger the generator, but generation should
756 // be suspended.
757 LLVMOrcCJITDylibSearchOrderElement SO[] = {
758 {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly}};
759 LLVMOrcRetainSymbolStringPoolEntry(Ctx.NameToGenerate);
760 LLVMOrcCLookupSetElement LS[] = {
761 {Ctx.NameToGenerate, LLVMOrcSymbolLookupFlagsRequiredSymbol}};
762 LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO,
763 1, LS, 1,
764 suspendLookupTestLookupHandlerCallback, &Ctx);
766 // Expect that we now have generator work to do.
767 EXPECT_TRUE(Ctx.AsyncWork)
768 << "Failed to generator (or failed to suspend generator)";
770 // Do the work. This should allow the query to complete.
771 Ctx.AsyncWork();
773 // Check that the query completed.
774 EXPECT_TRUE(Ctx.QueryCompleted);
776 // Release our local copy of the string.
777 LLVMOrcReleaseSymbolStringPoolEntry(Ctx.NameToGenerate);
779 // Explicitly tear down the JIT.
780 LLVMOrcDisposeLLJIT(Jit);
781 Jit = nullptr;
783 // Check that the generator context was "destroyed".
784 EXPECT_TRUE(Ctx.Disposed);