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/LLJIT.h"
13#include "llvm-c/Support.h"
14#include "llvm-c/Target.h"
15
16#include <assert.h>
17#include <stdio.h>
18#include <string.h>
19
20int handleError(LLVMErrorRef Err) {
21 char *ErrMsg = LLVMGetErrorMessage(Err);
22 fprintf(stderr, format: "Error: %s\n", ErrMsg);
23 LLVMDisposeErrorMessage(ErrMsg);
24 return 1;
25}
26
27// Example IR modules.
28//
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.
35
36const char FooMod[] = " define i32 @foo_body() { \n"
37 " entry: \n"
38 " ret i32 1 \n"
39 " } \n";
40
41const char BarMod[] = " define i32 @bar_body() { \n"
42 " entry: \n"
43 " ret i32 2 \n"
44 " } \n";
45
46const char MainMod[] =
47 " define i32 @entry(i32 %argc) { \n"
48 " entry: \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"
52 " \n"
53 " if.then: \n"
54 " %call = tail call i32 @foo() \n"
55 " br label %return \n"
56 " \n"
57 " if.end: \n"
58 " %call1 = tail call i32 @bar() \n"
59 " br label %return \n"
60 " \n"
61 " return: \n"
62 " %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.end ] \n"
63 " ret i32 %retval.0 \n"
64 " } \n"
65 " \n"
66 " declare i32 @foo() \n"
67 " declare i32 @bar() \n";
68
69LLVMErrorRef applyDataLayout(void *Ctx, LLVMModuleRef M) {
70 LLVMSetDataLayout(M, DataLayoutStr: LLVMOrcLLJITGetDataLayoutStr(J: (LLVMOrcLLJITRef)Ctx));
71 return LLVMErrorSuccess;
72}
73
74LLVMErrorRef parseExampleModule(const char *Source, size_t Len,
75 const char *Name,
76 LLVMOrcThreadSafeModuleRef *TSM) {
77 // Create a new ThreadSafeContext and underlying LLVMContext.
78 LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext();
79
80 // Get a reference to the underlying LLVMContext.
81 LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx);
82
83 // Wrap Source in a MemoryBuffer
84 LLVMMemoryBufferRef MB =
85 LLVMCreateMemoryBufferWithMemoryRange(InputData: Source, InputDataLength: Len, BufferName: Name, RequiresNullTerminator: 1);
86
87 // Parse the LLVM module.
88 LLVMModuleRef M;
89 char *ErrMsg;
90 if (LLVMParseIRInContext(ContextRef: Ctx, MemBuf: MB, OutM: &M, OutMessage: &ErrMsg)) {
91 LLVMErrorRef Err = LLVMCreateStringError(ErrMsg);
92 LLVMDisposeMessage(Message: ErrMsg);
93 return Err;
94 }
95
96 // Our module is now complete. Wrap it and our ThreadSafeContext in a
97 // ThreadSafeModule.
98 *TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);
99
100 // Dispose of our local ThreadSafeContext value. The underlying LLVMContext
101 // will be kept alive by our ThreadSafeModule, TSM.
102 LLVMOrcDisposeThreadSafeContext(TSCtx);
103
104 return LLVMErrorSuccess;
105}
106
107void Destroy(void *Ctx) {}
108
109void Materialize(void *Ctx, LLVMOrcMaterializationResponsibilityRef MR) {
110 int MainResult = 0;
111
112 size_t NumSymbols;
113 LLVMOrcSymbolStringPoolEntryRef *Symbols =
114 LLVMOrcMaterializationResponsibilityGetRequestedSymbols(MR, NumSymbols: &NumSymbols);
115
116 assert(NumSymbols == 1);
117
118 LLVMOrcLLJITRef J = (LLVMOrcLLJITRef)Ctx;
119 LLVMOrcSymbolStringPoolEntryRef Sym = Symbols[0];
120
121 LLVMOrcThreadSafeModuleRef TSM = 0;
122 LLVMErrorRef Err;
123
124 LLVMOrcSymbolStringPoolEntryRef FooBody =
125 LLVMOrcLLJITMangleAndIntern(J, UnmangledName: "foo_body");
126 LLVMOrcSymbolStringPoolEntryRef BarBody =
127 LLVMOrcLLJITMangleAndIntern(J, UnmangledName: "bar_body");
128
129 if (Sym == FooBody) {
130 if ((Err = parseExampleModule(Source: FooMod, Len: strlen(s: FooMod), Name: "foo-mod", TSM: &TSM))) {
131 MainResult = handleError(Err);
132 goto cleanup;
133 }
134 } else if (Sym == BarBody) {
135 if ((Err = parseExampleModule(Source: BarMod, Len: strlen(s: BarMod), Name: "bar-mod", TSM: &TSM))) {
136 MainResult = handleError(Err);
137 goto cleanup;
138 }
139 } else {
140 MainResult = 1;
141 goto cleanup;
142 }
143 assert(TSM);
144
145 if ((Err = LLVMOrcThreadSafeModuleWithModuleDo(TSM, F: &applyDataLayout, Ctx))) {
146 MainResult = handleError(Err);
147 goto cleanup;
148 }
149
150cleanup:
151 LLVMOrcReleaseSymbolStringPoolEntry(S: BarBody);
152 LLVMOrcReleaseSymbolStringPoolEntry(S: FooBody);
153 LLVMOrcDisposeSymbols(Symbols);
154 if (MainResult == 1) {
155 LLVMOrcMaterializationResponsibilityFailMaterialization(MR);
156 LLVMOrcDisposeMaterializationResponsibility(MR);
157 } else {
158 LLVMOrcIRTransformLayerRef IRLayer = LLVMOrcLLJITGetIRTransformLayer(J);
159 LLVMOrcIRTransformLayerEmit(IRTransformLayer: IRLayer, MR, TSM);
160 }
161}
162
163int main(int argc, const char *argv[]) {
164
165 int MainResult = 0;
166
167 // Parse command line arguments and initialize LLVM Core.
168 LLVMParseCommandLineOptions(argc, argv, Overview: "");
169
170 // Initialize native target codegen and asm printer.
171 LLVMInitializeNativeTarget();
172 LLVMInitializeNativeAsmPrinter();
173
174 // Set up a JIT instance.
175 LLVMOrcLLJITRef J;
176 const char *TargetTriple;
177 {
178 LLVMErrorRef Err;
179 if ((Err = LLVMOrcCreateLLJIT(Result: &J, Builder: 0))) {
180 MainResult = handleError(Err);
181 goto llvm_shutdown;
182 }
183 TargetTriple = LLVMOrcLLJITGetTripleString(J);
184 }
185
186 // Add our main module to the JIT.
187 {
188 LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
189 LLVMErrorRef Err;
190
191 LLVMOrcThreadSafeModuleRef MainTSM;
192 if ((Err = parseExampleModule(Source: MainMod, Len: strlen(s: MainMod), Name: "main-mod",
193 TSM: &MainTSM))) {
194 MainResult = handleError(Err);
195 goto jit_cleanup;
196 }
197
198 if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, JD: MainJD, TSM: MainTSM))) {
199 LLVMOrcDisposeThreadSafeModule(TSM: MainTSM);
200 MainResult = handleError(Err);
201 goto jit_cleanup;
202 }
203 }
204
205 LLVMJITSymbolFlags Flags = {
206 LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};
207 LLVMOrcCSymbolFlagsMapPair FooSym = {
208 LLVMOrcLLJITMangleAndIntern(J, UnmangledName: "foo_body"), Flags};
209 LLVMOrcCSymbolFlagsMapPair BarSym = {
210 LLVMOrcLLJITMangleAndIntern(J, UnmangledName: "bar_body"), Flags};
211
212 // add custom MaterializationUnit
213 {
214 LLVMOrcMaterializationUnitRef FooMU =
215 LLVMOrcCreateCustomMaterializationUnit(Name: "FooMU", Ctx: J, Syms: &FooSym, NumSyms: 1, NULL,
216 Materialize: &Materialize, NULL, Destroy: &Destroy);
217
218 LLVMOrcMaterializationUnitRef BarMU =
219 LLVMOrcCreateCustomMaterializationUnit(Name: "BarMU", Ctx: J, Syms: &BarSym, NumSyms: 1, NULL,
220 Materialize: &Materialize, NULL, Destroy: &Destroy);
221
222 LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
223 LLVMOrcJITDylibDefine(JD: MainJD, MU: FooMU);
224 LLVMOrcJITDylibDefine(JD: MainJD, MU: BarMU);
225 }
226
227 // add lazy reexports
228 LLVMOrcIndirectStubsManagerRef ISM =
229 LLVMOrcCreateLocalIndirectStubsManager(TargetTriple);
230
231 LLVMOrcLazyCallThroughManagerRef LCTM;
232 {
233 LLVMErrorRef Err;
234 LLVMOrcExecutionSessionRef ES = LLVMOrcLLJITGetExecutionSession(J);
235 if ((Err = LLVMOrcCreateLocalLazyCallThroughManager(TargetTriple, ES, ErrorHandlerAddr: 0,
236 LCTM: &LCTM))) {
237 LLVMOrcDisposeIndirectStubsManager(ISM);
238 MainResult = handleError(Err);
239 goto jit_cleanup;
240 }
241 }
242
243 LLVMOrcCSymbolAliasMapPair ReExports[2] = {
244 {LLVMOrcLLJITMangleAndIntern(J, UnmangledName: "foo"),
245 {LLVMOrcLLJITMangleAndIntern(J, UnmangledName: "foo_body"), Flags}},
246 {LLVMOrcLLJITMangleAndIntern(J, UnmangledName: "bar"),
247 {LLVMOrcLLJITMangleAndIntern(J, UnmangledName: "bar_body"), Flags}},
248 };
249
250 {
251 LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
252 LLVMOrcMaterializationUnitRef MU =
253 LLVMOrcLazyReexports(LCTM, ISM, SourceRef: MainJD, CallableAliases: ReExports, NumPairs: 2);
254 LLVMOrcJITDylibDefine(JD: MainJD, MU);
255 }
256
257 // Look up the address of our demo entry point.
258 LLVMOrcJITTargetAddress EntryAddr;
259 {
260 LLVMErrorRef Err;
261 if ((Err = LLVMOrcLLJITLookup(J, Result: &EntryAddr, Name: "entry"))) {
262 MainResult = handleError(Err);
263 goto cleanup;
264 }
265 }
266
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);
270
271 printf(format: "--- Result ---\n");
272 printf(format: "entry(%i) = %i\n", argc, Result);
273
274cleanup : {
275 LLVMOrcDisposeIndirectStubsManager(ISM);
276 LLVMOrcDisposeLazyCallThroughManager(LCTM);
277}
278
279jit_cleanup:
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.
284 {
285 LLVMErrorRef Err;
286 if ((Err = LLVMOrcDisposeLLJIT(J))) {
287 int NewFailureResult = handleError(Err);
288 if (MainResult == 0)
289 MainResult = NewFailureResult;
290 }
291 }
292
293llvm_shutdown:
294 // Shut down LLVM.
295 LLVMShutdown();
296
297 return MainResult;
298}
299

source code of llvm/examples/OrcV2Examples/OrcV2CBindingsVeryLazy/OrcV2CBindingsVeryLazy.c