diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:30 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:30 +0300 |
commit | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (patch) | |
tree | 012bb94d777798f1f56ac1cec429509766d05181 /contrib/libs/llvm12/lib/CodeGen/FixupStatepointCallerSaved.cpp | |
parent | 6751af0b0c1b952fede40b19b71da8025b5d8bcf (diff) | |
download | ydb-2598ef1d0aee359b4b6d5fdd1758916d5907d04f.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/CodeGen/FixupStatepointCallerSaved.cpp')
-rw-r--r-- | contrib/libs/llvm12/lib/CodeGen/FixupStatepointCallerSaved.cpp | 668 |
1 files changed, 334 insertions, 334 deletions
diff --git a/contrib/libs/llvm12/lib/CodeGen/FixupStatepointCallerSaved.cpp b/contrib/libs/llvm12/lib/CodeGen/FixupStatepointCallerSaved.cpp index f8f99b7e87..b7c0a46aa6 100644 --- a/contrib/libs/llvm12/lib/CodeGen/FixupStatepointCallerSaved.cpp +++ b/contrib/libs/llvm12/lib/CodeGen/FixupStatepointCallerSaved.cpp @@ -46,20 +46,20 @@ static cl::opt<bool> FixupSCSExtendSlotSize( cl::desc("Allow spill in spill slot of greater size than register size"), cl::Hidden); -static cl::opt<bool> PassGCPtrInCSR( - "fixup-allow-gcptr-in-csr", cl::Hidden, cl::init(false), - cl::desc("Allow passing GC Pointer arguments in callee saved registers")); - -static cl::opt<bool> EnableCopyProp( - "fixup-scs-enable-copy-propagation", cl::Hidden, cl::init(true), - cl::desc("Enable simple copy propagation during register reloading")); - -// This is purely debugging option. -// It may be handy for investigating statepoint spilling issues. -static cl::opt<unsigned> MaxStatepointsWithRegs( - "fixup-max-csr-statepoints", cl::Hidden, - cl::desc("Max number of statepoints allowed to pass GC Ptrs in registers")); - +static cl::opt<bool> PassGCPtrInCSR( + "fixup-allow-gcptr-in-csr", cl::Hidden, cl::init(false), + cl::desc("Allow passing GC Pointer arguments in callee saved registers")); + +static cl::opt<bool> EnableCopyProp( + "fixup-scs-enable-copy-propagation", cl::Hidden, cl::init(true), + cl::desc("Enable simple copy propagation during register reloading")); + +// This is purely debugging option. +// It may be handy for investigating statepoint spilling issues. +static cl::opt<unsigned> MaxStatepointsWithRegs( + "fixup-max-csr-statepoints", cl::Hidden, + cl::desc("Max number of statepoints allowed to pass GC Ptrs in registers")); + namespace { class FixupStatepointCallerSaved : public MachineFunctionPass { @@ -81,7 +81,7 @@ public: bool runOnMachineFunction(MachineFunction &MF) override; }; - + } // End anonymous namespace. char FixupStatepointCallerSaved::ID = 0; @@ -98,101 +98,101 @@ static unsigned getRegisterSize(const TargetRegisterInfo &TRI, Register Reg) { return TRI.getSpillSize(*RC); } -// Try to eliminate redundant copy to register which we're going to -// spill, i.e. try to change: -// X = COPY Y -// SPILL X -// to -// SPILL Y -// If there are no uses of X between copy and STATEPOINT, that COPY -// may be eliminated. -// Reg - register we're about to spill -// RI - On entry points to statepoint. -// On successful copy propagation set to new spill point. -// IsKill - set to true if COPY is Kill (there are no uses of Y) -// Returns either found source copy register or original one. -static Register performCopyPropagation(Register Reg, - MachineBasicBlock::iterator &RI, - bool &IsKill, const TargetInstrInfo &TII, - const TargetRegisterInfo &TRI) { - // First check if statepoint itself uses Reg in non-meta operands. - int Idx = RI->findRegisterUseOperandIdx(Reg, false, &TRI); - if (Idx >= 0 && (unsigned)Idx < StatepointOpers(&*RI).getNumDeoptArgsIdx()) { - IsKill = false; - return Reg; - } - - if (!EnableCopyProp) - return Reg; - - MachineBasicBlock *MBB = RI->getParent(); - MachineBasicBlock::reverse_iterator E = MBB->rend(); - MachineInstr *Def = nullptr, *Use = nullptr; - for (auto It = ++(RI.getReverse()); It != E; ++It) { - if (It->readsRegister(Reg, &TRI) && !Use) - Use = &*It; - if (It->modifiesRegister(Reg, &TRI)) { - Def = &*It; - break; - } - } - - if (!Def) - return Reg; - - auto DestSrc = TII.isCopyInstr(*Def); - if (!DestSrc || DestSrc->Destination->getReg() != Reg) - return Reg; - - Register SrcReg = DestSrc->Source->getReg(); - - if (getRegisterSize(TRI, Reg) != getRegisterSize(TRI, SrcReg)) - return Reg; - - LLVM_DEBUG(dbgs() << "spillRegisters: perform copy propagation " - << printReg(Reg, &TRI) << " -> " << printReg(SrcReg, &TRI) - << "\n"); - - // Insert spill immediately after Def - RI = ++MachineBasicBlock::iterator(Def); - IsKill = DestSrc->Source->isKill(); - - // There are no uses of original register between COPY and STATEPOINT. - // There can't be any after STATEPOINT, so we can eliminate Def. - if (!Use) { - LLVM_DEBUG(dbgs() << "spillRegisters: removing dead copy " << *Def); - Def->eraseFromParent(); - } - return SrcReg; -} - +// Try to eliminate redundant copy to register which we're going to +// spill, i.e. try to change: +// X = COPY Y +// SPILL X +// to +// SPILL Y +// If there are no uses of X between copy and STATEPOINT, that COPY +// may be eliminated. +// Reg - register we're about to spill +// RI - On entry points to statepoint. +// On successful copy propagation set to new spill point. +// IsKill - set to true if COPY is Kill (there are no uses of Y) +// Returns either found source copy register or original one. +static Register performCopyPropagation(Register Reg, + MachineBasicBlock::iterator &RI, + bool &IsKill, const TargetInstrInfo &TII, + const TargetRegisterInfo &TRI) { + // First check if statepoint itself uses Reg in non-meta operands. + int Idx = RI->findRegisterUseOperandIdx(Reg, false, &TRI); + if (Idx >= 0 && (unsigned)Idx < StatepointOpers(&*RI).getNumDeoptArgsIdx()) { + IsKill = false; + return Reg; + } + + if (!EnableCopyProp) + return Reg; + + MachineBasicBlock *MBB = RI->getParent(); + MachineBasicBlock::reverse_iterator E = MBB->rend(); + MachineInstr *Def = nullptr, *Use = nullptr; + for (auto It = ++(RI.getReverse()); It != E; ++It) { + if (It->readsRegister(Reg, &TRI) && !Use) + Use = &*It; + if (It->modifiesRegister(Reg, &TRI)) { + Def = &*It; + break; + } + } + + if (!Def) + return Reg; + + auto DestSrc = TII.isCopyInstr(*Def); + if (!DestSrc || DestSrc->Destination->getReg() != Reg) + return Reg; + + Register SrcReg = DestSrc->Source->getReg(); + + if (getRegisterSize(TRI, Reg) != getRegisterSize(TRI, SrcReg)) + return Reg; + + LLVM_DEBUG(dbgs() << "spillRegisters: perform copy propagation " + << printReg(Reg, &TRI) << " -> " << printReg(SrcReg, &TRI) + << "\n"); + + // Insert spill immediately after Def + RI = ++MachineBasicBlock::iterator(Def); + IsKill = DestSrc->Source->isKill(); + + // There are no uses of original register between COPY and STATEPOINT. + // There can't be any after STATEPOINT, so we can eliminate Def. + if (!Use) { + LLVM_DEBUG(dbgs() << "spillRegisters: removing dead copy " << *Def); + Def->eraseFromParent(); + } + return SrcReg; +} + namespace { -// Pair {Register, FrameIndex} -using RegSlotPair = std::pair<Register, int>; - -// Keeps track of what reloads were inserted in MBB. -class RegReloadCache { - using ReloadSet = SmallSet<RegSlotPair, 8>; - DenseMap<const MachineBasicBlock *, ReloadSet> Reloads; - -public: - RegReloadCache() = default; - - // Record reload of Reg from FI in block MBB - void recordReload(Register Reg, int FI, const MachineBasicBlock *MBB) { - RegSlotPair RSP(Reg, FI); - auto Res = Reloads[MBB].insert(RSP); - (void)Res; - assert(Res.second && "reload already exists"); - } - - // Does basic block MBB contains reload of Reg from FI? - bool hasReload(Register Reg, int FI, const MachineBasicBlock *MBB) { - RegSlotPair RSP(Reg, FI); - return Reloads.count(MBB) && Reloads[MBB].count(RSP); - } -}; - +// Pair {Register, FrameIndex} +using RegSlotPair = std::pair<Register, int>; + +// Keeps track of what reloads were inserted in MBB. +class RegReloadCache { + using ReloadSet = SmallSet<RegSlotPair, 8>; + DenseMap<const MachineBasicBlock *, ReloadSet> Reloads; + +public: + RegReloadCache() = default; + + // Record reload of Reg from FI in block MBB + void recordReload(Register Reg, int FI, const MachineBasicBlock *MBB) { + RegSlotPair RSP(Reg, FI); + auto Res = Reloads[MBB].insert(RSP); + (void)Res; + assert(Res.second && "reload already exists"); + } + + // Does basic block MBB contains reload of Reg from FI? + bool hasReload(Register Reg, int FI, const MachineBasicBlock *MBB) { + RegSlotPair RSP(Reg, FI); + return Reloads.count(MBB) && Reloads[MBB].count(RSP); + } +}; + // Cache used frame indexes during statepoint re-write to re-use them in // processing next statepoint instruction. // Two strategies. One is to preserve the size of spill slot while another one @@ -214,62 +214,62 @@ private: // size will be increased. DenseMap<unsigned, FrameIndexesPerSize> Cache; - // Keeps track of slots reserved for the shared landing pad processing. - // Initialized from GlobalIndices for the current EHPad. - SmallSet<int, 8> ReservedSlots; - - // Landing pad can be destination of several statepoints. Every register - // defined by such statepoints must be spilled to the same stack slot. - // This map keeps that information. - DenseMap<const MachineBasicBlock *, SmallVector<RegSlotPair, 8>> - GlobalIndices; - - FrameIndexesPerSize &getCacheBucket(unsigned Size) { - // In FixupSCSExtendSlotSize mode the bucket with 0 index is used - // for all sizes. - return Cache[FixupSCSExtendSlotSize ? 0 : Size]; - } - + // Keeps track of slots reserved for the shared landing pad processing. + // Initialized from GlobalIndices for the current EHPad. + SmallSet<int, 8> ReservedSlots; + + // Landing pad can be destination of several statepoints. Every register + // defined by such statepoints must be spilled to the same stack slot. + // This map keeps that information. + DenseMap<const MachineBasicBlock *, SmallVector<RegSlotPair, 8>> + GlobalIndices; + + FrameIndexesPerSize &getCacheBucket(unsigned Size) { + // In FixupSCSExtendSlotSize mode the bucket with 0 index is used + // for all sizes. + return Cache[FixupSCSExtendSlotSize ? 0 : Size]; + } + public: FrameIndexesCache(MachineFrameInfo &MFI, const TargetRegisterInfo &TRI) : MFI(MFI), TRI(TRI) {} // Reset the current state of used frame indexes. After invocation of - // this function all frame indexes are available for allocation with - // the exception of slots reserved for landing pad processing (if any). - void reset(const MachineBasicBlock *EHPad) { + // this function all frame indexes are available for allocation with + // the exception of slots reserved for landing pad processing (if any). + void reset(const MachineBasicBlock *EHPad) { for (auto &It : Cache) It.second.Index = 0; - - ReservedSlots.clear(); - if (EHPad && GlobalIndices.count(EHPad)) - for (auto &RSP : GlobalIndices[EHPad]) - ReservedSlots.insert(RSP.second); + + ReservedSlots.clear(); + if (EHPad && GlobalIndices.count(EHPad)) + for (auto &RSP : GlobalIndices[EHPad]) + ReservedSlots.insert(RSP.second); } - + // Get frame index to spill the register. - int getFrameIndex(Register Reg, MachineBasicBlock *EHPad) { - // Check if slot for Reg is already reserved at EHPad. - auto It = GlobalIndices.find(EHPad); - if (It != GlobalIndices.end()) { - auto &Vec = It->second; - auto Idx = llvm::find_if( - Vec, [Reg](RegSlotPair &RSP) { return Reg == RSP.first; }); - if (Idx != Vec.end()) { - int FI = Idx->second; - LLVM_DEBUG(dbgs() << "Found global FI " << FI << " for register " - << printReg(Reg, &TRI) << " at " - << printMBBReference(*EHPad) << "\n"); - assert(ReservedSlots.count(FI) && "using unreserved slot"); - return FI; - } - } - + int getFrameIndex(Register Reg, MachineBasicBlock *EHPad) { + // Check if slot for Reg is already reserved at EHPad. + auto It = GlobalIndices.find(EHPad); + if (It != GlobalIndices.end()) { + auto &Vec = It->second; + auto Idx = llvm::find_if( + Vec, [Reg](RegSlotPair &RSP) { return Reg == RSP.first; }); + if (Idx != Vec.end()) { + int FI = Idx->second; + LLVM_DEBUG(dbgs() << "Found global FI " << FI << " for register " + << printReg(Reg, &TRI) << " at " + << printMBBReference(*EHPad) << "\n"); + assert(ReservedSlots.count(FI) && "using unreserved slot"); + return FI; + } + } + unsigned Size = getRegisterSize(TRI, Reg); - FrameIndexesPerSize &Line = getCacheBucket(Size); - while (Line.Index < Line.Slots.size()) { + FrameIndexesPerSize &Line = getCacheBucket(Size); + while (Line.Index < Line.Slots.size()) { int FI = Line.Slots[Line.Index++]; - if (ReservedSlots.count(FI)) - continue; + if (ReservedSlots.count(FI)) + continue; // If all sizes are kept together we probably need to extend the // spill slot size. if (MFI.getObjectSize(FI) < Size) { @@ -283,25 +283,25 @@ public: NumSpillSlotsAllocated++; Line.Slots.push_back(FI); ++Line.Index; - - // Remember assignment {Reg, FI} for EHPad - if (EHPad) { - GlobalIndices[EHPad].push_back(std::make_pair(Reg, FI)); - LLVM_DEBUG(dbgs() << "Reserved FI " << FI << " for spilling reg " - << printReg(Reg, &TRI) << " at landing pad " - << printMBBReference(*EHPad) << "\n"); - } - + + // Remember assignment {Reg, FI} for EHPad + if (EHPad) { + GlobalIndices[EHPad].push_back(std::make_pair(Reg, FI)); + LLVM_DEBUG(dbgs() << "Reserved FI " << FI << " for spilling reg " + << printReg(Reg, &TRI) << " at landing pad " + << printMBBReference(*EHPad) << "\n"); + } + return FI; } - + // Sort all registers to spill in descendent order. In the // FixupSCSExtendSlotSize mode it will minimize the total frame size. // In non FixupSCSExtendSlotSize mode we can skip this step. void sortRegisters(SmallVectorImpl<Register> &Regs) { if (!FixupSCSExtendSlotSize) return; - llvm::sort(Regs, [&](Register &A, Register &B) { + llvm::sort(Regs, [&](Register &A, Register &B) { return getRegisterSize(TRI, A) > getRegisterSize(TRI, B); }); } @@ -313,8 +313,8 @@ private: // statepoint instruction. MachineInstr &MI; MachineFunction &MF; - // If non-null then statepoint is invoke, and this points to the landing pad. - MachineBasicBlock *EHPad; + // If non-null then statepoint is invoke, and this points to the landing pad. + MachineBasicBlock *EHPad; const TargetRegisterInfo &TRI; const TargetInstrInfo &TII; MachineFrameInfo &MFI; @@ -322,77 +322,77 @@ private: const uint32_t *Mask; // Cache of frame indexes used on previous instruction processing. FrameIndexesCache &CacheFI; - bool AllowGCPtrInCSR; + bool AllowGCPtrInCSR; // Operands with physical registers requiring spilling. SmallVector<unsigned, 8> OpsToSpill; // Set of register to spill. SmallVector<Register, 8> RegsToSpill; - // Set of registers to reload after statepoint. - SmallVector<Register, 8> RegsToReload; + // Set of registers to reload after statepoint. + SmallVector<Register, 8> RegsToReload; // Map Register to Frame Slot index. DenseMap<Register, int> RegToSlotIdx; public: StatepointState(MachineInstr &MI, const uint32_t *Mask, - FrameIndexesCache &CacheFI, bool AllowGCPtrInCSR) + FrameIndexesCache &CacheFI, bool AllowGCPtrInCSR) : MI(MI), MF(*MI.getMF()), TRI(*MF.getSubtarget().getRegisterInfo()), TII(*MF.getSubtarget().getInstrInfo()), MFI(MF.getFrameInfo()), - Mask(Mask), CacheFI(CacheFI), AllowGCPtrInCSR(AllowGCPtrInCSR) { - - // Find statepoint's landing pad, if any. - EHPad = nullptr; - MachineBasicBlock *MBB = MI.getParent(); - // Invoke statepoint must be last one in block. - bool Last = std::none_of(++MI.getIterator(), MBB->end().getInstrIterator(), - [](MachineInstr &I) { - return I.getOpcode() == TargetOpcode::STATEPOINT; - }); - - if (!Last) - return; - - auto IsEHPad = [](MachineBasicBlock *B) { return B->isEHPad(); }; - - assert(llvm::count_if(MBB->successors(), IsEHPad) < 2 && "multiple EHPads"); - - auto It = llvm::find_if(MBB->successors(), IsEHPad); - if (It != MBB->succ_end()) - EHPad = *It; - } - - MachineBasicBlock *getEHPad() const { return EHPad; } - + Mask(Mask), CacheFI(CacheFI), AllowGCPtrInCSR(AllowGCPtrInCSR) { + + // Find statepoint's landing pad, if any. + EHPad = nullptr; + MachineBasicBlock *MBB = MI.getParent(); + // Invoke statepoint must be last one in block. + bool Last = std::none_of(++MI.getIterator(), MBB->end().getInstrIterator(), + [](MachineInstr &I) { + return I.getOpcode() == TargetOpcode::STATEPOINT; + }); + + if (!Last) + return; + + auto IsEHPad = [](MachineBasicBlock *B) { return B->isEHPad(); }; + + assert(llvm::count_if(MBB->successors(), IsEHPad) < 2 && "multiple EHPads"); + + auto It = llvm::find_if(MBB->successors(), IsEHPad); + if (It != MBB->succ_end()) + EHPad = *It; + } + + MachineBasicBlock *getEHPad() const { return EHPad; } + // Return true if register is callee saved. bool isCalleeSaved(Register Reg) { return (Mask[Reg / 32] >> Reg % 32) & 1; } - + // Iterates over statepoint meta args to find caller saver registers. // Also cache the size of found registers. // Returns true if caller save registers found. bool findRegistersToSpill() { - SmallSet<Register, 8> GCRegs; - // All GC pointer operands assigned to registers produce new value. - // Since they're tied to their defs, it is enough to collect def registers. - for (const auto &Def : MI.defs()) - GCRegs.insert(Def.getReg()); - + SmallSet<Register, 8> GCRegs; + // All GC pointer operands assigned to registers produce new value. + // Since they're tied to their defs, it is enough to collect def registers. + for (const auto &Def : MI.defs()) + GCRegs.insert(Def.getReg()); + SmallSet<Register, 8> VisitedRegs; for (unsigned Idx = StatepointOpers(&MI).getVarIdx(), EndIdx = MI.getNumOperands(); Idx < EndIdx; ++Idx) { MachineOperand &MO = MI.getOperand(Idx); - // Leave `undef` operands as is, StackMaps will rewrite them - // into a constant. - if (!MO.isReg() || MO.isImplicit() || MO.isUndef()) + // Leave `undef` operands as is, StackMaps will rewrite them + // into a constant. + if (!MO.isReg() || MO.isImplicit() || MO.isUndef()) continue; Register Reg = MO.getReg(); assert(Reg.isPhysical() && "Only physical regs are expected"); - - if (isCalleeSaved(Reg) && (AllowGCPtrInCSR || !is_contained(GCRegs, Reg))) + + if (isCalleeSaved(Reg) && (AllowGCPtrInCSR || !is_contained(GCRegs, Reg))) continue; - - LLVM_DEBUG(dbgs() << "Will spill " << printReg(Reg, &TRI) << " at index " - << Idx << "\n"); - + + LLVM_DEBUG(dbgs() << "Will spill " << printReg(Reg, &TRI) << " at index " + << Idx << "\n"); + if (VisitedRegs.insert(Reg).second) RegsToSpill.push_back(Reg); OpsToSpill.push_back(Idx); @@ -400,109 +400,109 @@ public: CacheFI.sortRegisters(RegsToSpill); return !RegsToSpill.empty(); } - + // Spill all caller saved registers right before statepoint instruction. // Remember frame index where register is spilled. void spillRegisters() { for (Register Reg : RegsToSpill) { - int FI = CacheFI.getFrameIndex(Reg, EHPad); + int FI = CacheFI.getFrameIndex(Reg, EHPad); const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg); - + NumSpilledRegisters++; RegToSlotIdx[Reg] = FI; - - LLVM_DEBUG(dbgs() << "Spilling " << printReg(Reg, &TRI) << " to FI " << FI - << "\n"); - - // Perform trivial copy propagation - bool IsKill = true; - MachineBasicBlock::iterator InsertBefore(MI); - Reg = performCopyPropagation(Reg, InsertBefore, IsKill, TII, TRI); - - LLVM_DEBUG(dbgs() << "Insert spill before " << *InsertBefore); - TII.storeRegToStackSlot(*MI.getParent(), InsertBefore, Reg, IsKill, FI, - RC, &TRI); + + LLVM_DEBUG(dbgs() << "Spilling " << printReg(Reg, &TRI) << " to FI " << FI + << "\n"); + + // Perform trivial copy propagation + bool IsKill = true; + MachineBasicBlock::iterator InsertBefore(MI); + Reg = performCopyPropagation(Reg, InsertBefore, IsKill, TII, TRI); + + LLVM_DEBUG(dbgs() << "Insert spill before " << *InsertBefore); + TII.storeRegToStackSlot(*MI.getParent(), InsertBefore, Reg, IsKill, FI, + RC, &TRI); } } - - void insertReloadBefore(unsigned Reg, MachineBasicBlock::iterator It, - MachineBasicBlock *MBB) { - const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg); - int FI = RegToSlotIdx[Reg]; - if (It != MBB->end()) { - TII.loadRegFromStackSlot(*MBB, It, Reg, FI, RC, &TRI); - return; - } - - // To insert reload at the end of MBB, insert it before last instruction - // and then swap them. - assert(!MBB->empty() && "Empty block"); - --It; - TII.loadRegFromStackSlot(*MBB, It, Reg, FI, RC, &TRI); - MachineInstr *Reload = It->getPrevNode(); - int Dummy = 0; - (void)Dummy; - assert(TII.isLoadFromStackSlot(*Reload, Dummy) == Reg); - assert(Dummy == FI); - MBB->remove(Reload); - MBB->insertAfter(It, Reload); - } - - // Insert reloads of (relocated) registers spilled in statepoint. - void insertReloads(MachineInstr *NewStatepoint, RegReloadCache &RC) { - MachineBasicBlock *MBB = NewStatepoint->getParent(); - auto InsertPoint = std::next(NewStatepoint->getIterator()); - - for (auto Reg : RegsToReload) { - insertReloadBefore(Reg, InsertPoint, MBB); - LLVM_DEBUG(dbgs() << "Reloading " << printReg(Reg, &TRI) << " from FI " - << RegToSlotIdx[Reg] << " after statepoint\n"); - - if (EHPad && !RC.hasReload(Reg, RegToSlotIdx[Reg], EHPad)) { - RC.recordReload(Reg, RegToSlotIdx[Reg], EHPad); - auto EHPadInsertPoint = EHPad->SkipPHIsLabelsAndDebug(EHPad->begin()); - insertReloadBefore(Reg, EHPadInsertPoint, EHPad); - LLVM_DEBUG(dbgs() << "...also reload at EHPad " - << printMBBReference(*EHPad) << "\n"); - } - } - } - + + void insertReloadBefore(unsigned Reg, MachineBasicBlock::iterator It, + MachineBasicBlock *MBB) { + const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg); + int FI = RegToSlotIdx[Reg]; + if (It != MBB->end()) { + TII.loadRegFromStackSlot(*MBB, It, Reg, FI, RC, &TRI); + return; + } + + // To insert reload at the end of MBB, insert it before last instruction + // and then swap them. + assert(!MBB->empty() && "Empty block"); + --It; + TII.loadRegFromStackSlot(*MBB, It, Reg, FI, RC, &TRI); + MachineInstr *Reload = It->getPrevNode(); + int Dummy = 0; + (void)Dummy; + assert(TII.isLoadFromStackSlot(*Reload, Dummy) == Reg); + assert(Dummy == FI); + MBB->remove(Reload); + MBB->insertAfter(It, Reload); + } + + // Insert reloads of (relocated) registers spilled in statepoint. + void insertReloads(MachineInstr *NewStatepoint, RegReloadCache &RC) { + MachineBasicBlock *MBB = NewStatepoint->getParent(); + auto InsertPoint = std::next(NewStatepoint->getIterator()); + + for (auto Reg : RegsToReload) { + insertReloadBefore(Reg, InsertPoint, MBB); + LLVM_DEBUG(dbgs() << "Reloading " << printReg(Reg, &TRI) << " from FI " + << RegToSlotIdx[Reg] << " after statepoint\n"); + + if (EHPad && !RC.hasReload(Reg, RegToSlotIdx[Reg], EHPad)) { + RC.recordReload(Reg, RegToSlotIdx[Reg], EHPad); + auto EHPadInsertPoint = EHPad->SkipPHIsLabelsAndDebug(EHPad->begin()); + insertReloadBefore(Reg, EHPadInsertPoint, EHPad); + LLVM_DEBUG(dbgs() << "...also reload at EHPad " + << printMBBReference(*EHPad) << "\n"); + } + } + } + // Re-write statepoint machine instruction to replace caller saved operands // with indirect memory location (frame index). - MachineInstr *rewriteStatepoint() { + MachineInstr *rewriteStatepoint() { MachineInstr *NewMI = MF.CreateMachineInstr(TII.get(MI.getOpcode()), MI.getDebugLoc(), true); MachineInstrBuilder MIB(MF, NewMI); - unsigned NumOps = MI.getNumOperands(); - - // New indices for the remaining defs. - SmallVector<unsigned, 8> NewIndices; - unsigned NumDefs = MI.getNumDefs(); - for (unsigned I = 0; I < NumDefs; ++I) { - MachineOperand &DefMO = MI.getOperand(I); - assert(DefMO.isReg() && DefMO.isDef() && "Expected Reg Def operand"); - Register Reg = DefMO.getReg(); - if (!AllowGCPtrInCSR) { - assert(is_contained(RegsToSpill, Reg)); - RegsToReload.push_back(Reg); - } else { - if (isCalleeSaved(Reg)) { - NewIndices.push_back(NewMI->getNumOperands()); - MIB.addReg(Reg, RegState::Define); - } else { - NewIndices.push_back(NumOps); - RegsToReload.push_back(Reg); - } - } - } - + unsigned NumOps = MI.getNumOperands(); + + // New indices for the remaining defs. + SmallVector<unsigned, 8> NewIndices; + unsigned NumDefs = MI.getNumDefs(); + for (unsigned I = 0; I < NumDefs; ++I) { + MachineOperand &DefMO = MI.getOperand(I); + assert(DefMO.isReg() && DefMO.isDef() && "Expected Reg Def operand"); + Register Reg = DefMO.getReg(); + if (!AllowGCPtrInCSR) { + assert(is_contained(RegsToSpill, Reg)); + RegsToReload.push_back(Reg); + } else { + if (isCalleeSaved(Reg)) { + NewIndices.push_back(NewMI->getNumOperands()); + MIB.addReg(Reg, RegState::Define); + } else { + NewIndices.push_back(NumOps); + RegsToReload.push_back(Reg); + } + } + } + // Add End marker. OpsToSpill.push_back(MI.getNumOperands()); unsigned CurOpIdx = 0; - for (unsigned I = NumDefs; I < MI.getNumOperands(); ++I) { + for (unsigned I = NumDefs; I < MI.getNumOperands(); ++I) { MachineOperand &MO = MI.getOperand(I); if (I == OpsToSpill[CurOpIdx]) { int FI = RegToSlotIdx[MO.getReg()]; @@ -513,38 +513,38 @@ public: MIB.addFrameIndex(FI); MIB.addImm(0); ++CurOpIdx; - } else { + } else { MIB.add(MO); - unsigned OldDef; - if (AllowGCPtrInCSR && MI.isRegTiedToDefOperand(I, &OldDef)) { - assert(OldDef < NumDefs); - assert(NewIndices[OldDef] < NumOps); - MIB->tieOperands(NewIndices[OldDef], MIB->getNumOperands() - 1); - } - } + unsigned OldDef; + if (AllowGCPtrInCSR && MI.isRegTiedToDefOperand(I, &OldDef)) { + assert(OldDef < NumDefs); + assert(NewIndices[OldDef] < NumOps); + MIB->tieOperands(NewIndices[OldDef], MIB->getNumOperands() - 1); + } + } } assert(CurOpIdx == (OpsToSpill.size() - 1) && "Not all operands processed"); // Add mem operands. NewMI->setMemRefs(MF, MI.memoperands()); for (auto It : RegToSlotIdx) { - Register R = It.first; + Register R = It.first; int FrameIndex = It.second; auto PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIndex); - MachineMemOperand::Flags Flags = MachineMemOperand::MOLoad; - if (is_contained(RegsToReload, R)) - Flags |= MachineMemOperand::MOStore; - auto *MMO = - MF.getMachineMemOperand(PtrInfo, Flags, getRegisterSize(TRI, R), - MFI.getObjectAlign(FrameIndex)); + MachineMemOperand::Flags Flags = MachineMemOperand::MOLoad; + if (is_contained(RegsToReload, R)) + Flags |= MachineMemOperand::MOStore; + auto *MMO = + MF.getMachineMemOperand(PtrInfo, Flags, getRegisterSize(TRI, R), + MFI.getObjectAlign(FrameIndex)); NewMI->addMemOperand(MF, MMO); } - + // Insert new statepoint and erase old one. MI.getParent()->insert(MI, NewMI); - - LLVM_DEBUG(dbgs() << "rewritten statepoint to : " << *NewMI << "\n"); + + LLVM_DEBUG(dbgs() << "rewritten statepoint to : " << *NewMI << "\n"); MI.eraseFromParent(); - return NewMI; + return NewMI; } }; @@ -553,33 +553,33 @@ private: MachineFunction &MF; const TargetRegisterInfo &TRI; FrameIndexesCache CacheFI; - RegReloadCache ReloadCache; + RegReloadCache ReloadCache; public: StatepointProcessor(MachineFunction &MF) : MF(MF), TRI(*MF.getSubtarget().getRegisterInfo()), CacheFI(MF.getFrameInfo(), TRI) {} - bool process(MachineInstr &MI, bool AllowGCPtrInCSR) { + bool process(MachineInstr &MI, bool AllowGCPtrInCSR) { StatepointOpers SO(&MI); uint64_t Flags = SO.getFlags(); // Do nothing for LiveIn, it supports all registers. if (Flags & (uint64_t)StatepointFlags::DeoptLiveIn) return false; - LLVM_DEBUG(dbgs() << "\nMBB " << MI.getParent()->getNumber() << " " - << MI.getParent()->getName() << " : process statepoint " - << MI); + LLVM_DEBUG(dbgs() << "\nMBB " << MI.getParent()->getNumber() << " " + << MI.getParent()->getName() << " : process statepoint " + << MI); CallingConv::ID CC = SO.getCallingConv(); const uint32_t *Mask = TRI.getCallPreservedMask(MF, CC); - StatepointState SS(MI, Mask, CacheFI, AllowGCPtrInCSR); - CacheFI.reset(SS.getEHPad()); + StatepointState SS(MI, Mask, CacheFI, AllowGCPtrInCSR); + CacheFI.reset(SS.getEHPad()); if (!SS.findRegistersToSpill()) return false; SS.spillRegisters(); - auto *NewStatepoint = SS.rewriteStatepoint(); - SS.insertReloads(NewStatepoint, ReloadCache); + auto *NewStatepoint = SS.rewriteStatepoint(); + SS.insertReloads(NewStatepoint, ReloadCache); return true; } }; @@ -604,14 +604,14 @@ bool FixupStatepointCallerSaved::runOnMachineFunction(MachineFunction &MF) { bool Changed = false; StatepointProcessor SPP(MF); - unsigned NumStatepoints = 0; - bool AllowGCPtrInCSR = PassGCPtrInCSR; - for (MachineInstr *I : Statepoints) { - ++NumStatepoints; - if (MaxStatepointsWithRegs.getNumOccurrences() && - NumStatepoints >= MaxStatepointsWithRegs) - AllowGCPtrInCSR = false; - Changed |= SPP.process(*I, AllowGCPtrInCSR); - } + unsigned NumStatepoints = 0; + bool AllowGCPtrInCSR = PassGCPtrInCSR; + for (MachineInstr *I : Statepoints) { + ++NumStatepoints; + if (MaxStatepointsWithRegs.getNumOccurrences() && + NumStatepoints >= MaxStatepointsWithRegs) + AllowGCPtrInCSR = false; + Changed |= SPP.process(*I, AllowGCPtrInCSR); + } return Changed; } |