| //===- DetectDeadLanes.cpp - SubRegister Lane Usage Analysis --*- C++ -*---===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| /// \file | |
| /// Analysis that tracks defined/used subregister lanes across COPY instructions | |
| /// and instructions that get lowered to a COPY (PHI, REG_SEQUENCE, | |
| /// INSERT_SUBREG, EXTRACT_SUBREG). | |
| /// The information is used to detect dead definitions and the usage of | |
| /// (completely) undefined values and mark the operands as such. | |
| /// This pass is necessary because the dead/undef status is not obvious anymore | |
| /// when subregisters are involved. | |
| /// | |
| /// Example: | |
| /// %0 = some definition | |
| /// %1 = IMPLICIT_DEF | |
| /// %2 = REG_SEQUENCE %0, sub0, %1, sub1 | |
| /// %3 = EXTRACT_SUBREG %2, sub1 | |
| /// = use %3 | |
| /// The %0 definition is dead and %3 contains an undefined value. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include <deque> | |
| #include <vector> | |
| #include "llvm/ADT/BitVector.h" | |
| #include "llvm/ADT/SetVector.h" | |
| #include "llvm/CodeGen/MachineFunctionPass.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/CodeGen/Passes.h" | |
| #include "llvm/CodeGen/TargetRegisterInfo.h" | |
| #include "llvm/CodeGen/TargetSubtargetInfo.h" | |
| #include "llvm/InitializePasses.h" | |
| #include "llvm/Pass.h" | |
| #include "llvm/PassRegistry.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "detect-dead-lanes" | |
| namespace { | |
| /// Contains a bitmask of which lanes of a given virtual register are | |
| /// defined and which ones are actually used. | |
| struct VRegInfo { | |
| LaneBitmask UsedLanes; | |
| LaneBitmask DefinedLanes; | |
| }; | |
| class DetectDeadLanes : public MachineFunctionPass { | |
| public: | |
| bool runOnMachineFunction(MachineFunction &MF) override; | |
| static char ID; | |
| DetectDeadLanes() : MachineFunctionPass(ID) {} | |
| StringRef getPassName() const override { return "Detect Dead Lanes"; } | |
| void getAnalysisUsage(AnalysisUsage &AU) const override { | |
| AU.setPreservesCFG(); | |
| MachineFunctionPass::getAnalysisUsage(AU); | |
| } | |
| private: | |
| /// Add used lane bits on the register used by operand \p MO. This translates | |
| /// the bitmask based on the operands subregister, and puts the register into | |
| /// the worklist if any new bits were added. | |
| void addUsedLanesOnOperand(const MachineOperand &MO, LaneBitmask UsedLanes); | |
| /// Given a bitmask \p UsedLanes for the used lanes on a def output of a | |
| /// COPY-like instruction determine the lanes used on the use operands | |
| /// and call addUsedLanesOnOperand() for them. | |
| void transferUsedLanesStep(const MachineInstr &MI, LaneBitmask UsedLanes); | |
| /// Given a use regiser operand \p Use and a mask of defined lanes, check | |
| /// if the operand belongs to a lowersToCopies() instruction, transfer the | |
| /// mask to the def and put the instruction into the worklist. | |
| void transferDefinedLanesStep(const MachineOperand &Use, | |
| LaneBitmask DefinedLanes); | |
| /// Given a mask \p DefinedLanes of lanes defined at operand \p OpNum | |
| /// of COPY-like instruction, determine which lanes are defined at the output | |
| /// operand \p Def. | |
| LaneBitmask transferDefinedLanes(const MachineOperand &Def, unsigned OpNum, | |
| LaneBitmask DefinedLanes) const; | |
| /// Given a mask \p UsedLanes used from the output of instruction \p MI | |
| /// determine which lanes are used from operand \p MO of this instruction. | |
| LaneBitmask transferUsedLanes(const MachineInstr &MI, LaneBitmask UsedLanes, | |
| const MachineOperand &MO) const; | |
| bool runOnce(MachineFunction &MF); | |
| LaneBitmask determineInitialDefinedLanes(unsigned Reg); | |
| LaneBitmask determineInitialUsedLanes(unsigned Reg); | |
| bool isUndefRegAtInput(const MachineOperand &MO, | |
| const VRegInfo &RegInfo) const; | |
| bool isUndefInput(const MachineOperand &MO, bool *CrossCopy) const; | |
| const MachineRegisterInfo *MRI; | |
| const TargetRegisterInfo *TRI; | |
| void PutInWorklist(unsigned RegIdx) { | |
| if (WorklistMembers.test(RegIdx)) | |
| return; | |
| WorklistMembers.set(RegIdx); | |
| Worklist.push_back(RegIdx); | |
| } | |
| VRegInfo *VRegInfos; | |
| /// Worklist containing virtreg indexes. | |
| std::deque<unsigned> Worklist; | |
| BitVector WorklistMembers; | |
| /// This bitvector is set for each vreg index where the vreg is defined | |
| /// by an instruction where lowersToCopies()==true. | |
| BitVector DefinedByCopy; | |
| }; | |
| } // end anonymous namespace | |
| char DetectDeadLanes::ID = 0; | |
| char &llvm::DetectDeadLanesID = DetectDeadLanes::ID; | |
| INITIALIZE_PASS(DetectDeadLanes, DEBUG_TYPE, "Detect Dead Lanes", false, false) | |
| /// Returns true if \p MI will get lowered to a series of COPY instructions. | |
| /// We call this a COPY-like instruction. | |
| static bool lowersToCopies(const MachineInstr &MI) { | |
| // Note: We could support instructions with MCInstrDesc::isRegSequenceLike(), | |
| // isExtractSubRegLike(), isInsertSubregLike() in the future even though they | |
| // are not lowered to a COPY. | |
| switch (MI.getOpcode()) { | |
| case TargetOpcode::COPY: | |
| case TargetOpcode::PHI: | |
| case TargetOpcode::INSERT_SUBREG: | |
| case TargetOpcode::REG_SEQUENCE: | |
| case TargetOpcode::EXTRACT_SUBREG: | |
| return true; | |
| } | |
| return false; | |
| } | |
| static bool isCrossCopy(const MachineRegisterInfo &MRI, | |
| const MachineInstr &MI, | |
| const TargetRegisterClass *DstRC, | |
| const MachineOperand &MO) { | |
| assert(lowersToCopies(MI)); | |
| unsigned SrcReg = MO.getReg(); | |
| const TargetRegisterClass *SrcRC = MRI.getRegClass(SrcReg); | |
| if (DstRC == SrcRC) | |
| return false; | |
| unsigned SrcSubIdx = MO.getSubReg(); | |
| const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo(); | |
| unsigned DstSubIdx = 0; | |
| switch (MI.getOpcode()) { | |
| case TargetOpcode::INSERT_SUBREG: | |
| if (MI.getOperandNo(&MO) == 2) | |
| DstSubIdx = MI.getOperand(3).getImm(); | |
| break; | |
| case TargetOpcode::REG_SEQUENCE: { | |
| unsigned OpNum = MI.getOperandNo(&MO); | |
| DstSubIdx = MI.getOperand(OpNum+1).getImm(); | |
| break; | |
| } | |
| case TargetOpcode::EXTRACT_SUBREG: { | |
| unsigned SubReg = MI.getOperand(2).getImm(); | |
| SrcSubIdx = TRI.composeSubRegIndices(SubReg, SrcSubIdx); | |
| } | |
| } | |
| unsigned PreA, PreB; // Unused. | |
| if (SrcSubIdx && DstSubIdx) | |
| return !TRI.getCommonSuperRegClass(SrcRC, SrcSubIdx, DstRC, DstSubIdx, PreA, | |
| PreB); | |
| if (SrcSubIdx) | |
| return !TRI.getMatchingSuperRegClass(SrcRC, DstRC, SrcSubIdx); | |
| if (DstSubIdx) | |
| return !TRI.getMatchingSuperRegClass(DstRC, SrcRC, DstSubIdx); | |
| return !TRI.getCommonSubClass(SrcRC, DstRC); | |
| } | |
| void DetectDeadLanes::addUsedLanesOnOperand(const MachineOperand &MO, | |
| LaneBitmask UsedLanes) { | |
| if (!MO.readsReg()) | |
| return; | |
| unsigned MOReg = MO.getReg(); | |
| if (!TargetRegisterInfo::isVirtualRegister(MOReg)) | |
| return; | |
| unsigned MOSubReg = MO.getSubReg(); | |
| if (MOSubReg != 0) | |
| UsedLanes = TRI->composeSubRegIndexLaneMask(MOSubReg, UsedLanes); | |
| UsedLanes &= MRI->getMaxLaneMaskForVReg(MOReg); | |
| unsigned MORegIdx = TargetRegisterInfo::virtReg2Index(MOReg); | |
| VRegInfo &MORegInfo = VRegInfos[MORegIdx]; | |
| LaneBitmask PrevUsedLanes = MORegInfo.UsedLanes; | |
| // Any change at all? | |
| if ((UsedLanes & ~PrevUsedLanes).none()) | |
| return; | |
| // Set UsedLanes and remember instruction for further propagation. | |
| MORegInfo.UsedLanes = PrevUsedLanes | UsedLanes; | |
| if (DefinedByCopy.test(MORegIdx)) | |
| PutInWorklist(MORegIdx); | |
| } | |
| void DetectDeadLanes::transferUsedLanesStep(const MachineInstr &MI, | |
| LaneBitmask UsedLanes) { | |
| for (const MachineOperand &MO : MI.uses()) { | |
| if (!MO.isReg() || !TargetRegisterInfo::isVirtualRegister(MO.getReg())) | |
| continue; | |
| LaneBitmask UsedOnMO = transferUsedLanes(MI, UsedLanes, MO); | |
| addUsedLanesOnOperand(MO, UsedOnMO); | |
| } | |
| } | |
| LaneBitmask DetectDeadLanes::transferUsedLanes(const MachineInstr &MI, | |
| LaneBitmask UsedLanes, | |
| const MachineOperand &MO) const { | |
| unsigned OpNum = MI.getOperandNo(&MO); | |
| assert(lowersToCopies(MI) && DefinedByCopy[ | |
| TargetRegisterInfo::virtReg2Index(MI.getOperand(0).getReg())]); | |
| switch (MI.getOpcode()) { | |
| case TargetOpcode::COPY: | |
| case TargetOpcode::PHI: | |
| return UsedLanes; | |
| case TargetOpcode::REG_SEQUENCE: { | |
| assert(OpNum % 2 == 1); | |
| unsigned SubIdx = MI.getOperand(OpNum + 1).getImm(); | |
| return TRI->reverseComposeSubRegIndexLaneMask(SubIdx, UsedLanes); | |
| } | |
| case TargetOpcode::INSERT_SUBREG: { | |
| unsigned SubIdx = MI.getOperand(3).getImm(); | |
| LaneBitmask MO2UsedLanes = | |
| TRI->reverseComposeSubRegIndexLaneMask(SubIdx, UsedLanes); | |
| if (OpNum == 2) | |
| return MO2UsedLanes; | |
| const MachineOperand &Def = MI.getOperand(0); | |
| unsigned DefReg = Def.getReg(); | |
| const TargetRegisterClass *RC = MRI->getRegClass(DefReg); | |
| LaneBitmask MO1UsedLanes; | |
| if (RC->CoveredBySubRegs) | |
| MO1UsedLanes = UsedLanes & ~TRI->getSubRegIndexLaneMask(SubIdx); | |
| else | |
| MO1UsedLanes = RC->LaneMask; | |
| assert(OpNum == 1); | |
| return MO1UsedLanes; | |
| } | |
| case TargetOpcode::EXTRACT_SUBREG: { | |
| assert(OpNum == 1); | |
| unsigned SubIdx = MI.getOperand(2).getImm(); | |
| return TRI->composeSubRegIndexLaneMask(SubIdx, UsedLanes); | |
| } | |
| default: | |
| llvm_unreachable("function must be called with COPY-like instruction"); | |
| } | |
| } | |
| void DetectDeadLanes::transferDefinedLanesStep(const MachineOperand &Use, | |
| LaneBitmask DefinedLanes) { | |
| if (!Use.readsReg()) | |
| return; | |
| // Check whether the operand writes a vreg and is part of a COPY-like | |
| // instruction. | |
| const MachineInstr &MI = *Use.getParent(); | |
| if (MI.getDesc().getNumDefs() != 1) | |
| return; | |
| // FIXME: PATCHPOINT instructions announce a Def that does not always exist, | |
| // they really need to be modeled differently! | |
| if (MI.getOpcode() == TargetOpcode::PATCHPOINT) | |
| return; | |
| const MachineOperand &Def = *MI.defs().begin(); | |
| unsigned DefReg = Def.getReg(); | |
| if (!TargetRegisterInfo::isVirtualRegister(DefReg)) | |
| return; | |
| unsigned DefRegIdx = TargetRegisterInfo::virtReg2Index(DefReg); | |
| if (!DefinedByCopy.test(DefRegIdx)) | |
| return; | |
| unsigned OpNum = MI.getOperandNo(&Use); | |
| DefinedLanes = | |
| TRI->reverseComposeSubRegIndexLaneMask(Use.getSubReg(), DefinedLanes); | |
| DefinedLanes = transferDefinedLanes(Def, OpNum, DefinedLanes); | |
| VRegInfo &RegInfo = VRegInfos[DefRegIdx]; | |
| LaneBitmask PrevDefinedLanes = RegInfo.DefinedLanes; | |
| // Any change at all? | |
| if ((DefinedLanes & ~PrevDefinedLanes).none()) | |
| return; | |
| RegInfo.DefinedLanes = PrevDefinedLanes | DefinedLanes; | |
| PutInWorklist(DefRegIdx); | |
| } | |
| LaneBitmask DetectDeadLanes::transferDefinedLanes(const MachineOperand &Def, | |
| unsigned OpNum, LaneBitmask DefinedLanes) const { | |
| const MachineInstr &MI = *Def.getParent(); | |
| // Translate DefinedLanes if necessary. | |
| switch (MI.getOpcode()) { | |
| case TargetOpcode::REG_SEQUENCE: { | |
| unsigned SubIdx = MI.getOperand(OpNum + 1).getImm(); | |
| DefinedLanes = TRI->composeSubRegIndexLaneMask(SubIdx, DefinedLanes); | |
| DefinedLanes &= TRI->getSubRegIndexLaneMask(SubIdx); | |
| break; | |
| } | |
| case TargetOpcode::INSERT_SUBREG: { | |
| unsigned SubIdx = MI.getOperand(3).getImm(); | |
| if (OpNum == 2) { | |
| DefinedLanes = TRI->composeSubRegIndexLaneMask(SubIdx, DefinedLanes); | |
| DefinedLanes &= TRI->getSubRegIndexLaneMask(SubIdx); | |
| } else { | |
| assert(OpNum == 1 && "INSERT_SUBREG must have two operands"); | |
| // Ignore lanes defined by operand 2. | |
| DefinedLanes &= ~TRI->getSubRegIndexLaneMask(SubIdx); | |
| } | |
| break; | |
| } | |
| case TargetOpcode::EXTRACT_SUBREG: { | |
| unsigned SubIdx = MI.getOperand(2).getImm(); | |
| assert(OpNum == 1 && "EXTRACT_SUBREG must have one register operand only"); | |
| DefinedLanes = TRI->reverseComposeSubRegIndexLaneMask(SubIdx, DefinedLanes); | |
| break; | |
| } | |
| case TargetOpcode::COPY: | |
| case TargetOpcode::PHI: | |
| break; | |
| default: | |
| llvm_unreachable("function must be called with COPY-like instruction"); | |
| } | |
| assert(Def.getSubReg() == 0 && | |
| "Should not have subregister defs in machine SSA phase"); | |
| DefinedLanes &= MRI->getMaxLaneMaskForVReg(Def.getReg()); | |
| return DefinedLanes; | |
| } | |
| LaneBitmask DetectDeadLanes::determineInitialDefinedLanes(unsigned Reg) { | |
| // Live-In or unused registers have no definition but are considered fully | |
| // defined. | |
| if (!MRI->hasOneDef(Reg)) | |
| return LaneBitmask::getAll(); | |
| const MachineOperand &Def = *MRI->def_begin(Reg); | |
| const MachineInstr &DefMI = *Def.getParent(); | |
| if (lowersToCopies(DefMI)) { | |
| // Start optimisatically with no used or defined lanes for copy | |
| // instructions. The following dataflow analysis will add more bits. | |
| unsigned RegIdx = TargetRegisterInfo::virtReg2Index(Reg); | |
| DefinedByCopy.set(RegIdx); | |
| PutInWorklist(RegIdx); | |
| if (Def.isDead()) | |
| return LaneBitmask::getNone(); | |
| // COPY/PHI can copy across unrelated register classes (example: float/int) | |
| // with incompatible subregister structure. Do not include these in the | |
| // dataflow analysis since we cannot transfer lanemasks in a meaningful way. | |
| const TargetRegisterClass *DefRC = MRI->getRegClass(Reg); | |
| // Determine initially DefinedLanes. | |
| LaneBitmask DefinedLanes; | |
| for (const MachineOperand &MO : DefMI.uses()) { | |
| if (!MO.isReg() || !MO.readsReg()) | |
| continue; | |
| unsigned MOReg = MO.getReg(); | |
| if (!MOReg) | |
| continue; | |
| LaneBitmask MODefinedLanes; | |
| if (TargetRegisterInfo::isPhysicalRegister(MOReg)) { | |
| MODefinedLanes = LaneBitmask::getAll(); | |
| } else if (isCrossCopy(*MRI, DefMI, DefRC, MO)) { | |
| MODefinedLanes = LaneBitmask::getAll(); | |
| } else { | |
| assert(TargetRegisterInfo::isVirtualRegister(MOReg)); | |
| if (MRI->hasOneDef(MOReg)) { | |
| const MachineOperand &MODef = *MRI->def_begin(MOReg); | |
| const MachineInstr &MODefMI = *MODef.getParent(); | |
| // Bits from copy-like operations will be added later. | |
| if (lowersToCopies(MODefMI) || MODefMI.isImplicitDef()) | |
| continue; | |
| } | |
| unsigned MOSubReg = MO.getSubReg(); | |
| MODefinedLanes = MRI->getMaxLaneMaskForVReg(MOReg); | |
| MODefinedLanes = TRI->reverseComposeSubRegIndexLaneMask( | |
| MOSubReg, MODefinedLanes); | |
| } | |
| unsigned OpNum = DefMI.getOperandNo(&MO); | |
| DefinedLanes |= transferDefinedLanes(Def, OpNum, MODefinedLanes); | |
| } | |
| return DefinedLanes; | |
| } | |
| if (DefMI.isImplicitDef() || Def.isDead()) | |
| return LaneBitmask::getNone(); | |
| assert(Def.getSubReg() == 0 && | |
| "Should not have subregister defs in machine SSA phase"); | |
| return MRI->getMaxLaneMaskForVReg(Reg); | |
| } | |
| LaneBitmask DetectDeadLanes::determineInitialUsedLanes(unsigned Reg) { | |
| LaneBitmask UsedLanes = LaneBitmask::getNone(); | |
| for (const MachineOperand &MO : MRI->use_nodbg_operands(Reg)) { | |
| if (!MO.readsReg()) | |
| continue; | |
| const MachineInstr &UseMI = *MO.getParent(); | |
| if (UseMI.isKill()) | |
| continue; | |
| unsigned SubReg = MO.getSubReg(); | |
| if (lowersToCopies(UseMI)) { | |
| assert(UseMI.getDesc().getNumDefs() == 1); | |
| const MachineOperand &Def = *UseMI.defs().begin(); | |
| unsigned DefReg = Def.getReg(); | |
| // The used lanes of COPY-like instruction operands are determined by the | |
| // following dataflow analysis. | |
| if (TargetRegisterInfo::isVirtualRegister(DefReg)) { | |
| // But ignore copies across incompatible register classes. | |
| bool CrossCopy = false; | |
| if (lowersToCopies(UseMI)) { | |
| const TargetRegisterClass *DstRC = MRI->getRegClass(DefReg); | |
| CrossCopy = isCrossCopy(*MRI, UseMI, DstRC, MO); | |
| if (CrossCopy) | |
| LLVM_DEBUG(dbgs() << "Copy across incompatible classes: " << UseMI); | |
| } | |
| if (!CrossCopy) | |
| continue; | |
| } | |
| } | |
| // Shortcut: All lanes are used. | |
| if (SubReg == 0) | |
| return MRI->getMaxLaneMaskForVReg(Reg); | |
| UsedLanes |= TRI->getSubRegIndexLaneMask(SubReg); | |
| } | |
| return UsedLanes; | |
| } | |
| bool DetectDeadLanes::isUndefRegAtInput(const MachineOperand &MO, | |
| const VRegInfo &RegInfo) const { | |
| unsigned SubReg = MO.getSubReg(); | |
| LaneBitmask Mask = TRI->getSubRegIndexLaneMask(SubReg); | |
| return (RegInfo.DefinedLanes & RegInfo.UsedLanes & Mask).none(); | |
| } | |
| bool DetectDeadLanes::isUndefInput(const MachineOperand &MO, | |
| bool *CrossCopy) const { | |
| if (!MO.isUse()) | |
| return false; | |
| const MachineInstr &MI = *MO.getParent(); | |
| if (!lowersToCopies(MI)) | |
| return false; | |
| const MachineOperand &Def = MI.getOperand(0); | |
| unsigned DefReg = Def.getReg(); | |
| if (!TargetRegisterInfo::isVirtualRegister(DefReg)) | |
| return false; | |
| unsigned DefRegIdx = TargetRegisterInfo::virtReg2Index(DefReg); | |
| if (!DefinedByCopy.test(DefRegIdx)) | |
| return false; | |
| const VRegInfo &DefRegInfo = VRegInfos[DefRegIdx]; | |
| LaneBitmask UsedLanes = transferUsedLanes(MI, DefRegInfo.UsedLanes, MO); | |
| if (UsedLanes.any()) | |
| return false; | |
| unsigned MOReg = MO.getReg(); | |
| if (TargetRegisterInfo::isVirtualRegister(MOReg)) { | |
| const TargetRegisterClass *DstRC = MRI->getRegClass(DefReg); | |
| *CrossCopy = isCrossCopy(*MRI, MI, DstRC, MO); | |
| } | |
| return true; | |
| } | |
| bool DetectDeadLanes::runOnce(MachineFunction &MF) { | |
| // First pass: Populate defs/uses of vregs with initial values | |
| unsigned NumVirtRegs = MRI->getNumVirtRegs(); | |
| for (unsigned RegIdx = 0; RegIdx < NumVirtRegs; ++RegIdx) { | |
| unsigned Reg = TargetRegisterInfo::index2VirtReg(RegIdx); | |
| // Determine used/defined lanes and add copy instructions to worklist. | |
| VRegInfo &Info = VRegInfos[RegIdx]; | |
| Info.DefinedLanes = determineInitialDefinedLanes(Reg); | |
| Info.UsedLanes = determineInitialUsedLanes(Reg); | |
| } | |
| // Iterate as long as defined lanes/used lanes keep changing. | |
| while (!Worklist.empty()) { | |
| unsigned RegIdx = Worklist.front(); | |
| Worklist.pop_front(); | |
| WorklistMembers.reset(RegIdx); | |
| VRegInfo &Info = VRegInfos[RegIdx]; | |
| unsigned Reg = TargetRegisterInfo::index2VirtReg(RegIdx); | |
| // Transfer UsedLanes to operands of DefMI (backwards dataflow). | |
| MachineOperand &Def = *MRI->def_begin(Reg); | |
| const MachineInstr &MI = *Def.getParent(); | |
| transferUsedLanesStep(MI, Info.UsedLanes); | |
| // Transfer DefinedLanes to users of Reg (forward dataflow). | |
| for (const MachineOperand &MO : MRI->use_nodbg_operands(Reg)) | |
| transferDefinedLanesStep(MO, Info.DefinedLanes); | |
| } | |
| LLVM_DEBUG(dbgs() << "Defined/Used lanes:\n"; for (unsigned RegIdx = 0; | |
| RegIdx < NumVirtRegs; | |
| ++RegIdx) { | |
| unsigned Reg = TargetRegisterInfo::index2VirtReg(RegIdx); | |
| const VRegInfo &Info = VRegInfos[RegIdx]; | |
| dbgs() << printReg(Reg, nullptr) | |
| << " Used: " << PrintLaneMask(Info.UsedLanes) | |
| << " Def: " << PrintLaneMask(Info.DefinedLanes) << '\n'; | |
| } dbgs() << "\n";); | |
| bool Again = false; | |
| // Mark operands as dead/unused. | |
| for (MachineBasicBlock &MBB : MF) { | |
| for (MachineInstr &MI : MBB) { | |
| for (MachineOperand &MO : MI.operands()) { | |
| if (!MO.isReg()) | |
| continue; | |
| unsigned Reg = MO.getReg(); | |
| if (!TargetRegisterInfo::isVirtualRegister(Reg)) | |
| continue; | |
| unsigned RegIdx = TargetRegisterInfo::virtReg2Index(Reg); | |
| const VRegInfo &RegInfo = VRegInfos[RegIdx]; | |
| if (MO.isDef() && !MO.isDead() && RegInfo.UsedLanes.none()) { | |
| LLVM_DEBUG(dbgs() | |
| << "Marking operand '" << MO << "' as dead in " << MI); | |
| MO.setIsDead(); | |
| } | |
| if (MO.readsReg()) { | |
| bool CrossCopy = false; | |
| if (isUndefRegAtInput(MO, RegInfo)) { | |
| LLVM_DEBUG(dbgs() | |
| << "Marking operand '" << MO << "' as undef in " << MI); | |
| MO.setIsUndef(); | |
| } else if (isUndefInput(MO, &CrossCopy)) { | |
| LLVM_DEBUG(dbgs() | |
| << "Marking operand '" << MO << "' as undef in " << MI); | |
| MO.setIsUndef(); | |
| if (CrossCopy) | |
| Again = true; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return Again; | |
| } | |
| bool DetectDeadLanes::runOnMachineFunction(MachineFunction &MF) { | |
| // Don't bother if we won't track subregister liveness later. This pass is | |
| // required for correctness if subregister liveness is enabled because the | |
| // register coalescer cannot deal with hidden dead defs. However without | |
| // subregister liveness enabled, the expected benefits of this pass are small | |
| // so we safe the compile time. | |
| MRI = &MF.getRegInfo(); | |
| if (!MRI->subRegLivenessEnabled()) { | |
| LLVM_DEBUG(dbgs() << "Skipping Detect dead lanes pass\n"); | |
| return false; | |
| } | |
| TRI = MRI->getTargetRegisterInfo(); | |
| unsigned NumVirtRegs = MRI->getNumVirtRegs(); | |
| VRegInfos = new VRegInfo[NumVirtRegs]; | |
| WorklistMembers.resize(NumVirtRegs); | |
| DefinedByCopy.resize(NumVirtRegs); | |
| bool Again; | |
| do { | |
| Again = runOnce(MF); | |
| } while(Again); | |
| DefinedByCopy.clear(); | |
| WorklistMembers.clear(); | |
| delete[] VRegInfos; | |
| return true; | |
| } |