| //===-- 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<read-undef> = ... |
| /// %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<read-undef> = ... |
| /// %1:sub1<read-undef> = ... |
| /// use %1:sub1 |
| /// %2:sub1<read-undef> = ... |
| /// 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<LiveIntervals>(); |
| AU.addPreserved<LiveIntervals>(); |
| AU.addRequired<SlotIndexes>(); |
| AU.addPreserved<SlotIndexes>(); |
| 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<SubRangeInfo> &SubRangeInfos, |
| LiveInterval &LI) const; |
| |
| /// Distribute the LiveInterval segments into the new LiveIntervals |
| /// belonging to their class. |
| void distribute(const IntEqClasses &Classes, |
| const SmallVectorImpl<SubRangeInfo> &SubRangeInfos, |
| const SmallVectorImpl<LiveInterval*> &Intervals) const; |
| |
| /// Constructs main liverange and add missing undef+dead flags. |
| void computeMainRangesFixFlags(const IntEqClasses &Classes, |
| const SmallVectorImpl<SubRangeInfo> &SubRangeInfos, |
| const SmallVectorImpl<LiveInterval*> &Intervals) const; |
| |
| /// Rewrite Machine Operands to use the new vreg belonging to their class. |
| void rewriteOperands(const IntEqClasses &Classes, |
| const SmallVectorImpl<SubRangeInfo> &SubRangeInfos, |
| const SmallVectorImpl<LiveInterval*> &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<SubRangeInfo, 4> 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<LiveInterval*, 4> 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<RenameIndependentSubregs::SubRangeInfo> &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<SubRangeInfo> &SubRangeInfos, |
| const SmallVectorImpl<LiveInterval*> &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<SubRangeInfo> &SubRangeInfos, |
| const SmallVectorImpl<LiveInterval*> &Intervals) const { |
| unsigned NumClasses = Classes.getNumClasses(); |
| SmallVector<unsigned, 8> VNIMapping; |
| SmallVector<LiveInterval::SubRange*, 8> 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<SubRangeInfo> &SubRangeInfos, |
| const SmallVectorImpl<LiveInterval*> &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<LiveIntervals>(); |
| 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; |
| } |