Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / examples / OrcV2Examples / OrcV2CBindingsLazy / OrcV2CBindingsLazy.c
blob33398c8cb98165dd5e1b35f2e8a831b7dde38945
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 //===----------------------------------------------------------------------===//
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"
16 #include <stdio.h>
18 int handleError(LLVMErrorRef Err) {
19 char *ErrMsg = LLVMGetErrorMessage(Err);
20 fprintf(stderr, "Error: %s\n", ErrMsg);
21 LLVMDisposeErrorMessage(ErrMsg);
22 return 1;
25 // Example IR modules.
27 // Note that in the conditionally compiled modules, FooMod and BarMod, functions
28 // have been given an _body suffix. This is to ensure that their names do not
29 // clash with their lazy-reexports.
30 // For clients who do not wish to rename function bodies (e.g. because they want
31 // to re-use cached objects between static and JIT compiles) techniques exist to
32 // avoid renaming. See the lazy-reexports section of the ORCv2 design doc.
34 const char FooMod[] = " define i32 @foo_body() { \n"
35 " entry: \n"
36 " ret i32 1 \n"
37 " } \n";
39 const char BarMod[] = " define i32 @bar_body() { \n"
40 " entry: \n"
41 " ret i32 2 \n"
42 " } \n";
44 const char MainMod[] =
45 " define i32 @entry(i32 %argc) { \n"
46 " entry: \n"
47 " %and = and i32 %argc, 1 \n"
48 " %tobool = icmp eq i32 %and, 0 \n"
49 " br i1 %tobool, label %if.end, label %if.then \n"
50 " \n"
51 " if.then: \n"
52 " %call = tail call i32 @foo() \n"
53 " br label %return \n"
54 " \n"
55 " if.end: \n"
56 " %call1 = tail call i32 @bar() \n"
57 " br label %return \n"
58 " \n"
59 " return: \n"
60 " %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.end ] \n"
61 " ret i32 %retval.0 \n"
62 " } \n"
63 " \n"
64 " declare i32 @foo() \n"
65 " declare i32 @bar() \n";
67 LLVMErrorRef parseExampleModule(const char *Source, size_t Len,
68 const char *Name,
69 LLVMOrcThreadSafeModuleRef *TSM) {
70 // Create a new ThreadSafeContext and underlying LLVMContext.
71 LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext();
73 // Get a reference to the underlying LLVMContext.
74 LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx);
76 // Wrap Source in a MemoryBuffer
77 LLVMMemoryBufferRef MB =
78 LLVMCreateMemoryBufferWithMemoryRange(Source, Len, Name, 0);
80 // Parse the LLVM module.
81 LLVMModuleRef M;
82 char *ErrMsg;
83 if (LLVMParseIRInContext(Ctx, MB, &M, &ErrMsg)) {
84 return LLVMCreateStringError(ErrMsg);
85 // TODO: LLVMDisposeMessage(ErrMsg);
88 // Our module is now complete. Wrap it and our ThreadSafeContext in a
89 // ThreadSafeModule.
90 *TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);
92 // Dispose of our local ThreadSafeContext value. The underlying LLVMContext
93 // will be kept alive by our ThreadSafeModule, TSM.
94 LLVMOrcDisposeThreadSafeContext(TSCtx);
96 return LLVMErrorSuccess;
99 int main(int argc, const char *argv[]) {
101 int MainResult = 0;
103 // Parse command line arguments and initialize LLVM Core.
104 LLVMParseCommandLineOptions(argc, argv, "");
106 // Initialize native target codegen and asm printer.
107 LLVMInitializeNativeTarget();
108 LLVMInitializeNativeAsmPrinter();
110 // Set up a JIT instance.
111 LLVMOrcLLJITRef J;
112 const char *TargetTriple;
114 LLVMErrorRef Err;
115 if ((Err = LLVMOrcCreateLLJIT(&J, 0))) {
116 MainResult = handleError(Err);
117 goto llvm_shutdown;
119 TargetTriple = LLVMOrcLLJITGetTripleString(J);
122 // Add our demo modules to the JIT.
124 LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
125 LLVMErrorRef Err;
127 LLVMOrcThreadSafeModuleRef FooTSM;
128 if ((Err = parseExampleModule(FooMod, sizeof(FooMod) - 1, "foo-mod",
129 &FooTSM))) {
130 MainResult = handleError(Err);
131 goto jit_cleanup;
134 if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, FooTSM))) {
135 // If adding the ThreadSafeModule fails then we need to clean it up
136 // ourselves. If adding it succeeds the JIT will manage the memory.
137 LLVMOrcDisposeThreadSafeModule(FooTSM);
138 MainResult = handleError(Err);
139 goto jit_cleanup;
142 LLVMOrcThreadSafeModuleRef BarTSM;
143 if ((Err = parseExampleModule(BarMod, sizeof(BarMod) - 1, "bar-mod",
144 &BarTSM))) {
145 MainResult = handleError(Err);
146 goto jit_cleanup;
149 if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, BarTSM))) {
150 LLVMOrcDisposeThreadSafeModule(BarTSM);
151 MainResult = handleError(Err);
152 goto jit_cleanup;
155 LLVMOrcThreadSafeModuleRef MainTSM;
156 if ((Err = parseExampleModule(MainMod, sizeof(MainMod) - 1, "main-mod",
157 &MainTSM))) {
158 MainResult = handleError(Err);
159 goto jit_cleanup;
162 if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, MainTSM))) {
163 LLVMOrcDisposeThreadSafeModule(MainTSM);
164 MainResult = handleError(Err);
165 goto jit_cleanup;
169 // add lazy reexports
170 LLVMOrcIndirectStubsManagerRef ISM =
171 LLVMOrcCreateLocalIndirectStubsManager(TargetTriple);
173 LLVMOrcLazyCallThroughManagerRef LCTM;
175 LLVMErrorRef Err;
176 LLVMOrcExecutionSessionRef ES = LLVMOrcLLJITGetExecutionSession(J);
177 if ((Err = LLVMOrcCreateLocalLazyCallThroughManager(TargetTriple, ES, 0,
178 &LCTM))) {
179 LLVMOrcDisposeIndirectStubsManager(ISM);
180 MainResult = handleError(Err);
181 goto jit_cleanup;
185 LLVMJITSymbolFlags flag = {
186 LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};
187 LLVMOrcCSymbolAliasMapPair ReExports[2] = {
188 {LLVMOrcLLJITMangleAndIntern(J, "foo"),
189 {LLVMOrcLLJITMangleAndIntern(J, "foo_body"), flag}},
190 {LLVMOrcLLJITMangleAndIntern(J, "bar"),
191 {LLVMOrcLLJITMangleAndIntern(J, "bar_body"), flag}},
195 LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
196 LLVMOrcMaterializationUnitRef MU =
197 LLVMOrcLazyReexports(LCTM, ISM, MainJD, ReExports, 2);
198 LLVMOrcJITDylibDefine(MainJD, MU);
201 // Look up the address of our demo entry point.
202 LLVMOrcJITTargetAddress EntryAddr;
204 LLVMErrorRef Err;
205 if ((Err = LLVMOrcLLJITLookup(J, &EntryAddr, "entry"))) {
206 MainResult = handleError(Err);
207 goto cleanup;
211 // If we made it here then everything succeeded. Execute our JIT'd code.
212 int32_t (*Entry)(int32_t) = (int32_t(*)(int32_t))EntryAddr;
213 int32_t Result = Entry(argc);
215 printf("--- Result ---\n");
216 printf("entry(%i) = %i\n", argc, Result);
218 cleanup : {
219 LLVMOrcDisposeIndirectStubsManager(ISM);
220 LLVMOrcDisposeLazyCallThroughManager(LCTM);
223 jit_cleanup:
224 // Destroy our JIT instance. This will clean up any memory that the JIT has
225 // taken ownership of. This operation is non-trivial (e.g. it may need to
226 // JIT static destructors) and may also fail. In that case we want to render
227 // the error to stderr, but not overwrite any existing return value.
229 LLVMErrorRef Err;
230 if ((Err = LLVMOrcDisposeLLJIT(J))) {
231 int NewFailureResult = handleError(Err);
232 if (MainResult == 0)
233 MainResult = NewFailureResult;
237 llvm_shutdown:
238 // Shut down LLVM.
239 LLVMShutdown();
241 return MainResult;