//===-- RenameIndependentSubregs.cpp - Live Interval Analysis -------------===// // // 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 // //===----------------------------------------------------------------------===// // /// Rename independent subregisters looks for virtual registers with /// independently used subregisters and renames them to new virtual registers. /// Example: In the following: /// %0:sub0 = ... /// %0:sub1 = ... /// use %0:sub0 /// %0:sub0 = ... /// use %0:sub0 /// use %0:sub1 /// sub0 and sub1 are never used together, and we have two independent sub0 /// definitions. This pass will rename to: /// %0:sub0 = ... /// %1:sub1 = ... /// use %1:sub1 /// %2:sub1 = ... /// use %2:sub1 /// use %0:sub0 // //===----------------------------------------------------------------------===// #include "LiveRangeUtils.h" #include "PHIEliminationUtils.h" #include "llvm/CodeGen/LiveInterval.h" #include "llvm/CodeGen/LiveIntervals.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/InitializePasses.h" using namespace llvm; #define DEBUG_TYPE "rename-independent-subregs" namespace { class RenameIndependentSubregs : public MachineFunctionPass { public: static char ID; RenameIndependentSubregs() : MachineFunctionPass(ID) {} StringRef getPassName() const override { return "Rename Disconnected Subregister Components"; } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addRequired(); AU.addPreserved(); AU.addRequired(); AU.addPreserved(); MachineFunctionPass::getAnalysisUsage(AU); } bool runOnMachineFunction(MachineFunction &MF) override; private: struct SubRangeInfo { ConnectedVNInfoEqClasses ConEQ; LiveInterval::SubRange *SR; unsigned Index; SubRangeInfo(LiveIntervals &LIS, LiveInterval::SubRange &SR, unsigned Index) : ConEQ(LIS), SR(&SR), Index(Index) {} }; /// Split unrelated subregister components and rename them to new vregs. bool renameComponents(LiveInterval &LI) const; /// Build a vector of SubRange infos and a union find set of /// equivalence classes. /// Returns true if more than 1 equivalence class was found. bool findComponents(IntEqClasses &Classes, SmallVectorImpl &SubRangeInfos, LiveInterval &LI) const; /// Distribute the LiveInterval segments into the new LiveIntervals /// belonging to their class. void distribute(const IntEqClasses &Classes, const SmallVectorImpl &SubRangeInfos, const SmallVectorImpl &Intervals) const; /// Constructs main liverange and add missing undef+dead flags. void computeMainRangesFixFlags(const IntEqClasses &Classes, const SmallVectorImpl &SubRangeInfos, const SmallVectorImpl &Intervals) const; /// Rewrite Machine Operands to use the new vreg belonging to their class. void rewriteOperands(const IntEqClasses &Classes, const SmallVectorImpl &SubRangeInfos, const SmallVectorImpl &Intervals) const; LiveIntervals *LIS; MachineRegisterInfo *MRI; const TargetInstrInfo *TII; }; } // end anonymous namespace char RenameIndependentSubregs::ID; char &llvm::RenameIndependentSubregsID = RenameIndependentSubregs::ID; INITIALIZE_PASS_BEGIN(RenameIndependentSubregs, DEBUG_TYPE, "Rename Independent Subregisters", false, false) INITIALIZE_PASS_DEPENDENCY(SlotIndexes) INITIALIZE_PASS_DEPENDENCY(LiveIntervals) INITIALIZE_PASS_END(RenameIndependentSubregs, DEBUG_TYPE, "Rename Independent Subregisters", false, false) bool RenameIndependentSubregs::renameComponents(LiveInterval &LI) const { // Shortcut: We cannot have split components with a single definition. if (LI.valnos.size() < 2) return false; SmallVector SubRangeInfos; IntEqClasses Classes; if (!findComponents(Classes, SubRangeInfos, LI)) return false; // Create a new VReg for each class. unsigned Reg = LI.reg(); const TargetRegisterClass *RegClass = MRI->getRegClass(Reg); SmallVector Intervals; Intervals.push_back(&LI); LLVM_DEBUG(dbgs() << printReg(Reg) << ": Found " << Classes.getNumClasses() << " equivalence classes.\n"); LLVM_DEBUG(dbgs() << printReg(Reg) << ": Splitting into newly created:"); for (unsigned I = 1, NumClasses = Classes.getNumClasses(); I < NumClasses; ++I) { Register NewVReg = MRI->createVirtualRegister(RegClass); LiveInterval &NewLI = LIS->createEmptyInterval(NewVReg); Intervals.push_back(&NewLI); LLVM_DEBUG(dbgs() << ' ' << printReg(NewVReg)); } LLVM_DEBUG(dbgs() << '\n'); rewriteOperands(Classes, SubRangeInfos, Intervals); distribute(Classes, SubRangeInfos, Intervals); computeMainRangesFixFlags(Classes, SubRangeInfos, Intervals); return true; } bool RenameIndependentSubregs::findComponents(IntEqClasses &Classes, SmallVectorImpl &SubRangeInfos, LiveInterval &LI) const { // First step: Create connected components for the VNInfos inside the // subranges and count the global number of such components. unsigned NumComponents = 0; for (LiveInterval::SubRange &SR : LI.subranges()) { SubRangeInfos.push_back(SubRangeInfo(*LIS, SR, NumComponents)); ConnectedVNInfoEqClasses &ConEQ = SubRangeInfos.back().ConEQ; unsigned NumSubComponents = ConEQ.Classify(SR); NumComponents += NumSubComponents; } // Shortcut: With only 1 subrange, the normal separate component tests are // enough and we do not need to perform the union-find on the subregister // segments. if (SubRangeInfos.size() < 2) return false; // Next step: Build union-find structure over all subranges and merge classes // across subranges when they are affected by the same MachineOperand. const TargetRegisterInfo &TRI = *MRI->getTargetRegisterInfo(); Classes.grow(NumComponents); unsigned Reg = LI.reg(); for (const MachineOperand &MO : MRI->reg_nodbg_operands(Reg)) { if (!MO.isDef() && !MO.readsReg()) continue; unsigned SubRegIdx = MO.getSubReg(); LaneBitmask LaneMask = TRI.getSubRegIndexLaneMask(SubRegIdx); unsigned MergedID = ~0u; for (RenameIndependentSubregs::SubRangeInfo &SRInfo : SubRangeInfos) { const LiveInterval::SubRange &SR = *SRInfo.SR; if ((SR.LaneMask & LaneMask).none()) continue; SlotIndex Pos = LIS->getInstructionIndex(*MO.getParent()); Pos = MO.isDef() ? Pos.getRegSlot(MO.isEarlyClobber()) : Pos.getBaseIndex(); const VNInfo *VNI = SR.getVNInfoAt(Pos); if (VNI == nullptr) continue; // Map to local representant ID. unsigned LocalID = SRInfo.ConEQ.getEqClass(VNI); // Global ID unsigned ID = LocalID + SRInfo.Index; // Merge other sets MergedID = MergedID == ~0u ? ID : Classes.join(MergedID, ID); } } // Early exit if we ended up with a single equivalence class. Classes.compress(); unsigned NumClasses = Classes.getNumClasses(); return NumClasses > 1; } void RenameIndependentSubregs::rewriteOperands(const IntEqClasses &Classes, const SmallVectorImpl &SubRangeInfos, const SmallVectorImpl &Intervals) const { const TargetRegisterInfo &TRI = *MRI->getTargetRegisterInfo(); unsigned Reg = Intervals[0]->reg(); for (MachineRegisterInfo::reg_nodbg_iterator I = MRI->reg_nodbg_begin(Reg), E = MRI->reg_nodbg_end(); I != E; ) { MachineOperand &MO = *I++; if (!MO.isDef() && !MO.readsReg()) continue; auto *MI = MO.getParent(); SlotIndex Pos = LIS->getInstructionIndex(*MI); Pos = MO.isDef() ? Pos.getRegSlot(MO.isEarlyClobber()) : Pos.getBaseIndex(); unsigned SubRegIdx = MO.getSubReg(); LaneBitmask LaneMask = TRI.getSubRegIndexLaneMask(SubRegIdx); unsigned ID = ~0u; for (const SubRangeInfo &SRInfo : SubRangeInfos) { const LiveInterval::SubRange &SR = *SRInfo.SR; if ((SR.LaneMask & LaneMask).none()) continue; const VNInfo *VNI = SR.getVNInfoAt(Pos); if (VNI == nullptr) continue; // Map to local representant ID. unsigned LocalID = SRInfo.ConEQ.getEqClass(VNI); // Global ID ID = Classes[LocalID + SRInfo.Index]; break; } unsigned VReg = Intervals[ID]->reg(); MO.setReg(VReg); if (MO.isTied() && Reg != VReg) { /// Undef use operands are not tracked in the equivalence class, /// but need to be updated if they are tied; take care to only /// update the tied operand. unsigned OperandNo = MI->getOperandNo(&MO); unsigned TiedIdx = MI->findTiedOperandIdx(OperandNo); MI->getOperand(TiedIdx).setReg(VReg); // above substitution breaks the iterator, so restart. I = MRI->reg_nodbg_begin(Reg); } } // TODO: We could attempt to recompute new register classes while visiting // the operands: Some of the split register may be fine with less constraint // classes than the original vreg. } void RenameIndependentSubregs::distribute(const IntEqClasses &Classes, const SmallVectorImpl &SubRangeInfos, const SmallVectorImpl &Intervals) const { unsigned NumClasses = Classes.getNumClasses(); SmallVector VNIMapping; SmallVector SubRanges; BumpPtrAllocator &Allocator = LIS->getVNInfoAllocator(); for (const SubRangeInfo &SRInfo : SubRangeInfos) { LiveInterval::SubRange &SR = *SRInfo.SR; unsigned NumValNos = SR.valnos.size(); VNIMapping.clear(); VNIMapping.reserve(NumValNos); SubRanges.clear(); SubRanges.resize(NumClasses-1, nullptr); for (unsigned I = 0; I < NumValNos; ++I) { const VNInfo &VNI = *SR.valnos[I]; unsigned LocalID = SRInfo.ConEQ.getEqClass(&VNI); unsigned ID = Classes[LocalID + SRInfo.Index]; VNIMapping.push_back(ID); if (ID > 0 && SubRanges[ID-1] == nullptr) SubRanges[ID-1] = Intervals[ID]->createSubRange(Allocator, SR.LaneMask); } DistributeRange(SR, SubRanges.data(), VNIMapping); } } static bool subRangeLiveAt(const LiveInterval &LI, SlotIndex Pos) { for (const LiveInterval::SubRange &SR : LI.subranges()) { if (SR.liveAt(Pos)) return true; } return false; } void RenameIndependentSubregs::computeMainRangesFixFlags( const IntEqClasses &Classes, const SmallVectorImpl &SubRangeInfos, const SmallVectorImpl &Intervals) const { BumpPtrAllocator &Allocator = LIS->getVNInfoAllocator(); const SlotIndexes &Indexes = *LIS->getSlotIndexes(); for (size_t I = 0, E = Intervals.size(); I < E; ++I) { LiveInterval &LI = *Intervals[I]; unsigned Reg = LI.reg(); LI.removeEmptySubRanges(); // There must be a def (or live-in) before every use. Splitting vregs may // violate this principle as the splitted vreg may not have a definition on // every path. Fix this by creating IMPLICIT_DEF instruction as necessary. for (const LiveInterval::SubRange &SR : LI.subranges()) { // Search for "PHI" value numbers in the subranges. We must find a live // value in each predecessor block, add an IMPLICIT_DEF where it is // missing. for (unsigned I = 0; I < SR.valnos.size(); ++I) { const VNInfo &VNI = *SR.valnos[I]; if (VNI.isUnused() || !VNI.isPHIDef()) continue; SlotIndex Def = VNI.def; MachineBasicBlock &MBB = *Indexes.getMBBFromIndex(Def); for (MachineBasicBlock *PredMBB : MBB.predecessors()) { SlotIndex PredEnd = Indexes.getMBBEndIdx(PredMBB); if (subRangeLiveAt(LI, PredEnd.getPrevSlot())) continue; MachineBasicBlock::iterator InsertPos = llvm::findPHICopyInsertPoint(PredMBB, &MBB, Reg); const MCInstrDesc &MCDesc = TII->get(TargetOpcode::IMPLICIT_DEF); MachineInstrBuilder ImpDef = BuildMI(*PredMBB, InsertPos, DebugLoc(), MCDesc, Reg); SlotIndex DefIdx = LIS->InsertMachineInstrInMaps(*ImpDef); SlotIndex RegDefIdx = DefIdx.getRegSlot(); for (LiveInterval::SubRange &SR : LI.subranges()) { VNInfo *SRVNI = SR.getNextValue(RegDefIdx, Allocator); SR.addSegment(LiveRange::Segment(RegDefIdx, PredEnd, SRVNI)); } } } } for (MachineOperand &MO : MRI->reg_nodbg_operands(Reg)) { if (!MO.isDef()) continue; unsigned SubRegIdx = MO.getSubReg(); if (SubRegIdx == 0) continue; // After assigning the new vreg we may not have any other sublanes living // in and out of the instruction anymore. We need to add new dead and // undef flags in these cases. if (!MO.isUndef()) { SlotIndex Pos = LIS->getInstructionIndex(*MO.getParent()); if (!subRangeLiveAt(LI, Pos)) MO.setIsUndef(); } if (!MO.isDead()) { SlotIndex Pos = LIS->getInstructionIndex(*MO.getParent()).getDeadSlot(); if (!subRangeLiveAt(LI, Pos)) MO.setIsDead(); } } if (I == 0) LI.clear(); LIS->constructMainRangeFromSubranges(LI); // A def of a subregister may be a use of other register lanes. Replacing // such a def with a def of a different register will eliminate the use, // and may cause the recorded live range to be larger than the actual // liveness in the program IR. LIS->shrinkToUses(&LI); } } bool RenameIndependentSubregs::runOnMachineFunction(MachineFunction &MF) { // Skip renaming if liveness of subregister is not tracked. MRI = &MF.getRegInfo(); if (!MRI->subRegLivenessEnabled()) return false; LLVM_DEBUG(dbgs() << "Renaming independent subregister live ranges in " << MF.getName() << '\n'); LIS = &getAnalysis(); TII = MF.getSubtarget().getInstrInfo(); // Iterate over all vregs. Note that we query getNumVirtRegs() the newly // created vregs end up with higher numbers but do not need to be visited as // there can't be any further splitting. bool Changed = false; for (size_t I = 0, E = MRI->getNumVirtRegs(); I < E; ++I) { unsigned Reg = Register::index2VirtReg(I); if (!LIS->hasInterval(Reg)) continue; LiveInterval &LI = LIS->getInterval(Reg); if (!LI.hasSubRanges()) continue; Changed |= renameComponents(LI); } return Changed; }