1 //===-------- BasicOrcV2CBindings.c - Basic OrcV2 C Bindings Demo ---------===//
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/IRReader.h"
12 #include "llvm-c/LLJIT.h"
13 #include "llvm-c/Support.h"
14 #include "llvm-c/Target.h"
20 int handleError(LLVMErrorRef Err
) {
21 char *ErrMsg
= LLVMGetErrorMessage(Err
);
22 fprintf(stderr
, "Error: %s\n", ErrMsg
);
23 LLVMDisposeErrorMessage(ErrMsg
);
27 // Example IR modules.
29 // Note that in the conditionally compiled modules, FooMod and BarMod, functions
30 // have been given an _body suffix. This is to ensure that their names do not
31 // clash with their lazy-reexports.
32 // For clients who do not wish to rename function bodies (e.g. because they want
33 // to re-use cached objects between static and JIT compiles) techniques exist to
34 // avoid renaming. See the lazy-reexports section of the ORCv2 design doc.
36 const char FooMod
[] = " define i32 @foo_body() { \n"
41 const char BarMod
[] = " define i32 @bar_body() { \n"
46 const char MainMod
[] =
47 " define i32 @entry(i32 %argc) { \n"
49 " %and = and i32 %argc, 1 \n"
50 " %tobool = icmp eq i32 %and, 0 \n"
51 " br i1 %tobool, label %if.end, label %if.then \n"
54 " %call = tail call i32 @foo() \n"
55 " br label %return \n"
58 " %call1 = tail call i32 @bar() \n"
59 " br label %return \n"
62 " %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.end ] \n"
63 " ret i32 %retval.0 \n"
66 " declare i32 @foo() \n"
67 " declare i32 @bar() \n";
69 LLVMErrorRef
applyDataLayout(void *Ctx
, LLVMModuleRef M
) {
70 LLVMSetDataLayout(M
, LLVMOrcLLJITGetDataLayoutStr((LLVMOrcLLJITRef
)Ctx
));
71 return LLVMErrorSuccess
;
74 LLVMErrorRef
parseExampleModule(const char *Source
, size_t Len
,
76 LLVMOrcThreadSafeModuleRef
*TSM
) {
77 // Create a new ThreadSafeContext and underlying LLVMContext.
78 LLVMOrcThreadSafeContextRef TSCtx
= LLVMOrcCreateNewThreadSafeContext();
80 // Get a reference to the underlying LLVMContext.
81 LLVMContextRef Ctx
= LLVMOrcThreadSafeContextGetContext(TSCtx
);
83 // Wrap Source in a MemoryBuffer
84 LLVMMemoryBufferRef MB
=
85 LLVMCreateMemoryBufferWithMemoryRange(Source
, Len
, Name
, 1);
87 // Parse the LLVM module.
90 if (LLVMParseIRInContext(Ctx
, MB
, &M
, &ErrMsg
)) {
91 LLVMErrorRef Err
= LLVMCreateStringError(ErrMsg
);
92 LLVMDisposeMessage(ErrMsg
);
96 // Our module is now complete. Wrap it and our ThreadSafeContext in a
98 *TSM
= LLVMOrcCreateNewThreadSafeModule(M
, TSCtx
);
100 // Dispose of our local ThreadSafeContext value. The underlying LLVMContext
101 // will be kept alive by our ThreadSafeModule, TSM.
102 LLVMOrcDisposeThreadSafeContext(TSCtx
);
104 return LLVMErrorSuccess
;
107 void Destroy(void *Ctx
) {}
109 void Materialize(void *Ctx
, LLVMOrcMaterializationResponsibilityRef MR
) {
113 LLVMOrcSymbolStringPoolEntryRef
*Symbols
=
114 LLVMOrcMaterializationResponsibilityGetRequestedSymbols(MR
, &NumSymbols
);
116 assert(NumSymbols
== 1);
118 LLVMOrcLLJITRef J
= (LLVMOrcLLJITRef
)Ctx
;
119 LLVMOrcSymbolStringPoolEntryRef Sym
= Symbols
[0];
121 LLVMOrcThreadSafeModuleRef TSM
= 0;
124 LLVMOrcSymbolStringPoolEntryRef FooBody
=
125 LLVMOrcLLJITMangleAndIntern(J
, "foo_body");
126 LLVMOrcSymbolStringPoolEntryRef BarBody
=
127 LLVMOrcLLJITMangleAndIntern(J
, "bar_body");
129 if (Sym
== FooBody
) {
130 if ((Err
= parseExampleModule(FooMod
, strlen(FooMod
), "foo-mod", &TSM
))) {
131 MainResult
= handleError(Err
);
134 } else if (Sym
== BarBody
) {
135 if ((Err
= parseExampleModule(BarMod
, strlen(BarMod
), "bar-mod", &TSM
))) {
136 MainResult
= handleError(Err
);
145 if ((Err
= LLVMOrcThreadSafeModuleWithModuleDo(TSM
, &applyDataLayout
, Ctx
))) {
146 MainResult
= handleError(Err
);
151 LLVMOrcReleaseSymbolStringPoolEntry(BarBody
);
152 LLVMOrcReleaseSymbolStringPoolEntry(FooBody
);
153 LLVMOrcDisposeSymbols(Symbols
);
154 if (MainResult
== 1) {
155 LLVMOrcMaterializationResponsibilityFailMaterialization(MR
);
156 LLVMOrcDisposeMaterializationResponsibility(MR
);
158 LLVMOrcIRTransformLayerRef IRLayer
= LLVMOrcLLJITGetIRTransformLayer(J
);
159 LLVMOrcIRTransformLayerEmit(IRLayer
, MR
, TSM
);
163 int main(int argc
, const char *argv
[]) {
167 // Parse command line arguments and initialize LLVM Core.
168 LLVMParseCommandLineOptions(argc
, argv
, "");
170 // Initialize native target codegen and asm printer.
171 LLVMInitializeNativeTarget();
172 LLVMInitializeNativeAsmPrinter();
174 // Set up a JIT instance.
176 const char *TargetTriple
;
179 if ((Err
= LLVMOrcCreateLLJIT(&J
, 0))) {
180 MainResult
= handleError(Err
);
183 TargetTriple
= LLVMOrcLLJITGetTripleString(J
);
186 // Add our main module to the JIT.
188 LLVMOrcJITDylibRef MainJD
= LLVMOrcLLJITGetMainJITDylib(J
);
191 LLVMOrcThreadSafeModuleRef MainTSM
;
192 if ((Err
= parseExampleModule(MainMod
, strlen(MainMod
), "main-mod",
194 MainResult
= handleError(Err
);
198 if ((Err
= LLVMOrcLLJITAddLLVMIRModule(J
, MainJD
, MainTSM
))) {
199 LLVMOrcDisposeThreadSafeModule(MainTSM
);
200 MainResult
= handleError(Err
);
205 LLVMJITSymbolFlags Flags
= {
206 LLVMJITSymbolGenericFlagsExported
| LLVMJITSymbolGenericFlagsCallable
, 0};
207 LLVMOrcCSymbolFlagsMapPair FooSym
= {
208 LLVMOrcLLJITMangleAndIntern(J
, "foo_body"), Flags
};
209 LLVMOrcCSymbolFlagsMapPair BarSym
= {
210 LLVMOrcLLJITMangleAndIntern(J
, "bar_body"), Flags
};
212 // add custom MaterializationUnit
214 LLVMOrcMaterializationUnitRef FooMU
=
215 LLVMOrcCreateCustomMaterializationUnit("FooMU", J
, &FooSym
, 1, NULL
,
216 &Materialize
, NULL
, &Destroy
);
218 LLVMOrcMaterializationUnitRef BarMU
=
219 LLVMOrcCreateCustomMaterializationUnit("BarMU", J
, &BarSym
, 1, NULL
,
220 &Materialize
, NULL
, &Destroy
);
222 LLVMOrcJITDylibRef MainJD
= LLVMOrcLLJITGetMainJITDylib(J
);
223 LLVMOrcJITDylibDefine(MainJD
, FooMU
);
224 LLVMOrcJITDylibDefine(MainJD
, BarMU
);
227 // add lazy reexports
228 LLVMOrcIndirectStubsManagerRef ISM
=
229 LLVMOrcCreateLocalIndirectStubsManager(TargetTriple
);
231 LLVMOrcLazyCallThroughManagerRef LCTM
;
234 LLVMOrcExecutionSessionRef ES
= LLVMOrcLLJITGetExecutionSession(J
);
235 if ((Err
= LLVMOrcCreateLocalLazyCallThroughManager(TargetTriple
, ES
, 0,
237 LLVMOrcDisposeIndirectStubsManager(ISM
);
238 MainResult
= handleError(Err
);
243 LLVMOrcCSymbolAliasMapPair ReExports
[2] = {
244 {LLVMOrcLLJITMangleAndIntern(J
, "foo"),
245 {LLVMOrcLLJITMangleAndIntern(J
, "foo_body"), Flags
}},
246 {LLVMOrcLLJITMangleAndIntern(J
, "bar"),
247 {LLVMOrcLLJITMangleAndIntern(J
, "bar_body"), Flags
}},
251 LLVMOrcJITDylibRef MainJD
= LLVMOrcLLJITGetMainJITDylib(J
);
252 LLVMOrcMaterializationUnitRef MU
=
253 LLVMOrcLazyReexports(LCTM
, ISM
, MainJD
, ReExports
, 2);
254 LLVMOrcJITDylibDefine(MainJD
, MU
);
257 // Look up the address of our demo entry point.
258 LLVMOrcJITTargetAddress EntryAddr
;
261 if ((Err
= LLVMOrcLLJITLookup(J
, &EntryAddr
, "entry"))) {
262 MainResult
= handleError(Err
);
267 // If we made it here then everything succeeded. Execute our JIT'd code.
268 int32_t (*Entry
)(int32_t) = (int32_t(*)(int32_t))EntryAddr
;
269 int32_t Result
= Entry(argc
);
271 printf("--- Result ---\n");
272 printf("entry(%i) = %i\n", argc
, Result
);
275 LLVMOrcDisposeIndirectStubsManager(ISM
);
276 LLVMOrcDisposeLazyCallThroughManager(LCTM
);
280 // Destroy our JIT instance. This will clean up any memory that the JIT has
281 // taken ownership of. This operation is non-trivial (e.g. it may need to
282 // JIT static destructors) and may also fail. In that case we want to render
283 // the error to stderr, but not overwrite any existing return value.
286 if ((Err
= LLVMOrcDisposeLLJIT(J
))) {
287 int NewFailureResult
= handleError(Err
);
289 MainResult
= NewFailureResult
;