Skip to content

Commit 7b73cd6

Browse files
committed
[ORC] Introduce C API for adding object buffers directly to an object layer.
This can be useful for clients constructing custom JIT stacks: If the C API for your custom stack exposes API to obtain a reference to an object layer (e.g. LLVMOrcLLJITGetObjLinkingLayer) then the newly added LLVMOrcObjectLayerAddObjectFile and LLVMOrcObjectLayerAddObjectFileWithRT functions can be used to add objects directly to that layer.
1 parent 6fac342 commit 7b73cd6

File tree

3 files changed

+132
-24
lines changed

3 files changed

+132
-24
lines changed

llvm/include/llvm-c/Orc.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,37 @@ void LLVMOrcJITTargetMachineBuilderSetTargetTriple(
671671
void LLVMOrcJITTargetMachineBuilderDisposeTargetTriple(
672672
LLVMOrcJITTargetMachineBuilderRef JTMB, char *TargetTriple);
673673

674+
/**
675+
* Add an object to an ObjectLayer to the given JITDylib.
676+
*
677+
* Adds a buffer representing an object file to the given JITDylib using the
678+
* given ObjectLayer instance. This operation transfers ownership of the buffer
679+
* to the ObjectLayer instance. The buffer should not be disposed of or
680+
* referenced once this function returns.
681+
*
682+
* Resources associated with the given object will be tracked by the given
683+
* JITDylib's default ResourceTracker.
684+
*/
685+
LLVMErrorRef LLVMOrcObjectLayerAddObjectFile(LLVMOrcObjectLayerRef ObjLayer,
686+
LLVMOrcJITDylibRef JD,
687+
LLVMMemoryBufferRef ObjBuffer);
688+
689+
/**
690+
* Add an object to an ObjectLayer using the given ResourceTracker.
691+
*
692+
* Adds a buffer representing an object file to the given ResourceTracker's
693+
* JITDylib using the given ObjectLayer instance. This operation transfers
694+
* ownership of the buffer to the ObjectLayer instance. The buffer should not
695+
* be disposed of or referenced once this function returns.
696+
*
697+
* Resources associated with the given object will be tracked by
698+
* ResourceTracker RT.
699+
*/
700+
LLVMErrorRef
701+
LLVMOrcObjectLayerAddObjectFileWithRT(LLVMOrcObjectLayerRef ObjLayer,
702+
LLVMOrcResourceTrackerRef RT,
703+
LLVMMemoryBufferRef ObjBuffer);
704+
674705
/**
675706
* Emit an object buffer to an ObjectLayer.
676707
*

llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,21 @@ void LLVMOrcJITTargetMachineBuilderDisposeTargetTriple(
491491
free(TargetTriple);
492492
}
493493

494+
LLVMErrorRef LLVMOrcObjectLayerAddObjectFile(LLVMOrcObjectLayerRef ObjLayer,
495+
LLVMOrcJITDylibRef JD,
496+
LLVMMemoryBufferRef ObjBuffer) {
497+
return wrap(unwrap(ObjLayer)->add(
498+
*unwrap(JD), std::unique_ptr<MemoryBuffer>(unwrap(ObjBuffer))));
499+
}
500+
501+
LLVMErrorRef LLVMOrcLLJITAddObjectFileWithRT(LLVMOrcObjectLayerRef ObjLayer,
502+
LLVMOrcResourceTrackerRef RT,
503+
LLVMMemoryBufferRef ObjBuffer) {
504+
return wrap(
505+
unwrap(ObjLayer)->add(ResourceTrackerSP(unwrap(RT)),
506+
std::unique_ptr<MemoryBuffer>(unwrap(ObjBuffer))));
507+
}
508+
494509
void LLVMOrcObjectLayerEmit(LLVMOrcObjectLayerRef ObjLayer,
495510
LLVMOrcMaterializationResponsibilityRef R,
496511
LLVMMemoryBufferRef ObjBuffer) {

llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp

Lines changed: 86 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,18 @@
1313
#include "gtest/gtest.h"
1414

1515
#include "llvm/ADT/Triple.h"
16+
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
17+
#include "llvm/IR/LLVMContext.h"
18+
#include "llvm/IR/Module.h"
19+
#include "llvm/IRReader/IRReader.h"
20+
#include "llvm/Support/Error.h"
21+
#include "llvm/Support/SourceMgr.h"
1622
#include <string>
1723

1824
using namespace llvm;
25+
using namespace llvm::orc;
26+
27+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
1928

2029
// OrcCAPITestBase contains several helper methods and pointers for unit tests
2130
// written for the LLVM-C API. It provides the following helpers:
@@ -109,6 +118,7 @@ class OrcCAPITestBase : public testing::Test {
109118
}
110119

111120
static void materializationUnitFn() {}
121+
112122
// Stub definition generator, where all Names are materialized from the
113123
// materializationUnitFn() test function and defined into the JIT Dylib
114124
static LLVMErrorRef
@@ -132,29 +142,47 @@ class OrcCAPITestBase : public testing::Test {
132142
}
133143
return LLVMErrorSuccess;
134144
}
135-
// create a test LLVM IR module containing a function named "sum" which has
136-
// returns the sum of its two parameters
137-
static LLVMOrcThreadSafeModuleRef createTestModule() {
138-
LLVMOrcThreadSafeContextRef TSC = LLVMOrcCreateNewThreadSafeContext();
139-
LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSC);
140-
LLVMModuleRef Mod = LLVMModuleCreateWithNameInContext("test", Ctx);
145+
146+
static Error createSMDiagnosticError(llvm::SMDiagnostic &Diag) {
147+
std::string Msg;
141148
{
142-
LLVMTypeRef Int32Ty = LLVMInt32TypeInContext(Ctx);
143-
LLVMTypeRef ParamTys[] = {Int32Ty, Int32Ty};
144-
LLVMTypeRef TestFnTy = LLVMFunctionType(Int32Ty, ParamTys, 2, 0);
145-
LLVMValueRef TestFn = LLVMAddFunction(Mod, "sum", TestFnTy);
146-
LLVMBuilderRef IRBuilder = LLVMCreateBuilderInContext(Ctx);
147-
LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(TestFn, "entry");
148-
LLVMPositionBuilderAtEnd(IRBuilder, EntryBB);
149-
LLVMValueRef Arg1 = LLVMGetParam(TestFn, 0);
150-
LLVMValueRef Arg2 = LLVMGetParam(TestFn, 1);
151-
LLVMValueRef Sum = LLVMBuildAdd(IRBuilder, Arg1, Arg2, "");
152-
LLVMBuildRet(IRBuilder, Sum);
153-
LLVMDisposeBuilder(IRBuilder);
149+
raw_string_ostream OS(Msg);
150+
Diag.print("", OS);
154151
}
155-
LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(Mod, TSC);
156-
LLVMOrcDisposeThreadSafeContext(TSC);
157-
return TSM;
152+
return make_error<StringError>(std::move(Msg), inconvertibleErrorCode());
153+
}
154+
155+
// Create an LLVM IR module from the given StringRef.
156+
static Expected<std::unique_ptr<Module>>
157+
parseTestModule(LLVMContext &Ctx, StringRef Source, StringRef Name) {
158+
assert(TargetSupported &&
159+
"Attempted to create module for unsupported target");
160+
SMDiagnostic Err;
161+
if (auto M = parseIR(MemoryBufferRef(Source, Name), Err, Ctx))
162+
return std::move(M);
163+
return createSMDiagnosticError(Err);
164+
}
165+
166+
// returns the sum of its two parameters
167+
static LLVMOrcThreadSafeModuleRef createTestModule(StringRef Source,
168+
StringRef Name) {
169+
auto Ctx = std::make_unique<LLVMContext>();
170+
auto M = cantFail(parseTestModule(*Ctx, Source, Name));
171+
return wrap(new ThreadSafeModule(std::move(M), std::move(Ctx)));
172+
}
173+
174+
static LLVMMemoryBufferRef createTestObject(StringRef Source,
175+
StringRef Name) {
176+
auto Ctx = std::make_unique<LLVMContext>();
177+
auto M = cantFail(parseTestModule(*Ctx, Source, Name));
178+
179+
auto JTMB = cantFail(JITTargetMachineBuilder::detectHost());
180+
M->setDataLayout(cantFail(JTMB.getDefaultDataLayoutForTarget()));
181+
auto TM = cantFail(JTMB.createTargetMachine());
182+
183+
SimpleCompiler SC(*TM);
184+
auto ObjBuffer = cantFail(SC(*M));
185+
return wrap(ObjBuffer.release());
158186
}
159187

160188
static std::string TargetTriple;
@@ -164,6 +192,19 @@ class OrcCAPITestBase : public testing::Test {
164192
std::string OrcCAPITestBase::TargetTriple;
165193
bool OrcCAPITestBase::TargetSupported = false;
166194

195+
namespace {
196+
197+
constexpr StringRef SumExample =
198+
R"(
199+
define i32 @sum(i32 %x, i32 %y) {
200+
entry:
201+
%r = add nsw i32 %x, %y
202+
ret i32 %r
203+
}
204+
)";
205+
206+
} // end anonymous namespace.
207+
167208
// Consumes the given error ref and returns the string error message.
168209
static std::string toString(LLVMErrorRef E) {
169210
char *ErrMsg = LLVMGetErrorMessage(E);
@@ -261,7 +302,7 @@ TEST_F(OrcCAPITestBase, ResourceTrackerDefinitionLifetime) {
261302
// removed.
262303
LLVMOrcResourceTrackerRef RT =
263304
LLVMOrcJITDylibCreateResourceTracker(MainDylib);
264-
LLVMOrcThreadSafeModuleRef TSM = createTestModule();
305+
LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");
265306
if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, RT, TSM))
266307
FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple
267308
<< "): " << toString(E);
@@ -290,7 +331,7 @@ TEST_F(OrcCAPITestBase, ResourceTrackerTransfer) {
290331
LLVMOrcJITDylibGetDefaultResourceTracker(MainDylib);
291332
LLVMOrcResourceTrackerRef RT2 =
292333
LLVMOrcJITDylibCreateResourceTracker(MainDylib);
293-
LLVMOrcThreadSafeModuleRef TSM = createTestModule();
334+
LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");
294335
if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, DefaultRT, TSM))
295336
FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple
296337
<< "): " << toString(E);
@@ -304,6 +345,27 @@ TEST_F(OrcCAPITestBase, ResourceTrackerTransfer) {
304345
LLVMOrcReleaseResourceTracker(RT2);
305346
}
306347

348+
TEST_F(OrcCAPITestBase, AddObjectBuffer) {
349+
if (!Jit) {
350+
// TODO: Use GTEST_SKIP() when GTest is updated to version 1.10.0
351+
return;
352+
}
353+
354+
LLVMOrcObjectLayerRef ObjLinkingLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit);
355+
LLVMMemoryBufferRef ObjBuffer = createTestObject(SumExample, "sum.ll");
356+
357+
if (LLVMErrorRef E = LLVMOrcObjectLayerAddObjectFile(ObjLinkingLayer,
358+
MainDylib, ObjBuffer))
359+
FAIL() << "Failed to add object file to ObjLinkingLayer (triple = "
360+
<< TargetTriple << "): " << toString(E);
361+
362+
LLVMOrcJITTargetAddress SumAddr;
363+
if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &SumAddr, "sum"))
364+
FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple
365+
<< "): " << toString(E);
366+
ASSERT_TRUE(!!SumAddr);
367+
}
368+
307369
TEST_F(OrcCAPITestBase, ExecutionTest) {
308370
if (!Jit) {
309371
// TODO: Use GTEST_SKIP() when GTest is updated to version 1.10.0
@@ -314,7 +376,7 @@ TEST_F(OrcCAPITestBase, ExecutionTest) {
314376

315377
// This test performs OrcJIT compilation of a simple sum module
316378
LLVMInitializeNativeAsmPrinter();
317-
LLVMOrcThreadSafeModuleRef TSM = createTestModule();
379+
LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");
318380
if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModule(Jit, MainDylib, TSM))
319381
FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple
320382
<< ")" << toString(E);

0 commit comments

Comments
 (0)