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

source code of llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp