1 //===--- OrcCAPITest.cpp - Unit tests for the OrcJIT v2 C API ---*- C++ -*-===//
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
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"
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
{
44 LLVMOrcLLJITRef Jit
= nullptr;
45 LLVMOrcExecutionSessionRef ExecutionSession
= nullptr;
46 LLVMOrcJITDylibRef MainDylib
= nullptr;
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.
59 TargetSupported
= false;
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
);
68 LLVMDisposeMessage(TT
);
70 if (!isSupported(TargetTriple
)) {
71 // If this triple isn't supported then bail out.
72 TargetSupported
= false;
73 LLVMOrcDisposeJITTargetMachineBuilder(JTMB
);
77 LLVMOrcLLJITBuilderRef Builder
= LLVMOrcCreateLLJITBuilder();
78 LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder
, JTMB
);
80 if (LLVMErrorRef E
= LLVMOrcCreateLLJIT(&J
, Builder
)) {
81 // If setup fails then disable these tests.
82 TargetSupported
= false;
87 LLVMOrcDisposeLLJIT(J
);
88 TargetSupported
= true;
91 void SetUp() override
{
95 LLVMOrcJITTargetMachineBuilderRef JTMB
= nullptr;
96 LLVMErrorRef E1
= LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB
);
97 assert(E1
== LLVMErrorSuccess
&& "Expected call to detect host to succeed");
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");
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.
113 LLVMOrcDisposeLLJIT(Jit
);
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"))
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
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
);
151 return LLVMErrorSuccess
;
154 static Error
createSMDiagnosticError(llvm::SMDiagnostic
&Diag
) {
157 raw_string_ostream
OS(Msg
);
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");
169 if (auto M
= parseIR(MemoryBufferRef(Source
, Name
), Err
, Ctx
))
171 return createSMDiagnosticError(Err
);
174 // returns the sum of its two parameters
175 static LLVMOrcThreadSafeModuleRef
createTestModule(StringRef Source
,
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
,
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;
205 constexpr StringRef SumExample
=
207 define i32 @sum(i32 %x, i32 %y) {
209 %r = add nsw i32 %x, %y
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
);
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
,
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 "
289 auto ExpectedMappingEnd
= Ctx
->ExpectedMapping
+ Ctx
->NumExpectedPairs
;
290 for (unsigned I
= 0; I
!= NumPairs
; ++I
) {
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
);
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");
331 LLVMOrcJITDylibRef ExtraJD
= nullptr;
332 if (auto E
= LLVMOrcExecutionSessionCreateJITDylib(ExecutionSession
, &ExtraJD
,
334 FAIL() << "Unexpected error while creating JITDylib \"ExtraJD\" (triple = "
335 << TargetTriple
<< "): " << toString(E
);
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
,
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
,
408 EXPECT_TRUE(H
.CallbackReceived
) << "Lookup callback never received";
411 TEST_F(OrcCAPITestBase
, DefinitionGenerators
) {
412 LLVMOrcDefinitionGeneratorRef Gen
=
413 LLVMOrcCreateCustomCAPIDefinitionGenerator(&definitionGeneratorFn
,
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
);
426 TEST_F(OrcCAPITestBase
, DISABLED_ResourceTrackerDefinitionLifetime
) {
428 TEST_F(OrcCAPITestBase
, ResourceTrackerDefinitionLifetime
) {
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
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");
448 LLVMConsumeError(Err
);
450 ASSERT_FALSE(OutAddr
);
451 LLVMOrcReleaseResourceTracker(RT
);
455 TEST_F(OrcCAPITestBase
, DISABLED_ResourceTrackerTransfer
) {
457 TEST_F(OrcCAPITestBase
, ResourceTrackerTransfer
) {
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");
474 LLVMOrcReleaseResourceTracker(RT2
);
478 TEST_F(OrcCAPITestBase
, DISABLED_AddObjectBuffer
) {
480 TEST_F(OrcCAPITestBase
, AddObjectBuffer
) {
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
);
498 TEST_F(OrcCAPITestBase
, DISABLED_ExecutionTest
) {
500 TEST_F(OrcCAPITestBase
, ExecutionTest
) {
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
) {}
523 void Materialize(void *Ctx
, LLVMOrcMaterializationResponsibilityRef MR
) {
524 LLVMOrcJITDylibRef JD
=
525 LLVMOrcMaterializationResponsibilityGetTargetDylib(MR
);
528 LLVMOrcExecutionSessionRef ES
=
529 LLVMOrcMaterializationResponsibilityGetExecutionSession(MR
);
532 LLVMOrcSymbolStringPoolEntryRef InitSym
=
533 LLVMOrcMaterializationResponsibilityGetInitializerSymbol(MR
);
534 ASSERT_TRUE(!InitSym
);
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
);
587 char *ErrMsg
= LLVMGetErrorMessage(Err
);
588 fprintf(stderr
, "Error: %s\n", ErrMsg
);
589 LLVMDisposeErrorMessage(ErrMsg
);
590 LLVMOrcMaterializationResponsibilityFailMaterialization(MR
);
591 LLVMOrcDisposeMaterializationResponsibility(MR
);
597 LLVMOrcCSymbolMapPair OtherPair
= {OtherSymbol
, Sym
};
598 LLVMOrcMaterializationUnitRef OtherMU
= LLVMOrcAbsoluteSymbols(&OtherPair
, 1);
599 // OtherSymbol is no longer owned by us
602 LLVMOrcMaterializationResponsibilityReplace(OtherMR
, OtherMU
);
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
);
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
,
634 LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol
);
635 LLVMOrcMaterializationResponsibilityAddDependenciesForAll(MR
, &Dependency
, 1);
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"),
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
);
665 ASSERT_EQ(Addr
, (LLVMOrcJITTargetAddress
)&TargetFn
);
667 if (LLVMErrorRef Err
= LLVMOrcLLJITLookup(Jit
, &Addr
, "other")) {
668 FAIL() << "other was not materialized " << toString(Err
);
671 ASSERT_EQ(Addr
, (LLVMOrcJITTargetAddress
)&TargetFn
);
673 if (LLVMErrorRef Err
= LLVMOrcLLJITLookup(Jit
, &Addr
, "dependency")) {
674 FAIL() << "dependency was not materialized " << toString(Err
);
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;
721 suspendLookupTestLookupHandlerCallback(LLVMErrorRef Err
,
722 LLVMOrcCSymbolMapPairs Result
,
723 size_t NumPairs
, void *RawCtx
) {
725 FAIL() << "Suspended DefinitionGenerator did not create symbol \"foo\": "
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;
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
757 LLVMOrcCJITDylibSearchOrderElement SO
[] = {
758 {MainDylib
, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly
}};
759 LLVMOrcRetainSymbolStringPoolEntry(Ctx
.NameToGenerate
);
760 LLVMOrcCLookupSetElement LS
[] = {
761 {Ctx
.NameToGenerate
, LLVMOrcSymbolLookupFlagsRequiredSymbol
}};
762 LLVMOrcExecutionSessionLookup(ExecutionSession
, LLVMOrcLookupKindStatic
, SO
,
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.
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
);
783 // Check that the generator context was "destroyed".
784 EXPECT_TRUE(Ctx
.Disposed
);