[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / examples / OrcV2Examples / OrcV2CBindingsLazy / OrcV2CBindingsLazy.c
blob0f4f979127e853f2e958d0b838e502fab0475016
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/Initialization.h"
13 #include "llvm-c/LLJIT.h"
14 #include "llvm-c/Support.h"
15 #include "llvm-c/Target.h"
17 #include <stdio.h>
19 int handleError(LLVMErrorRef Err) {
20 char *ErrMsg = LLVMGetErrorMessage(Err);
21 fprintf(stderr, "Error: %s\n", ErrMsg);
22 LLVMDisposeErrorMessage(ErrMsg);
23 return 1;
26 // Example IR modules.
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.
35 const char FooMod[] = " define i32 @foo_body() { \n"
36 " entry: \n"
37 " ret i32 1 \n"
38 " } \n";
40 const char BarMod[] = " define i32 @bar_body() { \n"
41 " entry: \n"
42 " ret i32 2 \n"
43 " } \n";
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";
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();
74 // Get a reference to the underlying LLVMContext.
75 LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx);
77 // Wrap Source in a MemoryBuffer
78 LLVMMemoryBufferRef MB =
79 LLVMCreateMemoryBufferWithMemoryRange(Source, Len, Name, 0);
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);
89 // Our module is now complete. Wrap it and our ThreadSafeContext in a
90 // ThreadSafeModule.
91 *TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);
93 // Dispose of our local ThreadSafeContext value. The underlying LLVMContext
94 // will be kept alive by our ThreadSafeModule, TSM.
95 LLVMOrcDisposeThreadSafeContext(TSCtx);
97 return LLVMErrorSuccess;
100 int main(int argc, char *argv[]) {
102 int MainResult = 0;
104 // Parse command line arguments and initialize LLVM Core.
105 LLVMParseCommandLineOptions(argc, (const char **)argv, "");
106 LLVMInitializeCore(LLVMGetGlobalPassRegistry());
108 // Initialize native target codegen and asm printer.
109 LLVMInitializeNativeTarget();
110 LLVMInitializeNativeAsmPrinter();
112 // Set up a JIT instance.
113 LLVMOrcLLJITRef J;
114 const char *TargetTriple;
116 LLVMErrorRef Err;
117 if ((Err = LLVMOrcCreateLLJIT(&J, 0))) {
118 MainResult = handleError(Err);
119 goto llvm_shutdown;
121 TargetTriple = LLVMOrcLLJITGetTripleString(J);
124 // Add our demo modules to the JIT.
126 LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
127 LLVMErrorRef Err;
129 LLVMOrcThreadSafeModuleRef FooTSM;
130 if ((Err =
131 parseExampleModule(FooMod, sizeof(FooMod), "foo-mod", &FooTSM))) {
132 MainResult = handleError(Err);
133 goto jit_cleanup;
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;
144 LLVMOrcThreadSafeModuleRef BarTSM;
145 if ((Err =
146 parseExampleModule(BarMod, sizeof(BarMod), "bar-mod", &BarTSM))) {
147 MainResult = handleError(Err);
148 goto jit_cleanup;
151 if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, BarTSM))) {
152 LLVMOrcDisposeThreadSafeModule(BarTSM);
153 MainResult = handleError(Err);
154 goto jit_cleanup;
157 LLVMOrcThreadSafeModuleRef MainTSM;
158 if ((Err = parseExampleModule(MainMod, sizeof(MainMod), "main-mod",
159 &MainTSM))) {
160 MainResult = handleError(Err);
161 goto jit_cleanup;
164 if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, MainTSM))) {
165 LLVMOrcDisposeThreadSafeModule(MainTSM);
166 MainResult = handleError(Err);
167 goto jit_cleanup;
171 // add lazy reexports
172 LLVMOrcIndirectStubsManagerRef ISM =
173 LLVMOrcCreateLocalIndirectStubsManager(TargetTriple);
175 LLVMOrcLazyCallThroughManagerRef LCTM;
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;
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}},
197 LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
198 LLVMOrcMaterializationUnitRef MU =
199 LLVMOrcLazyReexports(LCTM, ISM, MainJD, ReExports, 2);
200 LLVMOrcJITDylibDefine(MainJD, MU);
203 // Look up the address of our demo entry point.
204 LLVMOrcJITTargetAddress EntryAddr;
206 LLVMErrorRef Err;
207 if ((Err = LLVMOrcLLJITLookup(J, &EntryAddr, "entry"))) {
208 MainResult = handleError(Err);
209 goto cleanup;
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);
217 printf("--- Result ---\n");
218 printf("entry(%i) = %i\n", argc, Result);
220 cleanup : {
221 LLVMOrcDisposeIndirectStubsManager(ISM);
222 LLVMOrcDisposeLazyCallThroughManager(LCTM);
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.
231 LLVMErrorRef Err;
232 if ((Err = LLVMOrcDisposeLLJIT(J))) {
233 int NewFailureResult = handleError(Err);
234 if (MainResult == 0)
235 MainResult = NewFailureResult;
239 llvm_shutdown:
240 // Shut down LLVM.
241 LLVMShutdown();
243 return MainResult;