Skip to content

Commit 45e8a0b

Browse files
committed
[Orc] At CBindings for LazyRexports
At C bindings and an example for LLJIT with lazy reexports Differential Revision: https://reviews.llvm.org/D104672
1 parent 355bf7c commit 45e8a0b

File tree

8 files changed

+406
-2
lines changed

8 files changed

+406
-2
lines changed

llvm/examples/OrcV2Examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ add_subdirectory(OrcV2CBindingsDumpObjects)
1414
add_subdirectory(OrcV2CBindingsIRTransforms)
1515
add_subdirectory(OrcV2CBindingsReflectProcessSymbols)
1616
add_subdirectory(OrcV2CBindingsRemovableCode)
17+
add_subdirectory(OrcV2CBindingsLazy)
1718

1819
if(CMAKE_HOST_UNIX)
1920
add_subdirectory(LLJITWithRemoteDebugging)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
set(LLVM_LINK_COMPONENTS
2+
Core
3+
ExecutionEngine
4+
IRReader
5+
JITLink
6+
MC
7+
OrcJIT
8+
Support
9+
Target
10+
nativecodegen
11+
)
12+
13+
add_llvm_example(OrcV2CBindingsLazy
14+
OrcV2CBindingsLazy.c
15+
)
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
//===-------- BasicOrcV2CBindings.c - Basic OrcV2 C Bindings Demo ---------===//
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/IRReader.h"
12+
#include "llvm-c/Initialization.h"
13+
#include "llvm-c/LLJIT.h"
14+
#include "llvm-c/Support.h"
15+
#include "llvm-c/Target.h"
16+
17+
#include <stdio.h>
18+
19+
int handleError(LLVMErrorRef Err) {
20+
char *ErrMsg = LLVMGetErrorMessage(Err);
21+
fprintf(stderr, "Error: %s\n", ErrMsg);
22+
LLVMDisposeErrorMessage(ErrMsg);
23+
return 1;
24+
}
25+
26+
// Example IR modules.
27+
//
28+
// Note that in the conditionally compiled modules, FooMod and BarMod, functions
29+
// have been given an _body suffix. This is to ensure that their names do not
30+
// clash with their lazy-reexports.
31+
// For clients who do not wish to rename function bodies (e.g. because they want
32+
// to re-use cached objects between static and JIT compiles) techniques exist to
33+
// avoid renaming. See the lazy-reexports section of the ORCv2 design doc.
34+
35+
const char FooMod[] = " define i32 @foo_body() { \n"
36+
" entry: \n"
37+
" ret i32 1 \n"
38+
" } \n";
39+
40+
const char BarMod[] = " define i32 @bar_body() { \n"
41+
" entry: \n"
42+
" ret i32 2 \n"
43+
" } \n";
44+
45+
const char MainMod[] =
46+
" define i32 @entry(i32 %argc) { \n"
47+
" entry: \n"
48+
" %and = and i32 %argc, 1 \n"
49+
" %tobool = icmp eq i32 %and, 0 \n"
50+
" br i1 %tobool, label %if.end, label %if.then \n"
51+
" \n"
52+
" if.then: \n"
53+
" %call = tail call i32 @foo() \n"
54+
" br label %return \n"
55+
" \n"
56+
" if.end: \n"
57+
" %call1 = tail call i32 @bar() \n"
58+
" br label %return \n"
59+
" \n"
60+
" return: \n"
61+
" %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.end ] \n"
62+
" ret i32 %retval.0 \n"
63+
" } \n"
64+
" \n"
65+
" declare i32 @foo() \n"
66+
" declare i32 @bar() \n";
67+
68+
LLVMErrorRef parseExampleModule(const char *Source, size_t Len,
69+
const char *Name,
70+
LLVMOrcThreadSafeModuleRef *TSM) {
71+
// Create a new ThreadSafeContext and underlying LLVMContext.
72+
LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext();
73+
74+
// Get a reference to the underlying LLVMContext.
75+
LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx);
76+
77+
// Wrap Source in a MemoryBuffer
78+
LLVMMemoryBufferRef MB =
79+
LLVMCreateMemoryBufferWithMemoryRange(Source, Len, Name, 0);
80+
81+
// Parse the LLVM module.
82+
LLVMModuleRef M;
83+
char *ErrMsg;
84+
if (LLVMParseIRInContext(Ctx, MB, &M, &ErrMsg)) {
85+
return LLVMCreateStringError(ErrMsg);
86+
// TODO: LLVMDisposeMessage(ErrMsg);
87+
}
88+
89+
// Our module is now complete. Wrap it and our ThreadSafeContext in a
90+
// ThreadSafeModule.
91+
*TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);
92+
93+
// Dispose of our local ThreadSafeContext value. The underlying LLVMContext
94+
// will be kept alive by our ThreadSafeModule, TSM.
95+
LLVMOrcDisposeThreadSafeContext(TSCtx);
96+
97+
return LLVMErrorSuccess;
98+
}
99+
100+
int main(int argc, char *argv[]) {
101+
102+
int MainResult = 0;
103+
104+
// Parse command line arguments and initialize LLVM Core.
105+
LLVMParseCommandLineOptions(argc, (const char **)argv, "");
106+
LLVMInitializeCore(LLVMGetGlobalPassRegistry());
107+
108+
// Initialize native target codegen and asm printer.
109+
LLVMInitializeNativeTarget();
110+
LLVMInitializeNativeAsmPrinter();
111+
112+
// Set up a JIT instance.
113+
LLVMOrcLLJITRef J;
114+
const char *TargetTriple;
115+
{
116+
LLVMErrorRef Err;
117+
if ((Err = LLVMOrcCreateLLJIT(&J, 0))) {
118+
MainResult = handleError(Err);
119+
goto llvm_shutdown;
120+
}
121+
TargetTriple = LLVMOrcLLJITGetTripleString(J);
122+
}
123+
124+
// Add our demo modules to the JIT.
125+
{
126+
LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
127+
LLVMErrorRef Err;
128+
129+
LLVMOrcThreadSafeModuleRef FooTSM;
130+
if ((Err =
131+
parseExampleModule(FooMod, sizeof(FooMod), "foo-mod", &FooTSM))) {
132+
MainResult = handleError(Err);
133+
goto jit_cleanup;
134+
}
135+
136+
if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, FooTSM))) {
137+
// If adding the ThreadSafeModule fails then we need to clean it up
138+
// ourselves. If adding it succeeds the JIT will manage the memory.
139+
LLVMOrcDisposeThreadSafeModule(FooTSM);
140+
MainResult = handleError(Err);
141+
goto jit_cleanup;
142+
}
143+
144+
LLVMOrcThreadSafeModuleRef BarTSM;
145+
if ((Err =
146+
parseExampleModule(BarMod, sizeof(BarMod), "bar-mod", &BarTSM))) {
147+
MainResult = handleError(Err);
148+
goto jit_cleanup;
149+
}
150+
151+
if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, BarTSM))) {
152+
LLVMOrcDisposeThreadSafeModule(BarTSM);
153+
MainResult = handleError(Err);
154+
goto jit_cleanup;
155+
}
156+
157+
LLVMOrcThreadSafeModuleRef MainTSM;
158+
if ((Err = parseExampleModule(MainMod, sizeof(MainMod), "main-mod",
159+
&MainTSM))) {
160+
MainResult = handleError(Err);
161+
goto jit_cleanup;
162+
}
163+
164+
if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, MainTSM))) {
165+
LLVMOrcDisposeThreadSafeModule(MainTSM);
166+
MainResult = handleError(Err);
167+
goto jit_cleanup;
168+
}
169+
}
170+
171+
// add lazy reexports
172+
LLVMOrcIndirectStubsManagerRef ISM =
173+
LLVMOrcCreateLocalIndirectStubsManager(TargetTriple);
174+
175+
LLVMOrcLazyCallThroughManagerRef LCTM;
176+
{
177+
LLVMErrorRef Err;
178+
LLVMOrcExecutionSessionRef ES = LLVMOrcLLJITGetExecutionSession(J);
179+
if ((Err = LLVMOrcCreateLocalLazyCallThroughManager(TargetTriple, ES, 0,
180+
&LCTM))) {
181+
LLVMOrcDisposeIndirectStubsManager(ISM);
182+
MainResult = handleError(Err);
183+
goto jit_cleanup;
184+
}
185+
}
186+
187+
LLVMJITSymbolFlags flag = {
188+
LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};
189+
LLVMOrcCSymbolAliasMapPair ReExports[2] = {
190+
{LLVMOrcLLJITMangleAndIntern(J, "foo"),
191+
{LLVMOrcLLJITMangleAndIntern(J, "foo_body"), flag}},
192+
{LLVMOrcLLJITMangleAndIntern(J, "bar"),
193+
{LLVMOrcLLJITMangleAndIntern(J, "bar_body"), flag}},
194+
};
195+
196+
{
197+
LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
198+
LLVMOrcMaterializationUnitRef MU =
199+
LLVMOrcLazyReexports(LCTM, ISM, MainJD, ReExports, 2);
200+
LLVMOrcJITDylibDefine(MainJD, MU);
201+
}
202+
203+
// Look up the address of our demo entry point.
204+
LLVMOrcJITTargetAddress EntryAddr;
205+
{
206+
LLVMErrorRef Err;
207+
if ((Err = LLVMOrcLLJITLookup(J, &EntryAddr, "entry"))) {
208+
MainResult = handleError(Err);
209+
goto cleanup;
210+
}
211+
}
212+
213+
// If we made it here then everything succeeded. Execute our JIT'd code.
214+
int32_t (*Entry)(int32_t) = (int32_t(*)(int32_t))EntryAddr;
215+
int32_t Result = Entry(argc);
216+
217+
printf("--- Result ---\n");
218+
printf("entry(%i) = %i\n", argc, Result);
219+
220+
cleanup : {
221+
LLVMOrcDisposeIndirectStubsManager(ISM);
222+
LLVMOrcDisposeLazyCallThroughManager(LCTM);
223+
}
224+
225+
jit_cleanup:
226+
// Destroy our JIT instance. This will clean up any memory that the JIT has
227+
// taken ownership of. This operation is non-trivial (e.g. it may need to
228+
// JIT static destructors) and may also fail. In that case we want to render
229+
// the error to stderr, but not overwrite any existing return value.
230+
{
231+
LLVMErrorRef Err;
232+
if ((Err = LLVMOrcDisposeLLJIT(J))) {
233+
int NewFailureResult = handleError(Err);
234+
if (MainResult == 0)
235+
MainResult = NewFailureResult;
236+
}
237+
}
238+
239+
llvm_shutdown:
240+
// Shut down LLVM.
241+
LLVMShutdown();
242+
243+
return MainResult;
244+
}

llvm/include/llvm-c/Orc.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,28 @@ typedef struct {
123123
*/
124124
typedef LLVMJITCSymbolMapPair *LLVMOrcCSymbolMapPairs;
125125

126+
/**
127+
* Represents a SymbolAliasMapEntry
128+
*/
129+
typedef struct {
130+
LLVMOrcSymbolStringPoolEntryRef Name;
131+
LLVMJITSymbolFlags Flags;
132+
} LLVMOrcCSymbolAliasMapEntry;
133+
134+
/**
135+
* Represents a pair of a symbol name and SymbolAliasMapEntry.
136+
*/
137+
typedef struct {
138+
LLVMOrcSymbolStringPoolEntryRef Name;
139+
LLVMOrcCSymbolAliasMapEntry Entry;
140+
} LLVMOrcCSymbolAliasMapPair;
141+
142+
/**
143+
* Represents a list of (SymbolStringPtr, (SymbolStringPtr, JITSymbolFlags))
144+
* pairs that can be used to construct a SymbolFlagsMap.
145+
*/
146+
typedef LLVMOrcCSymbolAliasMapPair *LLVMOrcCSymbolAliasMapPairs;
147+
126148
/**
127149
* Lookup kind. This can be used by definition generators when deciding whether
128150
* to produce a definition for a requested symbol.
@@ -373,6 +395,18 @@ typedef struct LLVMOrcOpaqueObjectTransformLayer
373395
typedef LLVMErrorRef (*LLVMOrcObjectTransformLayerTransformFunction)(
374396
void *Ctx, LLVMMemoryBufferRef *ObjInOut);
375397

398+
/**
399+
* A reference to an orc::IndirectStubsManager instance.
400+
*/
401+
typedef struct LLVMOrcOpaqueIndirectStubsManager
402+
*LLVMOrcIndirectStubsManagerRef;
403+
404+
/**
405+
* A reference to an orc::LazyCallThroughManager instance.
406+
*/
407+
typedef struct LLVMOrcOpaqueLazyCallThroughManager
408+
*LLVMOrcLazyCallThroughManagerRef;
409+
376410
/**
377411
* A reference to an orc::DumpObjects object.
378412
*
@@ -536,6 +570,33 @@ LLVMOrcMaterializationUnitRef LLVMOrcCreateCustomMaterializationUnit(
536570
LLVMOrcMaterializationUnitRef
537571
LLVMOrcAbsoluteSymbols(LLVMOrcCSymbolMapPairs Syms, size_t NumPairs);
538572

573+
/**
574+
* Create a MaterializationUnit to define lazy re-expots. These are callable
575+
* entry points that call through to the given symbols.
576+
*
577+
* This function takes ownership of the CallableAliases array. The Name
578+
* fields of the array elements are taken to have been retained for this
579+
* function. This allows the following pattern...
580+
*
581+
* size_t NumPairs;
582+
* LLVMOrcCSymbolAliasMapPairs CallableAliases;
583+
* -- Build CallableAliases array --
584+
* LLVMOrcMaterializationUnitRef MU =
585+
* LLVMOrcLazyReexports(LCTM, ISM, JD, CallableAliases, NumPairs);
586+
*
587+
* ... without requiring cleanup of the elements of the CallableAliases array afterwards.
588+
*
589+
* The client is still responsible for deleting the CallableAliases array itself.
590+
*
591+
* If a client wishes to reuse elements of the CallableAliases array after this call they
592+
* must explicitly retain each of the elements for themselves.
593+
*/
594+
LLVMOrcMaterializationUnitRef LLVMOrcLazyReexports(
595+
LLVMOrcLazyCallThroughManagerRef LCTM, LLVMOrcIndirectStubsManagerRef ISM,
596+
LLVMOrcJITDylibRef SourceRef, LLVMOrcCSymbolAliasMapPairs CallableAliases,
597+
size_t NumPairs);
598+
// TODO: ImplSymbolMad SrcJDLoc
599+
539600
/**
540601
* Create a "bare" JITDylib.
541602
*
@@ -799,6 +860,31 @@ void LLVMOrcObjectTransformLayerSetTransform(
799860
LLVMOrcObjectTransformLayerRef ObjTransformLayer,
800861
LLVMOrcObjectTransformLayerTransformFunction TransformFunction, void *Ctx);
801862

863+
/**
864+
* Create a LocalIndirectStubsManager from the given target triple.
865+
*
866+
* The resulting IndirectStubsManager is owned by the client
867+
* and must be disposed of by calling LLVMOrcDisposeDisposeIndirectStubsManager.
868+
*/
869+
LLVMOrcIndirectStubsManagerRef
870+
LLVMOrcCreateLocalIndirectStubsManager(const char *TargetTriple);
871+
872+
/**
873+
* Dispose of an IndirectStubsManager.
874+
*/
875+
void LLVMOrcDisposeIndirectStubsManager(LLVMOrcIndirectStubsManagerRef ISM);
876+
877+
LLVMErrorRef LLVMOrcCreateLocalLazyCallThroughManager(
878+
const char *TargetTriple, LLVMOrcExecutionSessionRef ES,
879+
LLVMOrcJITTargetAddress ErrorHandlerAddr,
880+
LLVMOrcLazyCallThroughManagerRef *LCTM);
881+
882+
/**
883+
* Dispose of an LazyCallThroughManager.
884+
*/
885+
void LLVMOrcDisposeLazyCallThroughManager(
886+
LLVMOrcLazyCallThroughManagerRef LCTM);
887+
802888
/**
803889
* Create a DumpObjects instance.
804890
*

0 commit comments

Comments
 (0)