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