Skip to content

Commit d122d80

Browse files
committed
Reapply "[ORC] Add unit tests for parts of the ..." with fixes and improvements.
This reapplies 8740360, which was reverted in bbddadd due to buildbot errors. This version checks that a JIT instance can be safely constructed, skipping tests if it can not be. To enable this it introduces new C API to retrieve and set the target triple for a JITTargetMachineBuilder.
1 parent 3c47f5f commit d122d80

File tree

5 files changed

+355
-2
lines changed

5 files changed

+355
-2
lines changed

llvm/include/llvm-c/LLJIT.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ void LLVMOrcDisposeLLJITBuilder(LLVMOrcLLJITBuilderRef Builder);
7878
* instance. Calling this function is optional: if it is not called then the
7979
* LLJITBuilder will use JITTargeTMachineBuilder::detectHost to construct a
8080
* JITTargetMachineBuilder.
81+
*
82+
* This function takes ownership of the JTMB argument: clients should not
83+
* dispose of the JITTargetMachineBuilder after calling this function.
8184
*/
8285
void LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(
8386
LLVMOrcLLJITBuilderRef Builder, LLVMOrcJITTargetMachineBuilderRef JTMB);

llvm/include/llvm-c/Orc.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -623,8 +623,9 @@ void LLVMOrcDisposeThreadSafeModule(LLVMOrcThreadSafeModuleRef TSM);
623623
* Create a JITTargetMachineBuilder by detecting the host.
624624
*
625625
* On success the client owns the resulting JITTargetMachineBuilder. It must be
626-
* passed to a consuming operation (e.g. LLVMOrcCreateLLJITBuilder) or disposed
627-
* of by calling LLVMOrcDisposeJITTargetMachineBuilder.
626+
* passed to a consuming operation (e.g.
627+
* LLVMOrcLLJITBuilderSetJITTargetMachineBuilder) or disposed of by calling
628+
* LLVMOrcDisposeJITTargetMachineBuilder.
628629
*/
629630
LLVMErrorRef LLVMOrcJITTargetMachineBuilderDetectHost(
630631
LLVMOrcJITTargetMachineBuilderRef *Result);
@@ -646,6 +647,29 @@ LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM);
646647
void LLVMOrcDisposeJITTargetMachineBuilder(
647648
LLVMOrcJITTargetMachineBuilderRef JTMB);
648649

650+
/**
651+
* Returns the target triple for the given JITTargetMachineBuilder as a string.
652+
*
653+
* The caller owns the resulting string as must dispose of it by calling
654+
* LLVMOrcJITTargetMachineBuilderDisposeTargetTriple.
655+
*/
656+
char *LLVMOrcJITTargetMachineBuilderGetTargetTriple(
657+
LLVMOrcJITTargetMachineBuilderRef JTMB);
658+
659+
/**
660+
* Sets the target triple for the given JITTargetMachineBuilder to the given
661+
* string.
662+
*/
663+
void LLVMOrcJITTargetMachineBuilderSetTargetTriple(
664+
LLVMOrcJITTargetMachineBuilderRef JTMB, const char *TargetTriple);
665+
666+
/**
667+
* Destroy a triple string returned by
668+
* LLVMOrcJITTargetMachineBuilderGetTargetTriple.
669+
*/
670+
void LLVMOrcJITTargetMachineBuilderDisposeTargetTriple(
671+
LLVMOrcJITTargetMachineBuilderRef JTMB, char *TargetTriple);
672+
649673
/**
650674
* Emit an object buffer to an ObjectLayer.
651675
*

llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,24 @@ void LLVMOrcDisposeJITTargetMachineBuilder(
473473
delete unwrap(JTMB);
474474
}
475475

476+
char *LLVMOrcJITTargetMachineBuilderGetTargetTriple(
477+
LLVMOrcJITTargetMachineBuilderRef JTMB) {
478+
auto Tmp = unwrap(JTMB)->getTargetTriple().str();
479+
char *TargetTriple = (char *)malloc(Tmp.size() + 1);
480+
strcpy(TargetTriple, Tmp.c_str());
481+
return TargetTriple;
482+
}
483+
484+
void LLVMOrcJITTargetMachineBuilderSetTargetTriple(
485+
LLVMOrcJITTargetMachineBuilderRef JTMB, const char *TargetTriple) {
486+
unwrap(JTMB)->getTargetTriple() = Triple(TargetTriple);
487+
}
488+
489+
void LLVMOrcJITTargetMachineBuilderDisposeTargetTriple(
490+
LLVMOrcJITTargetMachineBuilderRef JTMB, char *TargetTriple) {
491+
free(TargetTriple);
492+
}
493+
476494
void LLVMOrcObjectLayerEmit(LLVMOrcObjectLayerRef ObjLayer,
477495
LLVMOrcMaterializationResponsibilityRef R,
478496
LLVMMemoryBufferRef ObjBuffer) {

llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_llvm_unittest(OrcJITTests
1717
IndirectionUtilsTest.cpp
1818
JITTargetMachineBuilderTest.cpp
1919
LazyCallThroughAndReexportsTest.cpp
20+
OrcCAPITest.cpp
2021
OrcTestCommon.cpp
2122
QueueChannel.cpp
2223
ResourceTrackerTest.cpp
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
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/LLJIT.h"
11+
#include "llvm-c/Orc.h"
12+
#include "gtest/gtest.h"
13+
14+
#include "llvm/Support/Debug.h"
15+
#include "llvm/Support/raw_ostream.h"
16+
17+
using namespace llvm;
18+
19+
// OrcCAPITestBase contains several helper methods and pointers for unit tests
20+
// written for the LLVM-C API. It provides the following helpers:
21+
//
22+
// 1. Jit: an LLVMOrcLLJIT instance which is freed upon test exit
23+
// 2. ExecutionSession: the LLVMOrcExecutionSession for the JIT
24+
// 3. MainDylib: the main JITDylib for the LLJIT instance
25+
// 4. materializationUnitFn: function pointer to an empty function, used for
26+
// materialization unit testing
27+
// 5. definitionGeneratorFn: function pointer for a basic
28+
// LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction
29+
// 6. createTestModule: helper method for creating a basic thread-safe-module
30+
class OrcCAPITestBase : public testing::Test {
31+
protected:
32+
LLVMOrcLLJITRef Jit = nullptr;
33+
LLVMOrcExecutionSessionRef ExecutionSession = nullptr;
34+
LLVMOrcJITDylibRef MainDylib = nullptr;
35+
36+
public:
37+
static void SetUpTestCase() {
38+
LLVMInitializeNativeTarget();
39+
40+
// Attempt to set up a JIT instance once to verify that we can.
41+
LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr;
42+
if (LLVMErrorRef E = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB)) {
43+
// If setup fails then disable these tests.
44+
LLVMConsumeError(E);
45+
TargetSupported = false;
46+
return;
47+
}
48+
49+
char *Triple = LLVMOrcJITTargetMachineBuilderGetTargetTriple(JTMB);
50+
if (!isSupported(Triple)) {
51+
// If this triple isn't supported then bail out.
52+
TargetSupported = false;
53+
LLVMOrcJITTargetMachineBuilderDisposeTargetTriple(JTMB, Triple);
54+
LLVMOrcDisposeJITTargetMachineBuilder(JTMB);
55+
return;
56+
}
57+
58+
LLVMOrcJITTargetMachineBuilderDisposeTargetTriple(JTMB, Triple);
59+
LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder();
60+
LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB);
61+
LLVMOrcLLJITRef J;
62+
if (LLVMErrorRef E = LLVMOrcCreateLLJIT(&J, Builder)) {
63+
// If setup fails then disable these tests.
64+
TargetSupported = false;
65+
LLVMConsumeError(E);
66+
return;
67+
}
68+
69+
LLVMOrcDisposeLLJIT(J);
70+
TargetSupported = true;
71+
}
72+
73+
void SetUp() override {
74+
if (!TargetSupported)
75+
return;
76+
77+
LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr;
78+
LLVMErrorRef E1 = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB);
79+
assert(E1 == LLVMErrorSuccess && "Expected call to detect host to succeed");
80+
81+
LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder();
82+
LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB);
83+
LLVMErrorRef E2 = LLVMOrcCreateLLJIT(&Jit, Builder);
84+
assert(E2 == LLVMErrorSuccess &&
85+
"Expected call to create LLJIT to succeed");
86+
ExecutionSession = LLVMOrcLLJITGetExecutionSession(Jit);
87+
MainDylib = LLVMOrcLLJITGetMainJITDylib(Jit);
88+
}
89+
void TearDown() override {
90+
LLVMOrcDisposeLLJIT(Jit);
91+
Jit = nullptr;
92+
}
93+
94+
protected:
95+
static bool isSupported(StringRef Triple) {
96+
if (Triple.startswith("armv7"))
97+
return false;
98+
return true;
99+
}
100+
101+
static void materializationUnitFn() {}
102+
// Stub definition generator, where all Names are materialized from the
103+
// materializationUnitFn() test function and defined into the JIT Dylib
104+
static LLVMErrorRef
105+
definitionGeneratorFn(LLVMOrcDefinitionGeneratorRef G, void *Ctx,
106+
LLVMOrcLookupStateRef *LS, LLVMOrcLookupKind K,
107+
LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags F,
108+
LLVMOrcCLookupSet Names, size_t NamesCount) {
109+
for (size_t I = 0; I < NamesCount; I++) {
110+
LLVMOrcCLookupSetElement Element = Names[I];
111+
LLVMOrcJITTargetAddress Addr =
112+
(LLVMOrcJITTargetAddress)(&materializationUnitFn);
113+
LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0};
114+
LLVMJITEvaluatedSymbol Sym = {Addr, Flags};
115+
LLVMOrcRetainSymbolStringPoolEntry(Element.Name);
116+
LLVMJITCSymbolMapPair Pair = {Element.Name, Sym};
117+
LLVMJITCSymbolMapPair Pairs[] = {Pair};
118+
LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1);
119+
LLVMErrorRef Err = LLVMOrcJITDylibDefine(JD, MU);
120+
if (Err)
121+
return Err;
122+
}
123+
return LLVMErrorSuccess;
124+
}
125+
// create a test LLVM IR module containing a function named "sum" which has
126+
// returns the sum of its two parameters
127+
static LLVMOrcThreadSafeModuleRef createTestModule() {
128+
LLVMOrcThreadSafeContextRef TSC = LLVMOrcCreateNewThreadSafeContext();
129+
LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSC);
130+
LLVMModuleRef Mod = LLVMModuleCreateWithNameInContext("test", Ctx);
131+
{
132+
LLVMTypeRef Int32Ty = LLVMInt32TypeInContext(Ctx);
133+
LLVMTypeRef ParamTys[] = {Int32Ty, Int32Ty};
134+
LLVMTypeRef TestFnTy = LLVMFunctionType(Int32Ty, ParamTys, 2, 0);
135+
LLVMValueRef TestFn = LLVMAddFunction(Mod, "sum", TestFnTy);
136+
LLVMBuilderRef IRBuilder = LLVMCreateBuilderInContext(Ctx);
137+
LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(TestFn, "entry");
138+
LLVMPositionBuilderAtEnd(IRBuilder, EntryBB);
139+
LLVMValueRef Arg1 = LLVMGetParam(TestFn, 0);
140+
LLVMValueRef Arg2 = LLVMGetParam(TestFn, 1);
141+
LLVMValueRef Sum = LLVMBuildAdd(IRBuilder, Arg1, Arg2, "");
142+
LLVMBuildRet(IRBuilder, Sum);
143+
LLVMDisposeBuilder(IRBuilder);
144+
}
145+
LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(Mod, TSC);
146+
LLVMOrcDisposeThreadSafeContext(TSC);
147+
return TSM;
148+
}
149+
150+
static bool TargetSupported;
151+
};
152+
153+
bool OrcCAPITestBase::TargetSupported = false;
154+
155+
TEST_F(OrcCAPITestBase, SymbolStringPoolUniquing) {
156+
if (!Jit) {
157+
// TODO: Use GTEST_SKIP() when GTest is updated to version 1.10.0
158+
return;
159+
}
160+
161+
LLVMOrcSymbolStringPoolEntryRef E1 =
162+
LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa");
163+
LLVMOrcSymbolStringPoolEntryRef E2 =
164+
LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa");
165+
LLVMOrcSymbolStringPoolEntryRef E3 =
166+
LLVMOrcExecutionSessionIntern(ExecutionSession, "bbb");
167+
const char *SymbolName = LLVMOrcSymbolStringPoolEntryStr(E1);
168+
ASSERT_EQ(E1, E2) << "String pool entries are not unique";
169+
ASSERT_NE(E1, E3) << "Unique symbol pool entries are equal";
170+
ASSERT_STREQ("aaa", SymbolName) << "String value of symbol is not equal";
171+
LLVMOrcReleaseSymbolStringPoolEntry(E1);
172+
LLVMOrcReleaseSymbolStringPoolEntry(E2);
173+
LLVMOrcReleaseSymbolStringPoolEntry(E3);
174+
}
175+
176+
TEST_F(OrcCAPITestBase, JITDylibLookup) {
177+
if (!Jit) {
178+
// TODO: Use GTEST_SKIP() when GTest is updated to version 1.10.0
179+
return;
180+
}
181+
LLVMOrcJITDylibRef DoesNotExist =
182+
LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test");
183+
ASSERT_FALSE(!!DoesNotExist);
184+
LLVMOrcJITDylibRef L1 =
185+
LLVMOrcExecutionSessionCreateBareJITDylib(ExecutionSession, "test");
186+
LLVMOrcJITDylibRef L2 =
187+
LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test");
188+
ASSERT_EQ(L1, L2) << "Located JIT Dylib is not equal to original";
189+
}
190+
191+
TEST_F(OrcCAPITestBase, MaterializationUnitCreation) {
192+
if (!Jit) {
193+
// TODO: Use GTEST_SKIP() when GTest is updated to version 1.10.0
194+
return;
195+
}
196+
197+
LLVMOrcSymbolStringPoolEntryRef Name =
198+
LLVMOrcLLJITMangleAndIntern(Jit, "test");
199+
LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0};
200+
LLVMOrcJITTargetAddress Addr =
201+
(LLVMOrcJITTargetAddress)(&materializationUnitFn);
202+
LLVMJITEvaluatedSymbol Sym = {Addr, Flags};
203+
LLVMJITCSymbolMapPair Pair = {Name, Sym};
204+
LLVMJITCSymbolMapPair Pairs[] = {Pair};
205+
LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1);
206+
LLVMOrcJITDylibDefine(MainDylib, MU);
207+
LLVMOrcJITTargetAddress OutAddr;
208+
if (LLVMOrcLLJITLookup(Jit, &OutAddr, "test")) {
209+
FAIL() << "Failed to look up \"test\" symbol";
210+
}
211+
ASSERT_EQ(Addr, OutAddr);
212+
}
213+
214+
TEST_F(OrcCAPITestBase, DefinitionGenerators) {
215+
if (!Jit) {
216+
// TODO: Use GTEST_SKIP() when GTest is updated to version 1.10.0
217+
return;
218+
}
219+
220+
LLVMOrcDefinitionGeneratorRef Gen =
221+
LLVMOrcCreateCustomCAPIDefinitionGenerator(&definitionGeneratorFn,
222+
nullptr);
223+
LLVMOrcJITDylibAddGenerator(MainDylib, Gen);
224+
LLVMOrcJITTargetAddress OutAddr;
225+
if (LLVMOrcLLJITLookup(Jit, &OutAddr, "test")) {
226+
FAIL() << "The DefinitionGenerator did not create symbol \"test\"";
227+
}
228+
LLVMOrcJITTargetAddress ExpectedAddr =
229+
(LLVMOrcJITTargetAddress)(&materializationUnitFn);
230+
ASSERT_EQ(ExpectedAddr, OutAddr);
231+
}
232+
233+
TEST_F(OrcCAPITestBase, ResourceTrackerDefinitionLifetime) {
234+
if (!Jit) {
235+
// TODO: Use GTEST_SKIP() when GTest is updated to version 1.10.0
236+
return;
237+
}
238+
239+
// This test case ensures that all symbols loaded into a JITDylib with a
240+
// ResourceTracker attached are cleared from the JITDylib once the RT is
241+
// removed.
242+
LLVMOrcResourceTrackerRef RT =
243+
LLVMOrcJITDylibCreateResourceTracker(MainDylib);
244+
LLVMOrcThreadSafeModuleRef TSM = createTestModule();
245+
if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, RT, TSM)) {
246+
FAIL() << "Failed to add LLVM IR module to LLJIT";
247+
}
248+
LLVMOrcJITTargetAddress TestFnAddr;
249+
if (LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum")) {
250+
FAIL() << "Symbol \"sum\" was not added into JIT";
251+
}
252+
ASSERT_TRUE(!!TestFnAddr);
253+
LLVMOrcResourceTrackerRemove(RT);
254+
LLVMOrcJITTargetAddress OutAddr;
255+
LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &OutAddr, "sum");
256+
ASSERT_TRUE(Err);
257+
ASSERT_FALSE(OutAddr);
258+
LLVMOrcReleaseResourceTracker(RT);
259+
LLVMConsumeError(Err);
260+
}
261+
262+
TEST_F(OrcCAPITestBase, ResourceTrackerTransfer) {
263+
if (!Jit) {
264+
// TODO: Use GTEST_SKIP() when GTest is updated to version 1.10.0
265+
return;
266+
}
267+
268+
LLVMOrcResourceTrackerRef DefaultRT =
269+
LLVMOrcJITDylibGetDefaultResourceTracker(MainDylib);
270+
LLVMOrcResourceTrackerRef RT2 =
271+
LLVMOrcJITDylibCreateResourceTracker(MainDylib);
272+
LLVMOrcThreadSafeModuleRef TSM = createTestModule();
273+
if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, DefaultRT, TSM)) {
274+
FAIL() << "Failed to add LLVM IR module to LLJIT";
275+
}
276+
LLVMOrcJITTargetAddress Addr;
277+
if (LLVMOrcLLJITLookup(Jit, &Addr, "sum")) {
278+
FAIL() << "Symbol \"sum\" was not added into JIT";
279+
}
280+
LLVMOrcResourceTrackerTransferTo(DefaultRT, RT2);
281+
LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "sum");
282+
ASSERT_FALSE(Err);
283+
LLVMOrcReleaseResourceTracker(RT2);
284+
}
285+
286+
TEST_F(OrcCAPITestBase, ExecutionTest) {
287+
if (!Jit) {
288+
// TODO: Use GTEST_SKIP() when GTest is updated to version 1.10.0
289+
return;
290+
}
291+
292+
using SumFunctionType = int32_t (*)(int32_t, int32_t);
293+
294+
// This test performs OrcJIT compilation of a simple sum module
295+
LLVMInitializeNativeAsmPrinter();
296+
LLVMOrcThreadSafeModuleRef TSM = createTestModule();
297+
if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModule(Jit, MainDylib, TSM)) {
298+
FAIL() << "Failed to add LLVM IR module to LLJIT";
299+
}
300+
LLVMOrcJITTargetAddress TestFnAddr;
301+
if (LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum")) {
302+
FAIL() << "Symbol \"sum\" was not added into JIT";
303+
}
304+
auto *SumFn = (SumFunctionType)(TestFnAddr);
305+
int32_t Result = SumFn(1, 1);
306+
ASSERT_EQ(2, Result);
307+
}

0 commit comments

Comments
 (0)