245 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/IRReader.h"12#include "llvm-c/LLJIT.h"13#include "llvm-c/Support.h"14#include "llvm-c/Target.h"15 16#include <stdio.h>17 18int handleError(LLVMErrorRef Err) {19 char *ErrMsg = LLVMGetErrorMessage(Err);20 fprintf(stderr, "Error: %s\n", ErrMsg);21 LLVMDisposeErrorMessage(ErrMsg);22 return 1;23}24 25// Example IR modules.26//27// Note that in the conditionally compiled modules, FooMod and BarMod, functions28// have been given an _body suffix. This is to ensure that their names do not29// clash with their lazy-reexports.30// For clients who do not wish to rename function bodies (e.g. because they want31// to re-use cached objects between static and JIT compiles) techniques exist to32// avoid renaming. See the lazy-reexports section of the ORCv2 design doc.33 34const char FooMod[] = " define i32 @foo_body() { \n"35 " entry: \n"36 " ret i32 1 \n"37 " } \n";38 39const char BarMod[] = " define i32 @bar_body() { \n"40 " entry: \n"41 " ret i32 2 \n"42 " } \n";43 44const char MainMod[] =45 " define i32 @entry(i32 %argc) { \n"46 " entry: \n"47 " %and = and i32 %argc, 1 \n"48 " %tobool = icmp eq i32 %and, 0 \n"49 " br i1 %tobool, label %if.end, label %if.then \n"50 " \n"51 " if.then: \n"52 " %call = tail call i32 @foo() \n"53 " br label %return \n"54 " \n"55 " if.end: \n"56 " %call1 = tail call i32 @bar() \n"57 " br label %return \n"58 " \n"59 " return: \n"60 " %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.end ] \n"61 " ret i32 %retval.0 \n"62 " } \n"63 " \n"64 " declare i32 @foo() \n"65 " declare i32 @bar() \n";66 67LLVMErrorRef parseExampleModule(const char *Source, size_t Len,68 const char *Name,69 LLVMOrcThreadSafeModuleRef *TSM) {70 71 // Create an LLVMContext for the Module.72 LLVMContextRef Ctx = LLVMContextCreate();73 74 // Wrap Source in a MemoryBuffer75 LLVMMemoryBufferRef MB =76 LLVMCreateMemoryBufferWithMemoryRange(Source, Len, Name, 0);77 78 // Parse the LLVM module.79 LLVMModuleRef M;80 char *ErrMsg;81 if (LLVMParseIRInContext(Ctx, MB, &M, &ErrMsg)) {82 return LLVMCreateStringError(ErrMsg);83 // TODO: LLVMDisposeMessage(ErrMsg);84 }85 86 // Create a new ThreadSafeContext to hold the context.87 LLVMOrcThreadSafeContextRef TSCtx =88 LLVMOrcCreateNewThreadSafeContextFromLLVMContext(Ctx);89 90 // Our module is now complete. Wrap it and our ThreadSafeContext in a91 // ThreadSafeModule.92 *TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);93 94 // Dispose of our local ThreadSafeContext value. The underlying LLVMContext95 // will be kept alive by our ThreadSafeModule, TSM.96 LLVMOrcDisposeThreadSafeContext(TSCtx);97 98 return LLVMErrorSuccess;99}100 101int main(int argc, const char *argv[]) {102 103 int MainResult = 0;104 105 // Parse command line arguments and initialize LLVM Core.106 LLVMParseCommandLineOptions(argc, argv, "");107 108 // Initialize native target codegen and asm printer.109 LLVMInitializeNativeTarget();110 LLVMInitializeNativeAsmPrinter();111 112 // Set up a JIT instance.113 LLVMOrcLLJITRef J;114 const char *TargetTriple;115 {116 LLVMErrorRef Err;117 if ((Err = LLVMOrcCreateLLJIT(&J, 0))) {118 MainResult = handleError(Err);119 goto llvm_shutdown;120 }121 TargetTriple = LLVMOrcLLJITGetTripleString(J);122 }123 124 // Add our demo modules to the JIT.125 {126 LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);127 LLVMErrorRef Err;128 129 LLVMOrcThreadSafeModuleRef FooTSM;130 if ((Err = parseExampleModule(FooMod, sizeof(FooMod) - 1, "foo-mod",131 &FooTSM))) {132 MainResult = handleError(Err);133 goto jit_cleanup;134 }135 136 if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, FooTSM))) {137 // If adding the ThreadSafeModule fails then we need to clean it up138 // ourselves. If adding it succeeds the JIT will manage the memory.139 LLVMOrcDisposeThreadSafeModule(FooTSM);140 MainResult = handleError(Err);141 goto jit_cleanup;142 }143 144 LLVMOrcThreadSafeModuleRef BarTSM;145 if ((Err = parseExampleModule(BarMod, sizeof(BarMod) - 1, "bar-mod",146 &BarTSM))) {147 MainResult = handleError(Err);148 goto jit_cleanup;149 }150 151 if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, BarTSM))) {152 LLVMOrcDisposeThreadSafeModule(BarTSM);153 MainResult = handleError(Err);154 goto jit_cleanup;155 }156 157 LLVMOrcThreadSafeModuleRef MainTSM;158 if ((Err = parseExampleModule(MainMod, sizeof(MainMod) - 1, "main-mod",159 &MainTSM))) {160 MainResult = handleError(Err);161 goto jit_cleanup;162 }163 164 if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, MainTSM))) {165 LLVMOrcDisposeThreadSafeModule(MainTSM);166 MainResult = handleError(Err);167 goto jit_cleanup;168 }169 }170 171 // add lazy reexports172 LLVMOrcIndirectStubsManagerRef ISM =173 LLVMOrcCreateLocalIndirectStubsManager(TargetTriple);174 175 LLVMOrcLazyCallThroughManagerRef LCTM;176 {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;184 }185 }186 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}},194 };195 196 {197 LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);198 LLVMOrcMaterializationUnitRef MU =199 LLVMOrcLazyReexports(LCTM, ISM, MainJD, ReExports, 2);200 LLVMOrcJITDylibDefine(MainJD, MU);201 }202 203 // Look up the address of our demo entry point.204 LLVMOrcJITTargetAddress EntryAddr;205 {206 LLVMErrorRef Err;207 if ((Err = LLVMOrcLLJITLookup(J, &EntryAddr, "entry"))) {208 MainResult = handleError(Err);209 goto cleanup;210 }211 }212 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);216 217 printf("--- Result ---\n");218 printf("entry(%i) = %i\n", argc, Result);219 220cleanup : {221 LLVMOrcDisposeIndirectStubsManager(ISM);222 LLVMOrcDisposeLazyCallThroughManager(LCTM);223}224 225jit_cleanup:226 // Destroy our JIT instance. This will clean up any memory that the JIT has227 // taken ownership of. This operation is non-trivial (e.g. it may need to228 // JIT static destructors) and may also fail. In that case we want to render229 // the error to stderr, but not overwrite any existing return value.230 {231 LLVMErrorRef Err;232 if ((Err = LLVMOrcDisposeLLJIT(J))) {233 int NewFailureResult = handleError(Err);234 if (MainResult == 0)235 MainResult = NewFailureResult;236 }237 }238 239llvm_shutdown:240 // Shut down LLVM.241 LLVMShutdown();242 243 return MainResult;244}245