//===-- 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 #include 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(const_cast(P)); } /*===-- Operations on generic values --------------------------------------===*/ LLVMGenericValueRef LLVMCreateGenericValueOfInt(LLVMTypeRef Ty, unsigned long long N, LLVMBool IsSigned) { GenericValue *GenVal = new GenericValue(); GenVal->IntVal = APInt(unwrap(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(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(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(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 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 CM = unwrap(options.CodeModel, JIT)) builder.setCodeModel(*CM); if (options.MCJMM) builder.setMCJITMemoryManager( std::unique_ptr(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 ArgVec(ArgV, ArgV + ArgC); return unwrap(EE)->runFunctionAsMain(unwrap(F), ArgVec, EnvP); } LLVMGenericValueRef LLVMRunFunction(LLVMExecutionEngineRef EE, LLVMValueRef F, unsigned NumArgs, LLVMGenericValueRef *Args) { unwrap(EE)->finalizeObject(); std::vector 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(F), ArgVec); return wrap(Result); } void LLVMFreeMachineCodeForFunction(LLVMExecutionEngineRef EE, LLVMValueRef F) { } void LLVMAddModule(LLVMExecutionEngineRef EE, LLVMModuleRef M){ unwrap(EE)->addModule(std::unique_ptr(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(Global), Addr); } void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global) { unwrap(EE)->finalizeObject(); return unwrap(EE)->getPointerToGlobal(unwrap(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