Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp
35266 views
//===---- IndirectionUtils.cpp - Utilities for call indirection in Orc ----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"9#include "llvm/ADT/STLExtras.h"10#include "llvm/ExecutionEngine/JITLink/x86_64.h"11#include "llvm/ExecutionEngine/Orc/OrcABISupport.h"12#include "llvm/IR/IRBuilder.h"13#include "llvm/IR/Module.h"14#include "llvm/MC/MCDisassembler/MCDisassembler.h"15#include "llvm/MC/MCInstrAnalysis.h"16#include "llvm/Support/Format.h"17#include "llvm/TargetParser/Triple.h"18#include "llvm/Transforms/Utils/Cloning.h"19#include <sstream>2021#define DEBUG_TYPE "orc"2223using namespace llvm;24using namespace llvm::orc;2526namespace {2728class CompileCallbackMaterializationUnit : public orc::MaterializationUnit {29public:30using CompileFunction = JITCompileCallbackManager::CompileFunction;3132CompileCallbackMaterializationUnit(SymbolStringPtr Name,33CompileFunction Compile)34: MaterializationUnit(Interface(35SymbolFlagsMap({{Name, JITSymbolFlags::Exported}}), nullptr)),36Name(std::move(Name)), Compile(std::move(Compile)) {}3738StringRef getName() const override { return "<Compile Callbacks>"; }3940private:41void materialize(std::unique_ptr<MaterializationResponsibility> R) override {42SymbolMap Result;43Result[Name] = {Compile(), JITSymbolFlags::Exported};44// No dependencies, so these calls cannot fail.45cantFail(R->notifyResolved(Result));46cantFail(R->notifyEmitted({}));47}4849void discard(const JITDylib &JD, const SymbolStringPtr &Name) override {50llvm_unreachable("Discard should never occur on a LMU?");51}5253SymbolStringPtr Name;54CompileFunction Compile;55};5657} // namespace5859namespace llvm {60namespace orc {6162TrampolinePool::~TrampolinePool() = default;63void IndirectStubsManager::anchor() {}6465Expected<ExecutorAddr>66JITCompileCallbackManager::getCompileCallback(CompileFunction Compile) {67if (auto TrampolineAddr = TP->getTrampoline()) {68auto CallbackName =69ES.intern(std::string("cc") + std::to_string(++NextCallbackId));7071std::lock_guard<std::mutex> Lock(CCMgrMutex);72AddrToSymbol[*TrampolineAddr] = CallbackName;73cantFail(74CallbacksJD.define(std::make_unique<CompileCallbackMaterializationUnit>(75std::move(CallbackName), std::move(Compile))));76return *TrampolineAddr;77} else78return TrampolineAddr.takeError();79}8081ExecutorAddr82JITCompileCallbackManager::executeCompileCallback(ExecutorAddr TrampolineAddr) {83SymbolStringPtr Name;8485{86std::unique_lock<std::mutex> Lock(CCMgrMutex);87auto I = AddrToSymbol.find(TrampolineAddr);8889// If this address is not associated with a compile callback then report an90// error to the execution session and return ErrorHandlerAddress to the91// callee.92if (I == AddrToSymbol.end()) {93Lock.unlock();94ES.reportError(95make_error<StringError>("No compile callback for trampoline at " +96formatv("{0:x}", TrampolineAddr),97inconvertibleErrorCode()));98return ErrorHandlerAddress;99} else100Name = I->second;101}102103if (auto Sym =104ES.lookup(makeJITDylibSearchOrder(105&CallbacksJD, JITDylibLookupFlags::MatchAllSymbols),106Name))107return Sym->getAddress();108else {109llvm::dbgs() << "Didn't find callback.\n";110// If anything goes wrong materializing Sym then report it to the session111// and return the ErrorHandlerAddress;112ES.reportError(Sym.takeError());113return ErrorHandlerAddress;114}115}116117Expected<std::unique_ptr<JITCompileCallbackManager>>118createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES,119ExecutorAddr ErrorHandlerAddress) {120switch (T.getArch()) {121default:122return make_error<StringError>(123std::string("No callback manager available for ") + T.str(),124inconvertibleErrorCode());125case Triple::aarch64:126case Triple::aarch64_32: {127typedef orc::LocalJITCompileCallbackManager<orc::OrcAArch64> CCMgrT;128return CCMgrT::Create(ES, ErrorHandlerAddress);129}130131case Triple::x86: {132typedef orc::LocalJITCompileCallbackManager<orc::OrcI386> CCMgrT;133return CCMgrT::Create(ES, ErrorHandlerAddress);134}135136case Triple::loongarch64: {137typedef orc::LocalJITCompileCallbackManager<orc::OrcLoongArch64> CCMgrT;138return CCMgrT::Create(ES, ErrorHandlerAddress);139}140141case Triple::mips: {142typedef orc::LocalJITCompileCallbackManager<orc::OrcMips32Be> CCMgrT;143return CCMgrT::Create(ES, ErrorHandlerAddress);144}145case Triple::mipsel: {146typedef orc::LocalJITCompileCallbackManager<orc::OrcMips32Le> CCMgrT;147return CCMgrT::Create(ES, ErrorHandlerAddress);148}149150case Triple::mips64:151case Triple::mips64el: {152typedef orc::LocalJITCompileCallbackManager<orc::OrcMips64> CCMgrT;153return CCMgrT::Create(ES, ErrorHandlerAddress);154}155156case Triple::riscv64: {157typedef orc::LocalJITCompileCallbackManager<orc::OrcRiscv64> CCMgrT;158return CCMgrT::Create(ES, ErrorHandlerAddress);159}160161case Triple::x86_64: {162if (T.getOS() == Triple::OSType::Win32) {163typedef orc::LocalJITCompileCallbackManager<orc::OrcX86_64_Win32> CCMgrT;164return CCMgrT::Create(ES, ErrorHandlerAddress);165} else {166typedef orc::LocalJITCompileCallbackManager<orc::OrcX86_64_SysV> CCMgrT;167return CCMgrT::Create(ES, ErrorHandlerAddress);168}169}170171}172}173174std::function<std::unique_ptr<IndirectStubsManager>()>175createLocalIndirectStubsManagerBuilder(const Triple &T) {176switch (T.getArch()) {177default:178return [](){179return std::make_unique<180orc::LocalIndirectStubsManager<orc::OrcGenericABI>>();181};182183case Triple::aarch64:184case Triple::aarch64_32:185return [](){186return std::make_unique<187orc::LocalIndirectStubsManager<orc::OrcAArch64>>();188};189190case Triple::x86:191return [](){192return std::make_unique<193orc::LocalIndirectStubsManager<orc::OrcI386>>();194};195196case Triple::loongarch64:197return []() {198return std::make_unique<199orc::LocalIndirectStubsManager<orc::OrcLoongArch64>>();200};201202case Triple::mips:203return [](){204return std::make_unique<205orc::LocalIndirectStubsManager<orc::OrcMips32Be>>();206};207208case Triple::mipsel:209return [](){210return std::make_unique<211orc::LocalIndirectStubsManager<orc::OrcMips32Le>>();212};213214case Triple::mips64:215case Triple::mips64el:216return [](){217return std::make_unique<218orc::LocalIndirectStubsManager<orc::OrcMips64>>();219};220221case Triple::riscv64:222return []() {223return std::make_unique<224orc::LocalIndirectStubsManager<orc::OrcRiscv64>>();225};226227case Triple::x86_64:228if (T.getOS() == Triple::OSType::Win32) {229return [](){230return std::make_unique<231orc::LocalIndirectStubsManager<orc::OrcX86_64_Win32>>();232};233} else {234return [](){235return std::make_unique<236orc::LocalIndirectStubsManager<orc::OrcX86_64_SysV>>();237};238}239240}241}242243Constant* createIRTypedAddress(FunctionType &FT, ExecutorAddr Addr) {244Constant *AddrIntVal =245ConstantInt::get(Type::getInt64Ty(FT.getContext()), Addr.getValue());246Constant *AddrPtrVal =247ConstantExpr::getIntToPtr(AddrIntVal, PointerType::get(&FT, 0));248return AddrPtrVal;249}250251GlobalVariable* createImplPointer(PointerType &PT, Module &M,252const Twine &Name, Constant *Initializer) {253auto IP = new GlobalVariable(M, &PT, false, GlobalValue::ExternalLinkage,254Initializer, Name, nullptr,255GlobalValue::NotThreadLocal, 0, true);256IP->setVisibility(GlobalValue::HiddenVisibility);257return IP;258}259260void makeStub(Function &F, Value &ImplPointer) {261assert(F.isDeclaration() && "Can't turn a definition into a stub.");262assert(F.getParent() && "Function isn't in a module.");263Module &M = *F.getParent();264BasicBlock *EntryBlock = BasicBlock::Create(M.getContext(), "entry", &F);265IRBuilder<> Builder(EntryBlock);266LoadInst *ImplAddr = Builder.CreateLoad(F.getType(), &ImplPointer);267std::vector<Value*> CallArgs;268for (auto &A : F.args())269CallArgs.push_back(&A);270CallInst *Call = Builder.CreateCall(F.getFunctionType(), ImplAddr, CallArgs);271Call->setTailCall();272Call->setAttributes(F.getAttributes());273if (F.getReturnType()->isVoidTy())274Builder.CreateRetVoid();275else276Builder.CreateRet(Call);277}278279std::vector<GlobalValue *> SymbolLinkagePromoter::operator()(Module &M) {280std::vector<GlobalValue *> PromotedGlobals;281282for (auto &GV : M.global_values()) {283bool Promoted = true;284285// Rename if necessary.286if (!GV.hasName())287GV.setName("__orc_anon." + Twine(NextId++));288else if (GV.getName().starts_with("\01L"))289GV.setName("__" + GV.getName().substr(1) + "." + Twine(NextId++));290else if (GV.hasLocalLinkage())291GV.setName("__orc_lcl." + GV.getName() + "." + Twine(NextId++));292else293Promoted = false;294295if (GV.hasLocalLinkage()) {296GV.setLinkage(GlobalValue::ExternalLinkage);297GV.setVisibility(GlobalValue::HiddenVisibility);298Promoted = true;299}300GV.setUnnamedAddr(GlobalValue::UnnamedAddr::None);301302if (Promoted)303PromotedGlobals.push_back(&GV);304}305306return PromotedGlobals;307}308309Function* cloneFunctionDecl(Module &Dst, const Function &F,310ValueToValueMapTy *VMap) {311Function *NewF =312Function::Create(cast<FunctionType>(F.getValueType()),313F.getLinkage(), F.getName(), &Dst);314NewF->copyAttributesFrom(&F);315316if (VMap) {317(*VMap)[&F] = NewF;318auto NewArgI = NewF->arg_begin();319for (auto ArgI = F.arg_begin(), ArgE = F.arg_end(); ArgI != ArgE;320++ArgI, ++NewArgI)321(*VMap)[&*ArgI] = &*NewArgI;322}323324return NewF;325}326327GlobalVariable* cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,328ValueToValueMapTy *VMap) {329GlobalVariable *NewGV = new GlobalVariable(330Dst, GV.getValueType(), GV.isConstant(),331GV.getLinkage(), nullptr, GV.getName(), nullptr,332GV.getThreadLocalMode(), GV.getType()->getAddressSpace());333NewGV->copyAttributesFrom(&GV);334if (VMap)335(*VMap)[&GV] = NewGV;336return NewGV;337}338339GlobalAlias* cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,340ValueToValueMapTy &VMap) {341assert(OrigA.getAliasee() && "Original alias doesn't have an aliasee?");342auto *NewA = GlobalAlias::create(OrigA.getValueType(),343OrigA.getType()->getPointerAddressSpace(),344OrigA.getLinkage(), OrigA.getName(), &Dst);345NewA->copyAttributesFrom(&OrigA);346VMap[&OrigA] = NewA;347return NewA;348}349350Error addFunctionPointerRelocationsToCurrentSymbol(jitlink::Symbol &Sym,351jitlink::LinkGraph &G,352MCDisassembler &Disassembler,353MCInstrAnalysis &MIA) {354// AArch64 appears to already come with the necessary relocations. Among other355// architectures, only x86_64 is currently implemented here.356if (G.getTargetTriple().getArch() != Triple::x86_64)357return Error::success();358359raw_null_ostream CommentStream;360auto &STI = Disassembler.getSubtargetInfo();361362// Determine the function bounds363auto &B = Sym.getBlock();364assert(!B.isZeroFill() && "expected content block");365auto SymAddress = Sym.getAddress();366auto SymStartInBlock =367(const uint8_t *)B.getContent().data() + Sym.getOffset();368auto SymSize = Sym.getSize() ? Sym.getSize() : B.getSize() - Sym.getOffset();369auto Content = ArrayRef(SymStartInBlock, SymSize);370371LLVM_DEBUG(dbgs() << "Adding self-relocations to " << Sym.getName() << "\n");372373SmallDenseSet<uintptr_t, 8> ExistingRelocations;374for (auto &E : B.edges()) {375if (E.isRelocation())376ExistingRelocations.insert(E.getOffset());377}378379size_t I = 0;380while (I < Content.size()) {381MCInst Instr;382uint64_t InstrSize = 0;383uint64_t InstrStart = SymAddress.getValue() + I;384auto DecodeStatus = Disassembler.getInstruction(385Instr, InstrSize, Content.drop_front(I), InstrStart, CommentStream);386if (DecodeStatus != MCDisassembler::Success) {387LLVM_DEBUG(dbgs() << "Aborting due to disassembly failure at address "388<< InstrStart);389return make_error<StringError>(390formatv("failed to disassemble at address {0:x16}", InstrStart),391inconvertibleErrorCode());392}393// Advance to the next instruction.394I += InstrSize;395396// Check for a PC-relative address equal to the symbol itself.397auto PCRelAddr =398MIA.evaluateMemoryOperandAddress(Instr, &STI, InstrStart, InstrSize);399if (!PCRelAddr || *PCRelAddr != SymAddress.getValue())400continue;401402auto RelocOffInInstr =403MIA.getMemoryOperandRelocationOffset(Instr, InstrSize);404if (!RelocOffInInstr || InstrSize - *RelocOffInInstr != 4) {405LLVM_DEBUG(dbgs() << "Skipping unknown self-relocation at "406<< InstrStart);407continue;408}409410auto RelocOffInBlock = orc::ExecutorAddr(InstrStart) + *RelocOffInInstr -411SymAddress + Sym.getOffset();412if (ExistingRelocations.contains(RelocOffInBlock))413continue;414415LLVM_DEBUG(dbgs() << "Adding delta32 self-relocation at " << InstrStart);416B.addEdge(jitlink::x86_64::Delta32, RelocOffInBlock, Sym, /*Addend=*/-4);417}418return Error::success();419}420421} // End namespace orc.422} // End namespace llvm.423424425