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