1 | //===- OrcV2CBindingsDumpObjects.c - Dump JIT'd objects to disk via C API -===// |
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 | // To run the demo build 'OrcV2CBindingsDumpObjects', then run the built |
10 | // program. It will execute as for OrcV2CBindingsBasicUsage, but will write |
11 | // a single JIT'd object out to the working directory. |
12 | // |
13 | // Try experimenting with the DumpDir and IdentifierOverride arguments to |
14 | // LLVMOrcCreateDumpObjects. |
15 | // |
16 | //===----------------------------------------------------------------------===// |
17 | |
18 | #include "llvm-c/Core.h" |
19 | #include "llvm-c/Error.h" |
20 | #include "llvm-c/LLJIT.h" |
21 | #include "llvm-c/Support.h" |
22 | #include "llvm-c/Target.h" |
23 | #include "llvm-c/Transforms/PassBuilder.h" |
24 | |
25 | #include <stdio.h> |
26 | |
27 | int handleError(LLVMErrorRef Err) { |
28 | char *ErrMsg = LLVMGetErrorMessage(Err); |
29 | fprintf(stderr, format: "Error: %s\n" , ErrMsg); |
30 | LLVMDisposeErrorMessage(ErrMsg); |
31 | return 1; |
32 | } |
33 | |
34 | LLVMOrcThreadSafeModuleRef createDemoModule(void) { |
35 | LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext(); |
36 | LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx); |
37 | LLVMModuleRef M = LLVMModuleCreateWithNameInContext(ModuleID: "demo" , C: Ctx); |
38 | LLVMTypeRef ParamTypes[] = {LLVMInt32Type(), LLVMInt32Type()}; |
39 | LLVMTypeRef SumFunctionType = |
40 | LLVMFunctionType(ReturnType: LLVMInt32Type(), ParamTypes, ParamCount: 2, IsVarArg: 0); |
41 | LLVMValueRef SumFunction = LLVMAddFunction(M, Name: "sum" , FunctionTy: SumFunctionType); |
42 | LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(Fn: SumFunction, Name: "entry" ); |
43 | LLVMBuilderRef Builder = LLVMCreateBuilder(); |
44 | LLVMPositionBuilderAtEnd(Builder, Block: EntryBB); |
45 | LLVMValueRef SumArg0 = LLVMGetParam(Fn: SumFunction, Index: 0); |
46 | LLVMValueRef SumArg1 = LLVMGetParam(Fn: SumFunction, Index: 1); |
47 | LLVMValueRef Result = LLVMBuildAdd(Builder, LHS: SumArg0, RHS: SumArg1, Name: "result" ); |
48 | LLVMBuildRet(Builder, V: Result); |
49 | LLVMDisposeBuilder(Builder); |
50 | LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx); |
51 | LLVMOrcDisposeThreadSafeContext(TSCtx); |
52 | return TSM; |
53 | } |
54 | |
55 | LLVMErrorRef myModuleTransform(void *Ctx, LLVMModuleRef Mod) { |
56 | LLVMPassBuilderOptionsRef Options = LLVMCreatePassBuilderOptions(); |
57 | LLVMErrorRef E = LLVMRunPasses(M: Mod, Passes: "instcombine" , NULL, Options); |
58 | LLVMDisposePassBuilderOptions(Options); |
59 | return E; |
60 | } |
61 | |
62 | LLVMErrorRef transform(void *Ctx, LLVMOrcThreadSafeModuleRef *ModInOut, |
63 | LLVMOrcMaterializationResponsibilityRef MR) { |
64 | return LLVMOrcThreadSafeModuleWithModuleDo(TSM: *ModInOut, F: myModuleTransform, Ctx); |
65 | } |
66 | |
67 | int main(int argc, const char *argv[]) { |
68 | |
69 | int MainResult = 0; |
70 | |
71 | LLVMParseCommandLineOptions(argc, argv, Overview: "" ); |
72 | |
73 | LLVMInitializeNativeTarget(); |
74 | LLVMInitializeNativeAsmPrinter(); |
75 | |
76 | // Create a DumpObjects instance to use when dumping objects to disk. |
77 | LLVMOrcDumpObjectsRef DumpObjects = LLVMOrcCreateDumpObjects(DumpDir: "" , IdentifierOverride: "" ); |
78 | |
79 | // Create the JIT instance. |
80 | LLVMOrcLLJITRef J; |
81 | { |
82 | LLVMErrorRef Err; |
83 | if ((Err = LLVMOrcCreateLLJIT(Result: &J, Builder: 0))) { |
84 | MainResult = handleError(Err); |
85 | goto llvm_shutdown; |
86 | } |
87 | } |
88 | |
89 | // Use TransformLayer to set IR transform. |
90 | { |
91 | LLVMOrcIRTransformLayerRef TL = LLVMOrcLLJITGetIRTransformLayer(J); |
92 | LLVMOrcIRTransformLayerSetTransform(IRTransformLayer: TL, TransformFunction: *transform, NULL); |
93 | } |
94 | |
95 | // Create our demo module. |
96 | LLVMOrcThreadSafeModuleRef TSM = createDemoModule(); |
97 | |
98 | // Add our demo module to the JIT. |
99 | { |
100 | LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J); |
101 | LLVMErrorRef Err; |
102 | if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, JD: MainJD, 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 | LLVMOrcJITTargetAddress SumAddr; |
113 | { |
114 | LLVMErrorRef Err; |
115 | if ((Err = LLVMOrcLLJITLookup(J, Result: &SumAddr, Name: "sum" ))) { |
116 | MainResult = handleError(Err); |
117 | goto jit_cleanup; |
118 | } |
119 | } |
120 | |
121 | // If we made it here then everything succeeded. Execute our JIT'd code. |
122 | int32_t (*Sum)(int32_t, int32_t) = (int32_t(*)(int32_t, int32_t))SumAddr; |
123 | int32_t Result = Sum(1, 2); |
124 | |
125 | // Print the result. |
126 | printf(format: "1 + 2 = %i\n" , Result); |
127 | |
128 | jit_cleanup: |
129 | |
130 | // Destroy our JIT instance. |
131 | { |
132 | LLVMErrorRef Err; |
133 | if ((Err = LLVMOrcDisposeLLJIT(J))) { |
134 | int NewFailureResult = handleError(Err); |
135 | if (MainResult == 0) |
136 | MainResult = NewFailureResult; |
137 | } |
138 | } |
139 | |
140 | llvm_shutdown: |
141 | // Destroy our DumpObjects instance. |
142 | LLVMOrcDisposeDumpObjects(DumpObjects); |
143 | |
144 | // Shut down LLVM. |
145 | LLVMShutdown(); |
146 | |
147 | return MainResult; |
148 | } |
149 | |