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/LLJIT.h" |
12 | #include "llvm-c/Support.h" |
13 | #include "llvm-c/Target.h" |
14 | |
15 | #include <stdio.h> |
16 | |
17 | int handleError(LLVMErrorRef Err) { |
18 | char *ErrMsg = LLVMGetErrorMessage(Err); |
19 | fprintf(stderr, format: "Error: %s\n" , ErrMsg); |
20 | LLVMDisposeErrorMessage(ErrMsg); |
21 | return 1; |
22 | } |
23 | |
24 | LLVMOrcThreadSafeModuleRef createDemoModule(void) { |
25 | // Create a new ThreadSafeContext and underlying LLVMContext. |
26 | LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext(); |
27 | |
28 | // Get a reference to the underlying LLVMContext. |
29 | LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx); |
30 | |
31 | // Create a new LLVM module. |
32 | LLVMModuleRef M = LLVMModuleCreateWithNameInContext(ModuleID: "demo" , C: Ctx); |
33 | |
34 | // Add a "sum" function": |
35 | // - Create the function type and function instance. |
36 | LLVMTypeRef ParamTypes[] = {LLVMInt32Type(), LLVMInt32Type()}; |
37 | LLVMTypeRef SumFunctionType = |
38 | LLVMFunctionType(ReturnType: LLVMInt32Type(), ParamTypes, ParamCount: 2, IsVarArg: 0); |
39 | LLVMValueRef SumFunction = LLVMAddFunction(M, Name: "sum" , FunctionTy: SumFunctionType); |
40 | |
41 | // - Add a basic block to the function. |
42 | LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(Fn: SumFunction, Name: "entry" ); |
43 | |
44 | // - Add an IR builder and point it at the end of the basic block. |
45 | LLVMBuilderRef Builder = LLVMCreateBuilder(); |
46 | LLVMPositionBuilderAtEnd(Builder, Block: EntryBB); |
47 | |
48 | // - Get the two function arguments and use them co construct an "add" |
49 | // instruction. |
50 | LLVMValueRef SumArg0 = LLVMGetParam(Fn: SumFunction, Index: 0); |
51 | LLVMValueRef SumArg1 = LLVMGetParam(Fn: SumFunction, Index: 1); |
52 | LLVMValueRef Result = LLVMBuildAdd(Builder, LHS: SumArg0, RHS: SumArg1, Name: "result" ); |
53 | |
54 | // - Build the return instruction. |
55 | LLVMBuildRet(Builder, V: Result); |
56 | |
57 | // - Free the builder. |
58 | LLVMDisposeBuilder(Builder); |
59 | |
60 | // Our demo module is now complete. Wrap it and our ThreadSafeContext in a |
61 | // ThreadSafeModule. |
62 | LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx); |
63 | |
64 | // Dispose of our local ThreadSafeContext value. The underlying LLVMContext |
65 | // will be kept alive by our ThreadSafeModule, TSM. |
66 | LLVMOrcDisposeThreadSafeContext(TSCtx); |
67 | |
68 | // Return the result. |
69 | return TSM; |
70 | } |
71 | |
72 | int main(int argc, const char *argv[]) { |
73 | |
74 | int MainResult = 0; |
75 | |
76 | // Parse command line arguments and initialize LLVM Core. |
77 | LLVMParseCommandLineOptions(argc, argv, Overview: "" ); |
78 | |
79 | // Initialize native target codegen and asm printer. |
80 | LLVMInitializeNativeTarget(); |
81 | LLVMInitializeNativeAsmPrinter(); |
82 | |
83 | // Create the JIT instance. |
84 | LLVMOrcLLJITRef J; |
85 | { |
86 | LLVMErrorRef Err; |
87 | if ((Err = LLVMOrcCreateLLJIT(Result: &J, Builder: 0))) { |
88 | MainResult = handleError(Err); |
89 | goto llvm_shutdown; |
90 | } |
91 | } |
92 | |
93 | // Create our demo module. |
94 | LLVMOrcThreadSafeModuleRef TSM = createDemoModule(); |
95 | LLVMOrcResourceTrackerRef RT; |
96 | |
97 | // Add our demo module to the JIT. |
98 | { |
99 | LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J); |
100 | RT = LLVMOrcJITDylibCreateResourceTracker(JD: MainJD); |
101 | LLVMErrorRef Err; |
102 | if ((Err = LLVMOrcLLJITAddLLVMIRModuleWithRT(J, JD: RT, TSM))) { |
103 | // If adding the ThreadSafeModule fails then we need to clean it up |
104 | // ourselves. If adding it succeeds the JIT will manage the memory. |
105 | LLVMOrcDisposeThreadSafeModule(TSM); |
106 | MainResult = handleError(Err); |
107 | goto jit_cleanup; |
108 | } |
109 | } |
110 | |
111 | // Look up the address of our demo entry point. |
112 | printf(format: "Looking up before removal...\n" ); |
113 | LLVMOrcJITTargetAddress SumAddr; |
114 | { |
115 | LLVMErrorRef Err; |
116 | if ((Err = LLVMOrcLLJITLookup(J, Result: &SumAddr, Name: "sum" ))) { |
117 | MainResult = handleError(Err); |
118 | goto jit_cleanup; |
119 | } |
120 | } |
121 | |
122 | // If we made it here then everything succeeded. Execute our JIT'd code. |
123 | int32_t (*Sum)(int32_t, int32_t) = (int32_t(*)(int32_t, int32_t))SumAddr; |
124 | int32_t Result = Sum(1, 2); |
125 | |
126 | // Print the result. |
127 | printf(format: "1 + 2 = %i\n" , Result); |
128 | |
129 | // Remove the code. |
130 | { |
131 | LLVMErrorRef Err; |
132 | if ((Err = LLVMOrcResourceTrackerRemove(RT))) { |
133 | MainResult = handleError(Err); |
134 | goto jit_cleanup; |
135 | } |
136 | } |
137 | |
138 | // Attempt a second lookup. Here we expect an error as the code and symbols |
139 | // should have been removed. |
140 | printf(format: "Attempting to remove code / symbols...\n" ); |
141 | { |
142 | LLVMOrcJITTargetAddress ThrowAwayAddress; |
143 | LLVMErrorRef Err = LLVMOrcLLJITLookup(J, Result: &ThrowAwayAddress, Name: "sum" ); |
144 | if (Err) { |
145 | printf(format: "Received error as expected:\n" ); |
146 | handleError(Err); |
147 | } else { |
148 | printf(format: "Failure: Second lookup should have generated an error.\n" ); |
149 | MainResult = 1; |
150 | } |
151 | } |
152 | |
153 | jit_cleanup: |
154 | // Destroy our JIT instance. This will clean up any memory that the JIT has |
155 | // taken ownership of. This operation is non-trivial (e.g. it may need to |
156 | // JIT static destructors) and may also fail. In that case we want to render |
157 | // the error to stderr, but not overwrite any existing return value. |
158 | |
159 | printf(format: "Releasing resource tracker...\n" ); |
160 | LLVMOrcReleaseResourceTracker(RT); |
161 | |
162 | printf(format: "Destroying LLJIT instance and exiting.\n" ); |
163 | { |
164 | LLVMErrorRef Err; |
165 | if ((Err = LLVMOrcDisposeLLJIT(J))) { |
166 | int NewFailureResult = handleError(Err); |
167 | if (MainResult == 0) |
168 | MainResult = NewFailureResult; |
169 | } |
170 | } |
171 | |
172 | llvm_shutdown: |
173 | // Shut down LLVM. |
174 | LLVMShutdown(); |
175 | |
176 | return MainResult; |
177 | } |
178 | |