| //===- 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; | 
 | } |