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 | |
24 | #include <stdio.h> |
25 | |
26 | int handleError(LLVMErrorRef Err) { |
27 | char *ErrMsg = LLVMGetErrorMessage(Err); |
28 | fprintf(stderr, format: "Error: %s\n" , ErrMsg); |
29 | LLVMDisposeErrorMessage(ErrMsg); |
30 | return 1; |
31 | } |
32 | |
33 | LLVMOrcThreadSafeModuleRef createDemoModule(void) { |
34 | LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext(); |
35 | LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx); |
36 | LLVMModuleRef M = LLVMModuleCreateWithNameInContext(ModuleID: "demo" , C: Ctx); |
37 | LLVMTypeRef ParamTypes[] = {LLVMInt32Type(), LLVMInt32Type()}; |
38 | LLVMTypeRef SumFunctionType = |
39 | LLVMFunctionType(ReturnType: LLVMInt32Type(), ParamTypes, ParamCount: 2, IsVarArg: 0); |
40 | LLVMValueRef SumFunction = LLVMAddFunction(M, Name: "sum" , FunctionTy: SumFunctionType); |
41 | LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(Fn: SumFunction, Name: "entry" ); |
42 | LLVMBuilderRef Builder = LLVMCreateBuilder(); |
43 | LLVMPositionBuilderAtEnd(Builder, Block: EntryBB); |
44 | LLVMValueRef SumArg0 = LLVMGetParam(Fn: SumFunction, Index: 0); |
45 | LLVMValueRef SumArg1 = LLVMGetParam(Fn: SumFunction, Index: 1); |
46 | LLVMValueRef Result = LLVMBuildAdd(Builder, LHS: SumArg0, RHS: SumArg1, Name: "result" ); |
47 | LLVMBuildRet(Builder, V: Result); |
48 | LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx); |
49 | LLVMOrcDisposeThreadSafeContext(TSCtx); |
50 | return TSM; |
51 | } |
52 | |
53 | LLVMErrorRef dumpObjectsTransform(void *Ctx, LLVMMemoryBufferRef *ObjInOut) { |
54 | LLVMOrcDumpObjectsRef DumpObjects = *(LLVMOrcDumpObjectsRef *)Ctx; |
55 | return LLVMOrcDumpObjects_CallOperator(DumpObjects, ObjBuffer: ObjInOut); |
56 | } |
57 | |
58 | int main(int argc, const char *argv[]) { |
59 | |
60 | int MainResult = 0; |
61 | |
62 | LLVMParseCommandLineOptions(argc, argv, Overview: "" ); |
63 | |
64 | LLVMInitializeNativeTarget(); |
65 | LLVMInitializeNativeAsmPrinter(); |
66 | |
67 | // Create a DumpObjects instance to use when dumping objects to disk. |
68 | LLVMOrcDumpObjectsRef DumpObjects = LLVMOrcCreateDumpObjects(DumpDir: "" , IdentifierOverride: "" ); |
69 | |
70 | // Create the JIT instance. |
71 | LLVMOrcLLJITRef J; |
72 | { |
73 | LLVMErrorRef Err; |
74 | if ((Err = LLVMOrcCreateLLJIT(Result: &J, Builder: 0))) { |
75 | MainResult = handleError(Err); |
76 | goto llvm_shutdown; |
77 | } |
78 | } |
79 | |
80 | // Set an object transform to call our DumpObjects instance for every |
81 | // JIT'd object. |
82 | LLVMOrcObjectTransformLayerSetTransform(ObjTransformLayer: LLVMOrcLLJITGetObjTransformLayer(J), |
83 | TransformFunction: dumpObjectsTransform, Ctx: &DumpObjects); |
84 | |
85 | // Create our demo module. |
86 | LLVMOrcThreadSafeModuleRef TSM = createDemoModule(); |
87 | |
88 | // Add our demo module to the JIT. |
89 | { |
90 | LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J); |
91 | LLVMErrorRef Err; |
92 | if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, JD: MainJD, TSM))) { |
93 | // If adding the ThreadSafeModule fails then we need to clean it up |
94 | // ourselves. If adding it succeeds the JIT will manage the memory. |
95 | LLVMOrcDisposeThreadSafeModule(TSM); |
96 | MainResult = handleError(Err); |
97 | goto jit_cleanup; |
98 | } |
99 | } |
100 | |
101 | // Look up the address of our demo entry point. |
102 | LLVMOrcJITTargetAddress SumAddr; |
103 | { |
104 | LLVMErrorRef Err; |
105 | if ((Err = LLVMOrcLLJITLookup(J, Result: &SumAddr, Name: "sum" ))) { |
106 | MainResult = handleError(Err); |
107 | goto jit_cleanup; |
108 | } |
109 | } |
110 | |
111 | // If we made it here then everything succeeded. Execute our JIT'd code. |
112 | int32_t (*Sum)(int32_t, int32_t) = (int32_t(*)(int32_t, int32_t))SumAddr; |
113 | int32_t Result = Sum(1, 2); |
114 | |
115 | // Print the result. |
116 | printf(format: "1 + 2 = %i\n" , Result); |
117 | |
118 | jit_cleanup: |
119 | |
120 | // Destroy our JIT instance. |
121 | { |
122 | LLVMErrorRef Err; |
123 | if ((Err = LLVMOrcDisposeLLJIT(J))) { |
124 | int NewFailureResult = handleError(Err); |
125 | if (MainResult == 0) |
126 | MainResult = NewFailureResult; |
127 | } |
128 | } |
129 | |
130 | llvm_shutdown: |
131 | // Destroy our DumpObjects instance. |
132 | LLVMOrcDisposeDumpObjects(DumpObjects); |
133 | |
134 | // Shut down LLVM. |
135 | LLVMShutdown(); |
136 | |
137 | return MainResult; |
138 | } |
139 | |