|  | //===- 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/CodeGen/DetectDeadLanes.h" | 
|  | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  | #include "llvm/CodeGen/TargetRegisterInfo.h" | 
|  | #include "llvm/InitializePasses.h" | 
|  | #include "llvm/Pass.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "detect-dead-lanes" | 
|  |  | 
|  | DeadLaneDetector::DeadLaneDetector(const MachineRegisterInfo *MRI, | 
|  | const TargetRegisterInfo *TRI) | 
|  | : MRI(MRI), TRI(TRI) { | 
|  | unsigned NumVirtRegs = MRI->getNumVirtRegs(); | 
|  | VRegInfos = std::unique_ptr<VRegInfo[]>(new VRegInfo[NumVirtRegs]); | 
|  | WorklistMembers.resize(NumVirtRegs); | 
|  | DefinedByCopy.resize(NumVirtRegs); | 
|  | } | 
|  |  | 
|  | /// 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 (MO.getOperandNo() == 2) | 
|  | DstSubIdx = MI.getOperand(3).getImm(); | 
|  | break; | 
|  | case TargetOpcode::REG_SEQUENCE: { | 
|  | unsigned OpNum = MO.getOperandNo(); | 
|  | 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 DeadLaneDetector::addUsedLanesOnOperand(const MachineOperand &MO, | 
|  | LaneBitmask UsedLanes) { | 
|  | if (!MO.readsReg()) | 
|  | return; | 
|  | Register MOReg = MO.getReg(); | 
|  | if (!MOReg.isVirtual()) | 
|  | return; | 
|  |  | 
|  | unsigned MOSubReg = MO.getSubReg(); | 
|  | if (MOSubReg != 0) | 
|  | UsedLanes = TRI->composeSubRegIndexLaneMask(MOSubReg, UsedLanes); | 
|  | UsedLanes &= MRI->getMaxLaneMaskForVReg(MOReg); | 
|  |  | 
|  | unsigned MORegIdx = Register::virtReg2Index(MOReg); | 
|  | DeadLaneDetector::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 DeadLaneDetector::transferUsedLanesStep(const MachineInstr &MI, | 
|  | LaneBitmask UsedLanes) { | 
|  | for (const MachineOperand &MO : MI.uses()) { | 
|  | if (!MO.isReg() || !MO.getReg().isVirtual()) | 
|  | continue; | 
|  | LaneBitmask UsedOnMO = transferUsedLanes(MI, UsedLanes, MO); | 
|  | addUsedLanesOnOperand(MO, UsedOnMO); | 
|  | } | 
|  | } | 
|  |  | 
|  | LaneBitmask | 
|  | DeadLaneDetector::transferUsedLanes(const MachineInstr &MI, | 
|  | LaneBitmask UsedLanes, | 
|  | const MachineOperand &MO) const { | 
|  | unsigned OpNum = MO.getOperandNo(); | 
|  | 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 DeadLaneDetector::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 (!DefReg.isVirtual()) | 
|  | return; | 
|  | unsigned DefRegIdx = Register::virtReg2Index(DefReg); | 
|  | if (!DefinedByCopy.test(DefRegIdx)) | 
|  | return; | 
|  |  | 
|  | unsigned OpNum = Use.getOperandNo(); | 
|  | 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 DeadLaneDetector::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 DeadLaneDetector::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 (MOReg.isPhysical()) { | 
|  | MODefinedLanes = LaneBitmask::getAll(); | 
|  | } else if (isCrossCopy(*MRI, DefMI, DefRC, MO)) { | 
|  | MODefinedLanes = LaneBitmask::getAll(); | 
|  | } else { | 
|  | assert(MOReg.isVirtual()); | 
|  | 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 = MO.getOperandNo(); | 
|  | 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 DeadLaneDetector::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 (DefReg.isVirtual()) { | 
|  | // 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; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | 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: | 
|  | /// update the operand status. | 
|  | /// The first return value shows whether MF been changed. | 
|  | /// The second return value indicates we need to call | 
|  | /// DeadLaneDetector::computeSubRegisterLaneBitInfo and this function again | 
|  | /// to propagate changes. | 
|  | std::pair<bool, bool> | 
|  | modifySubRegisterOperandStatus(const DeadLaneDetector &DLD, | 
|  | MachineFunction &MF); | 
|  |  | 
|  | bool isUndefRegAtInput(const MachineOperand &MO, | 
|  | const DeadLaneDetector::VRegInfo &RegInfo) const; | 
|  |  | 
|  | bool isUndefInput(const DeadLaneDetector &DLD, const MachineOperand &MO, | 
|  | bool *CrossCopy) const; | 
|  |  | 
|  | const MachineRegisterInfo *MRI = nullptr; | 
|  | const TargetRegisterInfo *TRI = nullptr; | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | char DetectDeadLanes::ID = 0; | 
|  | char &llvm::DetectDeadLanesID = DetectDeadLanes::ID; | 
|  |  | 
|  | INITIALIZE_PASS(DetectDeadLanes, DEBUG_TYPE, "Detect Dead Lanes", false, false) | 
|  |  | 
|  | bool DetectDeadLanes::isUndefRegAtInput( | 
|  | const MachineOperand &MO, const DeadLaneDetector::VRegInfo &RegInfo) const { | 
|  | unsigned SubReg = MO.getSubReg(); | 
|  | LaneBitmask Mask = TRI->getSubRegIndexLaneMask(SubReg); | 
|  | return (RegInfo.DefinedLanes & RegInfo.UsedLanes & Mask).none(); | 
|  | } | 
|  |  | 
|  | bool DetectDeadLanes::isUndefInput(const DeadLaneDetector &DLD, | 
|  | 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 (!DefReg.isVirtual()) | 
|  | return false; | 
|  | unsigned DefRegIdx = Register::virtReg2Index(DefReg); | 
|  | if (!DLD.isDefinedByCopy(DefRegIdx)) | 
|  | return false; | 
|  |  | 
|  | const DeadLaneDetector::VRegInfo &DefRegInfo = DLD.getVRegInfo(DefRegIdx); | 
|  | LaneBitmask UsedLanes = DLD.transferUsedLanes(MI, DefRegInfo.UsedLanes, MO); | 
|  | if (UsedLanes.any()) | 
|  | return false; | 
|  |  | 
|  | Register MOReg = MO.getReg(); | 
|  | if (MOReg.isVirtual()) { | 
|  | const TargetRegisterClass *DstRC = MRI->getRegClass(DefReg); | 
|  | *CrossCopy = isCrossCopy(*MRI, MI, DstRC, MO); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void DeadLaneDetector::computeSubRegisterLaneBitInfo() { | 
|  | // First pass: Populate defs/uses of vregs with initial values | 
|  | unsigned NumVirtRegs = MRI->getNumVirtRegs(); | 
|  | for (unsigned RegIdx = 0; RegIdx < NumVirtRegs; ++RegIdx) { | 
|  | Register 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]; | 
|  | Register 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) { | 
|  | Register Reg = Register::index2VirtReg(RegIdx); | 
|  | const VRegInfo &Info = VRegInfos[RegIdx]; | 
|  | dbgs() << printReg(Reg, nullptr) | 
|  | << " Used: " << PrintLaneMask(Info.UsedLanes) | 
|  | << " Def: " << PrintLaneMask(Info.DefinedLanes) << '\n'; | 
|  | } | 
|  | dbgs() << "\n"; | 
|  | }); | 
|  | } | 
|  |  | 
|  | std::pair<bool, bool> | 
|  | DetectDeadLanes::modifySubRegisterOperandStatus(const DeadLaneDetector &DLD, | 
|  | MachineFunction &MF) { | 
|  | bool Changed = false; | 
|  | 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 (!Reg.isVirtual()) | 
|  | continue; | 
|  | unsigned RegIdx = Register::virtReg2Index(Reg); | 
|  | const DeadLaneDetector::VRegInfo &RegInfo = DLD.getVRegInfo(RegIdx); | 
|  | if (MO.isDef() && !MO.isDead() && RegInfo.UsedLanes.none()) { | 
|  | LLVM_DEBUG(dbgs() | 
|  | << "Marking operand '" << MO << "' as dead in " << MI); | 
|  | MO.setIsDead(); | 
|  | Changed = true; | 
|  | } | 
|  | if (MO.readsReg()) { | 
|  | bool CrossCopy = false; | 
|  | if (isUndefRegAtInput(MO, RegInfo)) { | 
|  | LLVM_DEBUG(dbgs() | 
|  | << "Marking operand '" << MO << "' as undef in " << MI); | 
|  | MO.setIsUndef(); | 
|  | Changed = true; | 
|  | } else if (isUndefInput(DLD, MO, &CrossCopy)) { | 
|  | LLVM_DEBUG(dbgs() | 
|  | << "Marking operand '" << MO << "' as undef in " << MI); | 
|  | MO.setIsUndef(); | 
|  | Changed = true; | 
|  | if (CrossCopy) | 
|  | Again = true; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return std::make_pair(Changed, 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(); | 
|  |  | 
|  | DeadLaneDetector DLD(MRI, TRI); | 
|  |  | 
|  | bool Changed = false; | 
|  | bool Again; | 
|  | do { | 
|  | DLD.computeSubRegisterLaneBitInfo(); | 
|  | bool LocalChanged; | 
|  | std::tie(LocalChanged, Again) = modifySubRegisterOperandStatus(DLD, MF); | 
|  | Changed |= LocalChanged; | 
|  | } while (Again); | 
|  |  | 
|  | return Changed; | 
|  | } |