| //===- DetectDeadLanes.cpp - SubRegister Lane Usage Analysis --*- C++ -*---===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| /// \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 "llvm/ADT/BitVector.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" |
| #include <deque> |
| |
| 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)); |
| Register 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; |
| Register MOReg = MO.getReg(); |
| if (!Register::isVirtualRegister(MOReg)) |
| return; |
| |
| unsigned MOSubReg = MO.getSubReg(); |
| if (MOSubReg != 0) |
| UsedLanes = TRI->composeSubRegIndexLaneMask(MOSubReg, UsedLanes); |
| UsedLanes &= MRI->getMaxLaneMaskForVReg(MOReg); |
| |
| unsigned MORegIdx = Register::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() || !Register::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[Register::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); |
| Register 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(); |
| Register DefReg = Def.getReg(); |
| if (!Register::isVirtualRegister(DefReg)) |
| return; |
| unsigned DefRegIdx = Register::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 = Register::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; |
| Register MOReg = MO.getReg(); |
| if (!MOReg) |
| continue; |
| |
| LaneBitmask MODefinedLanes; |
| if (Register::isPhysicalRegister(MOReg)) { |
| MODefinedLanes = LaneBitmask::getAll(); |
| } else if (isCrossCopy(*MRI, DefMI, DefRC, MO)) { |
| MODefinedLanes = LaneBitmask::getAll(); |
| } else { |
| assert(Register::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(); |
| Register DefReg = Def.getReg(); |
| // The used lanes of COPY-like instruction operands are determined by the |
| // following dataflow analysis. |
| if (Register::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); |
| Register DefReg = Def.getReg(); |
| if (!Register::isVirtualRegister(DefReg)) |
| return false; |
| unsigned DefRegIdx = Register::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; |
| |
| Register MOReg = MO.getReg(); |
| if (Register::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 = Register::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 = Register::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 = Register::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; |
| Register Reg = MO.getReg(); |
| if (!Register::isVirtualRegister(Reg)) |
| continue; |
| unsigned RegIdx = Register::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; |
| } |