| //===-- ExecutionEngineBindings.cpp - C bindings for EEs ------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the C bindings for the ExecutionEngine library. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm-c/ExecutionEngine.h" |
| #include "llvm/ExecutionEngine/ExecutionEngine.h" |
| #include "llvm/ExecutionEngine/GenericValue.h" |
| #include "llvm/ExecutionEngine/JITEventListener.h" |
| #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" |
| #include "llvm/IR/DerivedTypes.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Target/CodeGenCWrappers.h" |
| #include "llvm/Target/TargetOptions.h" |
| #include <cstring> |
| #include <optional> |
| |
| using namespace llvm; |
| |
| #define DEBUG_TYPE "jit" |
| |
| // Wrapping the C bindings types. |
| DEFINE_SIMPLE_CONVERSION_FUNCTIONS(GenericValue, LLVMGenericValueRef) |
| |
| |
| static LLVMTargetMachineRef wrap(const TargetMachine *P) { |
| return |
| reinterpret_cast<LLVMTargetMachineRef>(const_cast<TargetMachine*>(P)); |
| } |
| |
| /*===-- Operations on generic values --------------------------------------===*/ |
| |
| LLVMGenericValueRef LLVMCreateGenericValueOfInt(LLVMTypeRef Ty, |
| unsigned long long N, |
| LLVMBool IsSigned) { |
| GenericValue *GenVal = new GenericValue(); |
| GenVal->IntVal = APInt(unwrap<IntegerType>(Ty)->getBitWidth(), N, IsSigned); |
| return wrap(GenVal); |
| } |
| |
| LLVMGenericValueRef LLVMCreateGenericValueOfPointer(void *P) { |
| GenericValue *GenVal = new GenericValue(); |
| GenVal->PointerVal = P; |
| return wrap(GenVal); |
| } |
| |
| LLVMGenericValueRef LLVMCreateGenericValueOfFloat(LLVMTypeRef TyRef, double N) { |
| GenericValue *GenVal = new GenericValue(); |
| switch (unwrap(TyRef)->getTypeID()) { |
| case Type::FloatTyID: |
| GenVal->FloatVal = N; |
| break; |
| case Type::DoubleTyID: |
| GenVal->DoubleVal = N; |
| break; |
| default: |
| llvm_unreachable("LLVMGenericValueToFloat supports only float and double."); |
| } |
| return wrap(GenVal); |
| } |
| |
| unsigned LLVMGenericValueIntWidth(LLVMGenericValueRef GenValRef) { |
| return unwrap(GenValRef)->IntVal.getBitWidth(); |
| } |
| |
| unsigned long long LLVMGenericValueToInt(LLVMGenericValueRef GenValRef, |
| LLVMBool IsSigned) { |
| GenericValue *GenVal = unwrap(GenValRef); |
| if (IsSigned) |
| return GenVal->IntVal.getSExtValue(); |
| else |
| return GenVal->IntVal.getZExtValue(); |
| } |
| |
| void *LLVMGenericValueToPointer(LLVMGenericValueRef GenVal) { |
| return unwrap(GenVal)->PointerVal; |
| } |
| |
| double LLVMGenericValueToFloat(LLVMTypeRef TyRef, LLVMGenericValueRef GenVal) { |
| switch (unwrap(TyRef)->getTypeID()) { |
| case Type::FloatTyID: |
| return unwrap(GenVal)->FloatVal; |
| case Type::DoubleTyID: |
| return unwrap(GenVal)->DoubleVal; |
| default: |
| llvm_unreachable("LLVMGenericValueToFloat supports only float and double."); |
| } |
| } |
| |
| void LLVMDisposeGenericValue(LLVMGenericValueRef GenVal) { |
| delete unwrap(GenVal); |
| } |
| |
| /*===-- Operations on execution engines -----------------------------------===*/ |
| |
| LLVMBool LLVMCreateExecutionEngineForModule(LLVMExecutionEngineRef *OutEE, |
| LLVMModuleRef M, |
| char **OutError) { |
| std::string Error; |
| EngineBuilder builder(std::unique_ptr<Module>(unwrap(M))); |
| builder.setEngineKind(EngineKind::Either) |
| .setErrorStr(&Error); |
| if (ExecutionEngine *EE = builder.create()){ |
| *OutEE = wrap(EE); |
| return 0; |
| } |
| *OutError = strdup(Error.c_str()); |
| return 1; |
| } |
| |
| LLVMBool LLVMCreateInterpreterForModule(LLVMExecutionEngineRef *OutInterp, |
| LLVMModuleRef M, |
| char **OutError) { |
| std::string Error; |
| EngineBuilder builder(std::unique_ptr<Module>(unwrap(M))); |
| builder.setEngineKind(EngineKind::Interpreter) |
| .setErrorStr(&Error); |
| if (ExecutionEngine *Interp = builder.create()) { |
| *OutInterp = wrap(Interp); |
| return 0; |
| } |
| *OutError = strdup(Error.c_str()); |
| return 1; |
| } |
| |
| LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, |
| LLVMModuleRef M, |
| unsigned OptLevel, |
| char **OutError) { |
| std::string Error; |
| EngineBuilder builder(std::unique_ptr<Module>(unwrap(M))); |
| builder.setEngineKind(EngineKind::JIT) |
| .setErrorStr(&Error) |
| .setOptLevel((CodeGenOpt::Level)OptLevel); |
| if (ExecutionEngine *JIT = builder.create()) { |
| *OutJIT = wrap(JIT); |
| return 0; |
| } |
| *OutError = strdup(Error.c_str()); |
| return 1; |
| } |
| |
| void LLVMInitializeMCJITCompilerOptions(LLVMMCJITCompilerOptions *PassedOptions, |
| size_t SizeOfPassedOptions) { |
| LLVMMCJITCompilerOptions options; |
| memset(&options, 0, sizeof(options)); // Most fields are zero by default. |
| options.CodeModel = LLVMCodeModelJITDefault; |
| |
| memcpy(PassedOptions, &options, |
| std::min(sizeof(options), SizeOfPassedOptions)); |
| } |
| |
| LLVMBool LLVMCreateMCJITCompilerForModule( |
| LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M, |
| LLVMMCJITCompilerOptions *PassedOptions, size_t SizeOfPassedOptions, |
| char **OutError) { |
| LLVMMCJITCompilerOptions options; |
| // If the user passed a larger sized options struct, then they were compiled |
| // against a newer LLVM. Tell them that something is wrong. |
| if (SizeOfPassedOptions > sizeof(options)) { |
| *OutError = strdup( |
| "Refusing to use options struct that is larger than my own; assuming " |
| "LLVM library mismatch."); |
| return 1; |
| } |
| |
| // Defend against the user having an old version of the API by ensuring that |
| // any fields they didn't see are cleared. We must defend against fields being |
| // set to the bitwise equivalent of zero, and assume that this means "do the |
| // default" as if that option hadn't been available. |
| LLVMInitializeMCJITCompilerOptions(&options, sizeof(options)); |
| memcpy(&options, PassedOptions, SizeOfPassedOptions); |
| |
| TargetOptions targetOptions; |
| targetOptions.EnableFastISel = options.EnableFastISel; |
| std::unique_ptr<Module> Mod(unwrap(M)); |
| |
| if (Mod) |
| // Set function attribute "frame-pointer" based on |
| // NoFramePointerElim. |
| for (auto &F : *Mod) { |
| auto Attrs = F.getAttributes(); |
| StringRef Value = options.NoFramePointerElim ? "all" : "none"; |
| Attrs = Attrs.addFnAttribute(F.getContext(), "frame-pointer", Value); |
| F.setAttributes(Attrs); |
| } |
| |
| std::string Error; |
| EngineBuilder builder(std::move(Mod)); |
| builder.setEngineKind(EngineKind::JIT) |
| .setErrorStr(&Error) |
| .setOptLevel((CodeGenOpt::Level)options.OptLevel) |
| .setTargetOptions(targetOptions); |
| bool JIT; |
| if (std::optional<CodeModel::Model> CM = unwrap(options.CodeModel, JIT)) |
| builder.setCodeModel(*CM); |
| if (options.MCJMM) |
| builder.setMCJITMemoryManager( |
| std::unique_ptr<RTDyldMemoryManager>(unwrap(options.MCJMM))); |
| if (ExecutionEngine *JIT = builder.create()) { |
| *OutJIT = wrap(JIT); |
| return 0; |
| } |
| *OutError = strdup(Error.c_str()); |
| return 1; |
| } |
| |
| void LLVMDisposeExecutionEngine(LLVMExecutionEngineRef EE) { |
| delete unwrap(EE); |
| } |
| |
| void LLVMRunStaticConstructors(LLVMExecutionEngineRef EE) { |
| unwrap(EE)->finalizeObject(); |
| unwrap(EE)->runStaticConstructorsDestructors(false); |
| } |
| |
| void LLVMRunStaticDestructors(LLVMExecutionEngineRef EE) { |
| unwrap(EE)->finalizeObject(); |
| unwrap(EE)->runStaticConstructorsDestructors(true); |
| } |
| |
| int LLVMRunFunctionAsMain(LLVMExecutionEngineRef EE, LLVMValueRef F, |
| unsigned ArgC, const char * const *ArgV, |
| const char * const *EnvP) { |
| unwrap(EE)->finalizeObject(); |
| |
| std::vector<std::string> ArgVec(ArgV, ArgV + ArgC); |
| return unwrap(EE)->runFunctionAsMain(unwrap<Function>(F), ArgVec, EnvP); |
| } |
| |
| LLVMGenericValueRef LLVMRunFunction(LLVMExecutionEngineRef EE, LLVMValueRef F, |
| unsigned NumArgs, |
| LLVMGenericValueRef *Args) { |
| unwrap(EE)->finalizeObject(); |
| |
| std::vector<GenericValue> ArgVec; |
| ArgVec.reserve(NumArgs); |
| for (unsigned I = 0; I != NumArgs; ++I) |
| ArgVec.push_back(*unwrap(Args[I])); |
| |
| GenericValue *Result = new GenericValue(); |
| *Result = unwrap(EE)->runFunction(unwrap<Function>(F), ArgVec); |
| return wrap(Result); |
| } |
| |
| void LLVMFreeMachineCodeForFunction(LLVMExecutionEngineRef EE, LLVMValueRef F) { |
| } |
| |
| void LLVMAddModule(LLVMExecutionEngineRef EE, LLVMModuleRef M){ |
| unwrap(EE)->addModule(std::unique_ptr<Module>(unwrap(M))); |
| } |
| |
| LLVMBool LLVMRemoveModule(LLVMExecutionEngineRef EE, LLVMModuleRef M, |
| LLVMModuleRef *OutMod, char **OutError) { |
| Module *Mod = unwrap(M); |
| unwrap(EE)->removeModule(Mod); |
| *OutMod = wrap(Mod); |
| return 0; |
| } |
| |
| LLVMBool LLVMFindFunction(LLVMExecutionEngineRef EE, const char *Name, |
| LLVMValueRef *OutFn) { |
| if (Function *F = unwrap(EE)->FindFunctionNamed(Name)) { |
| *OutFn = wrap(F); |
| return 0; |
| } |
| return 1; |
| } |
| |
| void *LLVMRecompileAndRelinkFunction(LLVMExecutionEngineRef EE, |
| LLVMValueRef Fn) { |
| return nullptr; |
| } |
| |
| LLVMTargetDataRef LLVMGetExecutionEngineTargetData(LLVMExecutionEngineRef EE) { |
| return wrap(&unwrap(EE)->getDataLayout()); |
| } |
| |
| LLVMTargetMachineRef |
| LLVMGetExecutionEngineTargetMachine(LLVMExecutionEngineRef EE) { |
| return wrap(unwrap(EE)->getTargetMachine()); |
| } |
| |
| void LLVMAddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global, |
| void* Addr) { |
| unwrap(EE)->addGlobalMapping(unwrap<GlobalValue>(Global), Addr); |
| } |
| |
| void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global) { |
| unwrap(EE)->finalizeObject(); |
| |
| return unwrap(EE)->getPointerToGlobal(unwrap<GlobalValue>(Global)); |
| } |
| |
| uint64_t LLVMGetGlobalValueAddress(LLVMExecutionEngineRef EE, const char *Name) { |
| return unwrap(EE)->getGlobalValueAddress(Name); |
| } |
| |
| uint64_t LLVMGetFunctionAddress(LLVMExecutionEngineRef EE, const char *Name) { |
| return unwrap(EE)->getFunctionAddress(Name); |
| } |
| |
| LLVMBool LLVMExecutionEngineGetErrMsg(LLVMExecutionEngineRef EE, |
| char **OutError) { |
| assert(OutError && "OutError must be non-null"); |
| auto *ExecEngine = unwrap(EE); |
| if (ExecEngine->hasError()) { |
| *OutError = strdup(ExecEngine->getErrorMessage().c_str()); |
| ExecEngine->clearErrorMessage(); |
| return true; |
| } |
| return false; |
| } |
| |
| /*===-- Operations on memory managers -------------------------------------===*/ |
| |
| namespace { |
| |
| struct SimpleBindingMMFunctions { |
| LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection; |
| LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection; |
| LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory; |
| LLVMMemoryManagerDestroyCallback Destroy; |
| }; |
| |
| class SimpleBindingMemoryManager : public RTDyldMemoryManager { |
| public: |
| SimpleBindingMemoryManager(const SimpleBindingMMFunctions& Functions, |
| void *Opaque); |
| ~SimpleBindingMemoryManager() override; |
| |
| uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, |
| unsigned SectionID, |
| StringRef SectionName) override; |
| |
| uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, |
| unsigned SectionID, StringRef SectionName, |
| bool isReadOnly) override; |
| |
| bool finalizeMemory(std::string *ErrMsg) override; |
| |
| private: |
| SimpleBindingMMFunctions Functions; |
| void *Opaque; |
| }; |
| |
| SimpleBindingMemoryManager::SimpleBindingMemoryManager( |
| const SimpleBindingMMFunctions& Functions, |
| void *Opaque) |
| : Functions(Functions), Opaque(Opaque) { |
| assert(Functions.AllocateCodeSection && |
| "No AllocateCodeSection function provided!"); |
| assert(Functions.AllocateDataSection && |
| "No AllocateDataSection function provided!"); |
| assert(Functions.FinalizeMemory && |
| "No FinalizeMemory function provided!"); |
| assert(Functions.Destroy && |
| "No Destroy function provided!"); |
| } |
| |
| SimpleBindingMemoryManager::~SimpleBindingMemoryManager() { |
| Functions.Destroy(Opaque); |
| } |
| |
| uint8_t *SimpleBindingMemoryManager::allocateCodeSection( |
| uintptr_t Size, unsigned Alignment, unsigned SectionID, |
| StringRef SectionName) { |
| return Functions.AllocateCodeSection(Opaque, Size, Alignment, SectionID, |
| SectionName.str().c_str()); |
| } |
| |
| uint8_t *SimpleBindingMemoryManager::allocateDataSection( |
| uintptr_t Size, unsigned Alignment, unsigned SectionID, |
| StringRef SectionName, bool isReadOnly) { |
| return Functions.AllocateDataSection(Opaque, Size, Alignment, SectionID, |
| SectionName.str().c_str(), |
| isReadOnly); |
| } |
| |
| bool SimpleBindingMemoryManager::finalizeMemory(std::string *ErrMsg) { |
| char *errMsgCString = nullptr; |
| bool result = Functions.FinalizeMemory(Opaque, &errMsgCString); |
| assert((result || !errMsgCString) && |
| "Did not expect an error message if FinalizeMemory succeeded"); |
| if (errMsgCString) { |
| if (ErrMsg) |
| *ErrMsg = errMsgCString; |
| free(errMsgCString); |
| } |
| return result; |
| } |
| |
| } // anonymous namespace |
| |
| LLVMMCJITMemoryManagerRef LLVMCreateSimpleMCJITMemoryManager( |
| void *Opaque, |
| LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection, |
| LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection, |
| LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory, |
| LLVMMemoryManagerDestroyCallback Destroy) { |
| |
| if (!AllocateCodeSection || !AllocateDataSection || !FinalizeMemory || |
| !Destroy) |
| return nullptr; |
| |
| SimpleBindingMMFunctions functions; |
| functions.AllocateCodeSection = AllocateCodeSection; |
| functions.AllocateDataSection = AllocateDataSection; |
| functions.FinalizeMemory = FinalizeMemory; |
| functions.Destroy = Destroy; |
| return wrap(new SimpleBindingMemoryManager(functions, Opaque)); |
| } |
| |
| void LLVMDisposeMCJITMemoryManager(LLVMMCJITMemoryManagerRef MM) { |
| delete unwrap(MM); |
| } |
| |
| /*===-- JIT Event Listener functions -------------------------------------===*/ |
| |
| |
| #if !LLVM_USE_INTEL_JITEVENTS |
| LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void) |
| { |
| return nullptr; |
| } |
| #endif |
| |
| #if !LLVM_USE_OPROFILE |
| LLVMJITEventListenerRef LLVMCreateOProfileJITEventListener(void) |
| { |
| return nullptr; |
| } |
| #endif |
| |
| #if !LLVM_USE_PERF |
| LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void) |
| { |
| return nullptr; |
| } |
| #endif |