| //===-- 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 "llvm/CodeGen/RenameIndependentSubregs.h" | |
| #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/TargetInstrInfo.h" | |
| #include "llvm/InitializePasses.h" | |
| #include "llvm/Pass.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "rename-independent-subregs" | |
| namespace { | |
| class RenameIndependentSubregs { | |
| public: | |
| RenameIndependentSubregs(LiveIntervals *LIS) : LIS(LIS) {} | |
| bool run(MachineFunction &MF); | |
| 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 = nullptr; | |
| MachineRegisterInfo *MRI = nullptr; | |
| const TargetInstrInfo *TII = nullptr; | |
| }; | |
| class RenameIndependentSubregsLegacy : public MachineFunctionPass { | |
| public: | |
| static char ID; | |
| RenameIndependentSubregsLegacy() : MachineFunctionPass(ID) {} | |
| bool runOnMachineFunction(MachineFunction &MF) override; | |
| StringRef getPassName() const override { | |
| return "Rename Disconnected Subregister Components"; | |
| } | |
| void getAnalysisUsage(AnalysisUsage &AU) const override { | |
| AU.setPreservesCFG(); | |
| AU.addRequired<LiveIntervalsWrapperPass>(); | |
| AU.addPreserved<LiveIntervalsWrapperPass>(); | |
| AU.addRequired<SlotIndexesWrapperPass>(); | |
| AU.addPreserved<SlotIndexesWrapperPass>(); | |
| MachineFunctionPass::getAnalysisUsage(AU); | |
| } | |
| }; | |
| } // end anonymous namespace | |
| char RenameIndependentSubregsLegacy::ID; | |
| char &llvm::RenameIndependentSubregsID = RenameIndependentSubregsLegacy::ID; | |
| INITIALIZE_PASS_BEGIN(RenameIndependentSubregsLegacy, DEBUG_TYPE, | |
| "Rename Independent Subregisters", false, false) | |
| INITIALIZE_PASS_DEPENDENCY(SlotIndexesWrapperPass) | |
| INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass) | |
| INITIALIZE_PASS_END(RenameIndependentSubregsLegacy, 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. | |
| Register 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); | |
| Register 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(); | |
| Register 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; | |
| } | |
| Register 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 = MO.getOperandNo(); | |
| 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 { | |
| const TargetRegisterInfo &TRI = TII->getRegisterInfo(); | |
| BumpPtrAllocator &Allocator = LIS->getVNInfoAllocator(); | |
| const SlotIndexes &Indexes = *LIS->getSlotIndexes(); | |
| for (size_t I = 0, E = Intervals.size(); I < E; ++I) { | |
| LiveInterval &LI = *Intervals[I]; | |
| Register Reg = LI.reg(); | |
| LI.removeEmptySubRanges(); | |
| // Try to establish a single subregister which covers all uses. | |
| // Note: this is assuming the selected subregister will only be | |
| // used for fixing up live intervals issues created by this pass. | |
| LaneBitmask UsedMask, UnusedMask; | |
| for (LiveInterval::SubRange &SR : LI.subranges()) | |
| UsedMask |= SR.LaneMask; | |
| SmallVector<unsigned> SubRegIdxs; | |
| RegState Flags = {}; | |
| unsigned SubReg = 0; | |
| // TODO: Handle SubRegIdxs.size() > 1 | |
| if (TRI.getCoveringSubRegIndexes(MRI->getRegClass(Reg), UsedMask, | |
| SubRegIdxs) && | |
| SubRegIdxs.size() == 1) { | |
| SubReg = SubRegIdxs.front(); | |
| Flags = RegState::Undef; | |
| } else { | |
| UnusedMask = MRI->getMaxLaneMaskForVReg(Reg) & ~UsedMask; | |
| } | |
| // 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) | |
| .addDef(Reg, Flags, SubReg); | |
| 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)); | |
| } | |
| if (!UnusedMask.none()) { | |
| LiveInterval::SubRange *SR = | |
| LI.createSubRange(Allocator, UnusedMask); | |
| SR->createDeadDef(RegDefIdx, Allocator); | |
| } | |
| } | |
| } | |
| } | |
| 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); | |
| } | |
| } | |
| PreservedAnalyses | |
| RenameIndependentSubregsPass::run(MachineFunction &MF, | |
| MachineFunctionAnalysisManager &MFAM) { | |
| auto &LIS = MFAM.getResult<LiveIntervalsAnalysis>(MF); | |
| if (!RenameIndependentSubregs(&LIS).run(MF)) | |
| return PreservedAnalyses::all(); | |
| auto PA = getMachineFunctionPassPreservedAnalyses(); | |
| PA.preserveSet<CFGAnalyses>(); | |
| PA.preserve<LiveIntervalsAnalysis>(); | |
| PA.preserve<SlotIndexesAnalysis>(); | |
| return PA; | |
| } | |
| bool RenameIndependentSubregsLegacy::runOnMachineFunction(MachineFunction &MF) { | |
| auto &LIS = getAnalysis<LiveIntervalsWrapperPass>().getLIS(); | |
| return RenameIndependentSubregs(&LIS).run(MF); | |
| } | |
| bool RenameIndependentSubregs::run(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'); | |
| 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) { | |
| Register Reg = Register::index2VirtReg(I); | |
| if (!LIS->hasInterval(Reg)) | |
| continue; | |
| LiveInterval &LI = LIS->getInterval(Reg); | |
| if (!LI.hasSubRanges()) | |
| continue; | |
| Changed |= renameComponents(LI); | |
| } | |
| return Changed; | |
| } |