xref: /src/contrib/llvm-project/llvm/lib/CodeGen/DetectDeadLanes.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
101095a5dSDimitry Andric //===- DetectDeadLanes.cpp - SubRegister Lane Usage Analysis --*- C++ -*---===//
201095a5dSDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
601095a5dSDimitry Andric //
701095a5dSDimitry Andric //===----------------------------------------------------------------------===//
801095a5dSDimitry Andric //
901095a5dSDimitry Andric /// \file
1001095a5dSDimitry Andric /// Analysis that tracks defined/used subregister lanes across COPY instructions
1101095a5dSDimitry Andric /// and instructions that get lowered to a COPY (PHI, REG_SEQUENCE,
1201095a5dSDimitry Andric /// INSERT_SUBREG, EXTRACT_SUBREG).
1301095a5dSDimitry Andric /// The information is used to detect dead definitions and the usage of
1401095a5dSDimitry Andric /// (completely) undefined values and mark the operands as such.
1501095a5dSDimitry Andric /// This pass is necessary because the dead/undef status is not obvious anymore
1601095a5dSDimitry Andric /// when subregisters are involved.
1701095a5dSDimitry Andric ///
1801095a5dSDimitry Andric /// Example:
19044eb2f6SDimitry Andric ///    %0 = some definition
20044eb2f6SDimitry Andric ///    %1 = IMPLICIT_DEF
21044eb2f6SDimitry Andric ///    %2 = REG_SEQUENCE %0, sub0, %1, sub1
22044eb2f6SDimitry Andric ///    %3 = EXTRACT_SUBREG %2, sub1
23044eb2f6SDimitry Andric ///       = use %3
24044eb2f6SDimitry Andric /// The %0 definition is dead and %3 contains an undefined value.
2501095a5dSDimitry Andric //
2601095a5dSDimitry Andric //===----------------------------------------------------------------------===//
2701095a5dSDimitry Andric 
287fa27ce4SDimitry Andric #include "llvm/CodeGen/DetectDeadLanes.h"
2901095a5dSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
3001095a5dSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
31044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
3201095a5dSDimitry Andric #include "llvm/InitializePasses.h"
3301095a5dSDimitry Andric #include "llvm/Pass.h"
3401095a5dSDimitry Andric #include "llvm/Support/Debug.h"
3501095a5dSDimitry Andric #include "llvm/Support/raw_ostream.h"
3601095a5dSDimitry Andric 
3701095a5dSDimitry Andric using namespace llvm;
3801095a5dSDimitry Andric 
3901095a5dSDimitry Andric #define DEBUG_TYPE "detect-dead-lanes"
4001095a5dSDimitry Andric 
DeadLaneDetector(const MachineRegisterInfo * MRI,const TargetRegisterInfo * TRI)417fa27ce4SDimitry Andric DeadLaneDetector::DeadLaneDetector(const MachineRegisterInfo *MRI,
427fa27ce4SDimitry Andric                                    const TargetRegisterInfo *TRI)
437fa27ce4SDimitry Andric     : MRI(MRI), TRI(TRI) {
447fa27ce4SDimitry Andric   unsigned NumVirtRegs = MRI->getNumVirtRegs();
457fa27ce4SDimitry Andric   VRegInfos = std::unique_ptr<VRegInfo[]>(new VRegInfo[NumVirtRegs]);
467fa27ce4SDimitry Andric   WorklistMembers.resize(NumVirtRegs);
477fa27ce4SDimitry Andric   DefinedByCopy.resize(NumVirtRegs);
4801095a5dSDimitry Andric }
4901095a5dSDimitry Andric 
5001095a5dSDimitry Andric /// Returns true if \p MI will get lowered to a series of COPY instructions.
5101095a5dSDimitry Andric /// We call this a COPY-like instruction.
lowersToCopies(const MachineInstr & MI)5201095a5dSDimitry Andric static bool lowersToCopies(const MachineInstr &MI) {
5301095a5dSDimitry Andric   // Note: We could support instructions with MCInstrDesc::isRegSequenceLike(),
5401095a5dSDimitry Andric   // isExtractSubRegLike(), isInsertSubregLike() in the future even though they
5501095a5dSDimitry Andric   // are not lowered to a COPY.
5601095a5dSDimitry Andric   switch (MI.getOpcode()) {
5701095a5dSDimitry Andric   case TargetOpcode::COPY:
5801095a5dSDimitry Andric   case TargetOpcode::PHI:
5901095a5dSDimitry Andric   case TargetOpcode::INSERT_SUBREG:
6001095a5dSDimitry Andric   case TargetOpcode::REG_SEQUENCE:
6101095a5dSDimitry Andric   case TargetOpcode::EXTRACT_SUBREG:
6201095a5dSDimitry Andric     return true;
6301095a5dSDimitry Andric   }
6401095a5dSDimitry Andric   return false;
6501095a5dSDimitry Andric }
6601095a5dSDimitry Andric 
isCrossCopy(const MachineRegisterInfo & MRI,const MachineInstr & MI,const TargetRegisterClass * DstRC,const MachineOperand & MO)6701095a5dSDimitry Andric static bool isCrossCopy(const MachineRegisterInfo &MRI,
6801095a5dSDimitry Andric                         const MachineInstr &MI,
6901095a5dSDimitry Andric                         const TargetRegisterClass *DstRC,
7001095a5dSDimitry Andric                         const MachineOperand &MO) {
7101095a5dSDimitry Andric   assert(lowersToCopies(MI));
721d5ae102SDimitry Andric   Register SrcReg = MO.getReg();
7301095a5dSDimitry Andric   const TargetRegisterClass *SrcRC = MRI.getRegClass(SrcReg);
7401095a5dSDimitry Andric   if (DstRC == SrcRC)
7501095a5dSDimitry Andric     return false;
7601095a5dSDimitry Andric 
7701095a5dSDimitry Andric   unsigned SrcSubIdx = MO.getSubReg();
7801095a5dSDimitry Andric 
7901095a5dSDimitry Andric   const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
8001095a5dSDimitry Andric   unsigned DstSubIdx = 0;
8101095a5dSDimitry Andric   switch (MI.getOpcode()) {
8201095a5dSDimitry Andric   case TargetOpcode::INSERT_SUBREG:
837fa27ce4SDimitry Andric     if (MO.getOperandNo() == 2)
8401095a5dSDimitry Andric       DstSubIdx = MI.getOperand(3).getImm();
8501095a5dSDimitry Andric     break;
8601095a5dSDimitry Andric   case TargetOpcode::REG_SEQUENCE: {
877fa27ce4SDimitry Andric     unsigned OpNum = MO.getOperandNo();
8801095a5dSDimitry Andric     DstSubIdx = MI.getOperand(OpNum+1).getImm();
8901095a5dSDimitry Andric     break;
9001095a5dSDimitry Andric   }
9101095a5dSDimitry Andric   case TargetOpcode::EXTRACT_SUBREG: {
9201095a5dSDimitry Andric     unsigned SubReg = MI.getOperand(2).getImm();
9301095a5dSDimitry Andric     SrcSubIdx = TRI.composeSubRegIndices(SubReg, SrcSubIdx);
9401095a5dSDimitry Andric   }
9501095a5dSDimitry Andric   }
9601095a5dSDimitry Andric 
9701095a5dSDimitry Andric   unsigned PreA, PreB; // Unused.
9801095a5dSDimitry Andric   if (SrcSubIdx && DstSubIdx)
9901095a5dSDimitry Andric     return !TRI.getCommonSuperRegClass(SrcRC, SrcSubIdx, DstRC, DstSubIdx, PreA,
10001095a5dSDimitry Andric                                        PreB);
10101095a5dSDimitry Andric   if (SrcSubIdx)
10201095a5dSDimitry Andric     return !TRI.getMatchingSuperRegClass(SrcRC, DstRC, SrcSubIdx);
10301095a5dSDimitry Andric   if (DstSubIdx)
10401095a5dSDimitry Andric     return !TRI.getMatchingSuperRegClass(DstRC, SrcRC, DstSubIdx);
10501095a5dSDimitry Andric   return !TRI.getCommonSubClass(SrcRC, DstRC);
10601095a5dSDimitry Andric }
10701095a5dSDimitry Andric 
addUsedLanesOnOperand(const MachineOperand & MO,LaneBitmask UsedLanes)1087fa27ce4SDimitry Andric void DeadLaneDetector::addUsedLanesOnOperand(const MachineOperand &MO,
10901095a5dSDimitry Andric                                              LaneBitmask UsedLanes) {
11001095a5dSDimitry Andric   if (!MO.readsReg())
11101095a5dSDimitry Andric     return;
1121d5ae102SDimitry Andric   Register MOReg = MO.getReg();
113e3b55780SDimitry Andric   if (!MOReg.isVirtual())
11401095a5dSDimitry Andric     return;
11501095a5dSDimitry Andric 
11601095a5dSDimitry Andric   unsigned MOSubReg = MO.getSubReg();
11701095a5dSDimitry Andric   if (MOSubReg != 0)
11801095a5dSDimitry Andric     UsedLanes = TRI->composeSubRegIndexLaneMask(MOSubReg, UsedLanes);
11901095a5dSDimitry Andric   UsedLanes &= MRI->getMaxLaneMaskForVReg(MOReg);
12001095a5dSDimitry Andric 
1211d5ae102SDimitry Andric   unsigned MORegIdx = Register::virtReg2Index(MOReg);
1227fa27ce4SDimitry Andric   DeadLaneDetector::VRegInfo &MORegInfo = VRegInfos[MORegIdx];
12301095a5dSDimitry Andric   LaneBitmask PrevUsedLanes = MORegInfo.UsedLanes;
12401095a5dSDimitry Andric   // Any change at all?
125b915e9e0SDimitry Andric   if ((UsedLanes & ~PrevUsedLanes).none())
12601095a5dSDimitry Andric     return;
12701095a5dSDimitry Andric 
12801095a5dSDimitry Andric   // Set UsedLanes and remember instruction for further propagation.
12901095a5dSDimitry Andric   MORegInfo.UsedLanes = PrevUsedLanes | UsedLanes;
13001095a5dSDimitry Andric   if (DefinedByCopy.test(MORegIdx))
13101095a5dSDimitry Andric     PutInWorklist(MORegIdx);
13201095a5dSDimitry Andric }
13301095a5dSDimitry Andric 
transferUsedLanesStep(const MachineInstr & MI,LaneBitmask UsedLanes)1347fa27ce4SDimitry Andric void DeadLaneDetector::transferUsedLanesStep(const MachineInstr &MI,
13501095a5dSDimitry Andric                                              LaneBitmask UsedLanes) {
13601095a5dSDimitry Andric   for (const MachineOperand &MO : MI.uses()) {
137e3b55780SDimitry Andric     if (!MO.isReg() || !MO.getReg().isVirtual())
13801095a5dSDimitry Andric       continue;
13901095a5dSDimitry Andric     LaneBitmask UsedOnMO = transferUsedLanes(MI, UsedLanes, MO);
14001095a5dSDimitry Andric     addUsedLanesOnOperand(MO, UsedOnMO);
14101095a5dSDimitry Andric   }
14201095a5dSDimitry Andric }
14301095a5dSDimitry Andric 
1447fa27ce4SDimitry Andric LaneBitmask
transferUsedLanes(const MachineInstr & MI,LaneBitmask UsedLanes,const MachineOperand & MO) const1457fa27ce4SDimitry Andric DeadLaneDetector::transferUsedLanes(const MachineInstr &MI,
14601095a5dSDimitry Andric                                     LaneBitmask UsedLanes,
14701095a5dSDimitry Andric                                     const MachineOperand &MO) const {
1487fa27ce4SDimitry Andric   unsigned OpNum = MO.getOperandNo();
1491d5ae102SDimitry Andric   assert(lowersToCopies(MI) &&
1501d5ae102SDimitry Andric          DefinedByCopy[Register::virtReg2Index(MI.getOperand(0).getReg())]);
15101095a5dSDimitry Andric 
15201095a5dSDimitry Andric   switch (MI.getOpcode()) {
15301095a5dSDimitry Andric   case TargetOpcode::COPY:
15401095a5dSDimitry Andric   case TargetOpcode::PHI:
15501095a5dSDimitry Andric     return UsedLanes;
15601095a5dSDimitry Andric   case TargetOpcode::REG_SEQUENCE: {
15701095a5dSDimitry Andric     assert(OpNum % 2 == 1);
15801095a5dSDimitry Andric     unsigned SubIdx = MI.getOperand(OpNum + 1).getImm();
15901095a5dSDimitry Andric     return TRI->reverseComposeSubRegIndexLaneMask(SubIdx, UsedLanes);
16001095a5dSDimitry Andric   }
16101095a5dSDimitry Andric   case TargetOpcode::INSERT_SUBREG: {
16201095a5dSDimitry Andric     unsigned SubIdx = MI.getOperand(3).getImm();
16301095a5dSDimitry Andric     LaneBitmask MO2UsedLanes =
16401095a5dSDimitry Andric         TRI->reverseComposeSubRegIndexLaneMask(SubIdx, UsedLanes);
16501095a5dSDimitry Andric     if (OpNum == 2)
16601095a5dSDimitry Andric       return MO2UsedLanes;
16701095a5dSDimitry Andric 
16801095a5dSDimitry Andric     const MachineOperand &Def = MI.getOperand(0);
1691d5ae102SDimitry Andric     Register DefReg = Def.getReg();
17001095a5dSDimitry Andric     const TargetRegisterClass *RC = MRI->getRegClass(DefReg);
17101095a5dSDimitry Andric     LaneBitmask MO1UsedLanes;
17201095a5dSDimitry Andric     if (RC->CoveredBySubRegs)
17301095a5dSDimitry Andric       MO1UsedLanes = UsedLanes & ~TRI->getSubRegIndexLaneMask(SubIdx);
17401095a5dSDimitry Andric     else
17501095a5dSDimitry Andric       MO1UsedLanes = RC->LaneMask;
17601095a5dSDimitry Andric 
17701095a5dSDimitry Andric     assert(OpNum == 1);
17801095a5dSDimitry Andric     return MO1UsedLanes;
17901095a5dSDimitry Andric   }
18001095a5dSDimitry Andric   case TargetOpcode::EXTRACT_SUBREG: {
18101095a5dSDimitry Andric     assert(OpNum == 1);
18201095a5dSDimitry Andric     unsigned SubIdx = MI.getOperand(2).getImm();
18301095a5dSDimitry Andric     return TRI->composeSubRegIndexLaneMask(SubIdx, UsedLanes);
18401095a5dSDimitry Andric   }
18501095a5dSDimitry Andric   default:
18601095a5dSDimitry Andric     llvm_unreachable("function must be called with COPY-like instruction");
18701095a5dSDimitry Andric   }
18801095a5dSDimitry Andric }
18901095a5dSDimitry Andric 
transferDefinedLanesStep(const MachineOperand & Use,LaneBitmask DefinedLanes)1907fa27ce4SDimitry Andric void DeadLaneDetector::transferDefinedLanesStep(const MachineOperand &Use,
19101095a5dSDimitry Andric                                                 LaneBitmask DefinedLanes) {
19201095a5dSDimitry Andric   if (!Use.readsReg())
19301095a5dSDimitry Andric     return;
19401095a5dSDimitry Andric   // Check whether the operand writes a vreg and is part of a COPY-like
19501095a5dSDimitry Andric   // instruction.
19601095a5dSDimitry Andric   const MachineInstr &MI = *Use.getParent();
19701095a5dSDimitry Andric   if (MI.getDesc().getNumDefs() != 1)
19801095a5dSDimitry Andric     return;
19901095a5dSDimitry Andric   // FIXME: PATCHPOINT instructions announce a Def that does not always exist,
20001095a5dSDimitry Andric   // they really need to be modeled differently!
20101095a5dSDimitry Andric   if (MI.getOpcode() == TargetOpcode::PATCHPOINT)
20201095a5dSDimitry Andric     return;
20301095a5dSDimitry Andric   const MachineOperand &Def = *MI.defs().begin();
2041d5ae102SDimitry Andric   Register DefReg = Def.getReg();
205e3b55780SDimitry Andric   if (!DefReg.isVirtual())
20601095a5dSDimitry Andric     return;
2071d5ae102SDimitry Andric   unsigned DefRegIdx = Register::virtReg2Index(DefReg);
20801095a5dSDimitry Andric   if (!DefinedByCopy.test(DefRegIdx))
20901095a5dSDimitry Andric     return;
21001095a5dSDimitry Andric 
2117fa27ce4SDimitry Andric   unsigned OpNum = Use.getOperandNo();
21201095a5dSDimitry Andric   DefinedLanes =
21301095a5dSDimitry Andric       TRI->reverseComposeSubRegIndexLaneMask(Use.getSubReg(), DefinedLanes);
21401095a5dSDimitry Andric   DefinedLanes = transferDefinedLanes(Def, OpNum, DefinedLanes);
21501095a5dSDimitry Andric 
21601095a5dSDimitry Andric   VRegInfo &RegInfo = VRegInfos[DefRegIdx];
21701095a5dSDimitry Andric   LaneBitmask PrevDefinedLanes = RegInfo.DefinedLanes;
21801095a5dSDimitry Andric   // Any change at all?
219b915e9e0SDimitry Andric   if ((DefinedLanes & ~PrevDefinedLanes).none())
22001095a5dSDimitry Andric     return;
22101095a5dSDimitry Andric 
22201095a5dSDimitry Andric   RegInfo.DefinedLanes = PrevDefinedLanes | DefinedLanes;
22301095a5dSDimitry Andric   PutInWorklist(DefRegIdx);
22401095a5dSDimitry Andric }
22501095a5dSDimitry Andric 
transferDefinedLanes(const MachineOperand & Def,unsigned OpNum,LaneBitmask DefinedLanes) const2267fa27ce4SDimitry Andric LaneBitmask DeadLaneDetector::transferDefinedLanes(
2277fa27ce4SDimitry Andric     const MachineOperand &Def, unsigned OpNum, LaneBitmask DefinedLanes) const {
22801095a5dSDimitry Andric   const MachineInstr &MI = *Def.getParent();
22901095a5dSDimitry Andric   // Translate DefinedLanes if necessary.
23001095a5dSDimitry Andric   switch (MI.getOpcode()) {
23101095a5dSDimitry Andric   case TargetOpcode::REG_SEQUENCE: {
23201095a5dSDimitry Andric     unsigned SubIdx = MI.getOperand(OpNum + 1).getImm();
23301095a5dSDimitry Andric     DefinedLanes = TRI->composeSubRegIndexLaneMask(SubIdx, DefinedLanes);
23401095a5dSDimitry Andric     DefinedLanes &= TRI->getSubRegIndexLaneMask(SubIdx);
23501095a5dSDimitry Andric     break;
23601095a5dSDimitry Andric   }
23701095a5dSDimitry Andric   case TargetOpcode::INSERT_SUBREG: {
23801095a5dSDimitry Andric     unsigned SubIdx = MI.getOperand(3).getImm();
23901095a5dSDimitry Andric     if (OpNum == 2) {
24001095a5dSDimitry Andric       DefinedLanes = TRI->composeSubRegIndexLaneMask(SubIdx, DefinedLanes);
24101095a5dSDimitry Andric       DefinedLanes &= TRI->getSubRegIndexLaneMask(SubIdx);
24201095a5dSDimitry Andric     } else {
24301095a5dSDimitry Andric       assert(OpNum == 1 && "INSERT_SUBREG must have two operands");
24401095a5dSDimitry Andric       // Ignore lanes defined by operand 2.
24501095a5dSDimitry Andric       DefinedLanes &= ~TRI->getSubRegIndexLaneMask(SubIdx);
24601095a5dSDimitry Andric     }
24701095a5dSDimitry Andric     break;
24801095a5dSDimitry Andric   }
24901095a5dSDimitry Andric   case TargetOpcode::EXTRACT_SUBREG: {
25001095a5dSDimitry Andric     unsigned SubIdx = MI.getOperand(2).getImm();
25101095a5dSDimitry Andric     assert(OpNum == 1 && "EXTRACT_SUBREG must have one register operand only");
25201095a5dSDimitry Andric     DefinedLanes = TRI->reverseComposeSubRegIndexLaneMask(SubIdx, DefinedLanes);
25301095a5dSDimitry Andric     break;
25401095a5dSDimitry Andric   }
25501095a5dSDimitry Andric   case TargetOpcode::COPY:
25601095a5dSDimitry Andric   case TargetOpcode::PHI:
25701095a5dSDimitry Andric     break;
25801095a5dSDimitry Andric   default:
25901095a5dSDimitry Andric     llvm_unreachable("function must be called with COPY-like instruction");
26001095a5dSDimitry Andric   }
26101095a5dSDimitry Andric 
26201095a5dSDimitry Andric   assert(Def.getSubReg() == 0 &&
26301095a5dSDimitry Andric          "Should not have subregister defs in machine SSA phase");
26401095a5dSDimitry Andric   DefinedLanes &= MRI->getMaxLaneMaskForVReg(Def.getReg());
26501095a5dSDimitry Andric   return DefinedLanes;
26601095a5dSDimitry Andric }
26701095a5dSDimitry Andric 
determineInitialDefinedLanes(unsigned Reg)2687fa27ce4SDimitry Andric LaneBitmask DeadLaneDetector::determineInitialDefinedLanes(unsigned Reg) {
26901095a5dSDimitry Andric   // Live-In or unused registers have no definition but are considered fully
27001095a5dSDimitry Andric   // defined.
27101095a5dSDimitry Andric   if (!MRI->hasOneDef(Reg))
272b915e9e0SDimitry Andric     return LaneBitmask::getAll();
27301095a5dSDimitry Andric 
27401095a5dSDimitry Andric   const MachineOperand &Def = *MRI->def_begin(Reg);
27501095a5dSDimitry Andric   const MachineInstr &DefMI = *Def.getParent();
27601095a5dSDimitry Andric   if (lowersToCopies(DefMI)) {
27701095a5dSDimitry Andric     // Start optimisatically with no used or defined lanes for copy
27801095a5dSDimitry Andric     // instructions. The following dataflow analysis will add more bits.
2791d5ae102SDimitry Andric     unsigned RegIdx = Register::virtReg2Index(Reg);
28001095a5dSDimitry Andric     DefinedByCopy.set(RegIdx);
28101095a5dSDimitry Andric     PutInWorklist(RegIdx);
28201095a5dSDimitry Andric 
28301095a5dSDimitry Andric     if (Def.isDead())
284b915e9e0SDimitry Andric       return LaneBitmask::getNone();
28501095a5dSDimitry Andric 
28601095a5dSDimitry Andric     // COPY/PHI can copy across unrelated register classes (example: float/int)
28701095a5dSDimitry Andric     // with incompatible subregister structure. Do not include these in the
28801095a5dSDimitry Andric     // dataflow analysis since we cannot transfer lanemasks in a meaningful way.
28901095a5dSDimitry Andric     const TargetRegisterClass *DefRC = MRI->getRegClass(Reg);
29001095a5dSDimitry Andric 
29101095a5dSDimitry Andric     // Determine initially DefinedLanes.
292b915e9e0SDimitry Andric     LaneBitmask DefinedLanes;
29301095a5dSDimitry Andric     for (const MachineOperand &MO : DefMI.uses()) {
29401095a5dSDimitry Andric       if (!MO.isReg() || !MO.readsReg())
29501095a5dSDimitry Andric         continue;
2961d5ae102SDimitry Andric       Register MOReg = MO.getReg();
29701095a5dSDimitry Andric       if (!MOReg)
29801095a5dSDimitry Andric         continue;
29901095a5dSDimitry Andric 
30001095a5dSDimitry Andric       LaneBitmask MODefinedLanes;
301e3b55780SDimitry Andric       if (MOReg.isPhysical()) {
302b915e9e0SDimitry Andric         MODefinedLanes = LaneBitmask::getAll();
30301095a5dSDimitry Andric       } else if (isCrossCopy(*MRI, DefMI, DefRC, MO)) {
304b915e9e0SDimitry Andric         MODefinedLanes = LaneBitmask::getAll();
30501095a5dSDimitry Andric       } else {
306e3b55780SDimitry Andric         assert(MOReg.isVirtual());
30701095a5dSDimitry Andric         if (MRI->hasOneDef(MOReg)) {
30801095a5dSDimitry Andric           const MachineOperand &MODef = *MRI->def_begin(MOReg);
30901095a5dSDimitry Andric           const MachineInstr &MODefMI = *MODef.getParent();
31001095a5dSDimitry Andric           // Bits from copy-like operations will be added later.
31101095a5dSDimitry Andric           if (lowersToCopies(MODefMI) || MODefMI.isImplicitDef())
31201095a5dSDimitry Andric             continue;
31301095a5dSDimitry Andric         }
31401095a5dSDimitry Andric         unsigned MOSubReg = MO.getSubReg();
31501095a5dSDimitry Andric         MODefinedLanes = MRI->getMaxLaneMaskForVReg(MOReg);
31601095a5dSDimitry Andric         MODefinedLanes = TRI->reverseComposeSubRegIndexLaneMask(
31701095a5dSDimitry Andric             MOSubReg, MODefinedLanes);
31801095a5dSDimitry Andric       }
31901095a5dSDimitry Andric 
3207fa27ce4SDimitry Andric       unsigned OpNum = MO.getOperandNo();
32101095a5dSDimitry Andric       DefinedLanes |= transferDefinedLanes(Def, OpNum, MODefinedLanes);
32201095a5dSDimitry Andric     }
32301095a5dSDimitry Andric     return DefinedLanes;
32401095a5dSDimitry Andric   }
32501095a5dSDimitry Andric   if (DefMI.isImplicitDef() || Def.isDead())
326b915e9e0SDimitry Andric     return LaneBitmask::getNone();
32701095a5dSDimitry Andric 
32801095a5dSDimitry Andric   assert(Def.getSubReg() == 0 &&
32901095a5dSDimitry Andric          "Should not have subregister defs in machine SSA phase");
33001095a5dSDimitry Andric   return MRI->getMaxLaneMaskForVReg(Reg);
33101095a5dSDimitry Andric }
33201095a5dSDimitry Andric 
determineInitialUsedLanes(unsigned Reg)3337fa27ce4SDimitry Andric LaneBitmask DeadLaneDetector::determineInitialUsedLanes(unsigned Reg) {
334b915e9e0SDimitry Andric   LaneBitmask UsedLanes = LaneBitmask::getNone();
33501095a5dSDimitry Andric   for (const MachineOperand &MO : MRI->use_nodbg_operands(Reg)) {
33601095a5dSDimitry Andric     if (!MO.readsReg())
33701095a5dSDimitry Andric       continue;
33801095a5dSDimitry Andric 
33901095a5dSDimitry Andric     const MachineInstr &UseMI = *MO.getParent();
34001095a5dSDimitry Andric     if (UseMI.isKill())
34101095a5dSDimitry Andric       continue;
34201095a5dSDimitry Andric 
34301095a5dSDimitry Andric     unsigned SubReg = MO.getSubReg();
34401095a5dSDimitry Andric     if (lowersToCopies(UseMI)) {
34501095a5dSDimitry Andric       assert(UseMI.getDesc().getNumDefs() == 1);
34601095a5dSDimitry Andric       const MachineOperand &Def = *UseMI.defs().begin();
3471d5ae102SDimitry Andric       Register DefReg = Def.getReg();
34801095a5dSDimitry Andric       // The used lanes of COPY-like instruction operands are determined by the
34901095a5dSDimitry Andric       // following dataflow analysis.
350e3b55780SDimitry Andric       if (DefReg.isVirtual()) {
35101095a5dSDimitry Andric         // But ignore copies across incompatible register classes.
35201095a5dSDimitry Andric         bool CrossCopy = false;
35301095a5dSDimitry Andric         if (lowersToCopies(UseMI)) {
35401095a5dSDimitry Andric           const TargetRegisterClass *DstRC = MRI->getRegClass(DefReg);
35501095a5dSDimitry Andric           CrossCopy = isCrossCopy(*MRI, UseMI, DstRC, MO);
35601095a5dSDimitry Andric           if (CrossCopy)
357eb11fae6SDimitry Andric             LLVM_DEBUG(dbgs() << "Copy across incompatible classes: " << UseMI);
35801095a5dSDimitry Andric         }
35901095a5dSDimitry Andric 
36001095a5dSDimitry Andric         if (!CrossCopy)
36101095a5dSDimitry Andric           continue;
36201095a5dSDimitry Andric       }
36301095a5dSDimitry Andric     }
36401095a5dSDimitry Andric 
36501095a5dSDimitry Andric     // Shortcut: All lanes are used.
36601095a5dSDimitry Andric     if (SubReg == 0)
36701095a5dSDimitry Andric       return MRI->getMaxLaneMaskForVReg(Reg);
36801095a5dSDimitry Andric 
36901095a5dSDimitry Andric     UsedLanes |= TRI->getSubRegIndexLaneMask(SubReg);
37001095a5dSDimitry Andric   }
37101095a5dSDimitry Andric   return UsedLanes;
37201095a5dSDimitry Andric }
37301095a5dSDimitry Andric 
3747fa27ce4SDimitry Andric namespace {
3757fa27ce4SDimitry Andric 
3767fa27ce4SDimitry Andric class DetectDeadLanes : public MachineFunctionPass {
3777fa27ce4SDimitry Andric public:
3787fa27ce4SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
3797fa27ce4SDimitry Andric 
3807fa27ce4SDimitry Andric   static char ID;
DetectDeadLanes()3817fa27ce4SDimitry Andric   DetectDeadLanes() : MachineFunctionPass(ID) {}
3827fa27ce4SDimitry Andric 
getPassName() const3837fa27ce4SDimitry Andric   StringRef getPassName() const override { return "Detect Dead Lanes"; }
3847fa27ce4SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const3857fa27ce4SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
3867fa27ce4SDimitry Andric     AU.setPreservesCFG();
3877fa27ce4SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
3887fa27ce4SDimitry Andric   }
3897fa27ce4SDimitry Andric 
3907fa27ce4SDimitry Andric private:
3917fa27ce4SDimitry Andric   /// update the operand status.
3927fa27ce4SDimitry Andric   /// The first return value shows whether MF been changed.
3937fa27ce4SDimitry Andric   /// The second return value indicates we need to call
3947fa27ce4SDimitry Andric   /// DeadLaneDetector::computeSubRegisterLaneBitInfo and this function again
3957fa27ce4SDimitry Andric   /// to propagate changes.
3967fa27ce4SDimitry Andric   std::pair<bool, bool>
3977fa27ce4SDimitry Andric   modifySubRegisterOperandStatus(const DeadLaneDetector &DLD,
3987fa27ce4SDimitry Andric                                  MachineFunction &MF);
3997fa27ce4SDimitry Andric 
4007fa27ce4SDimitry Andric   bool isUndefRegAtInput(const MachineOperand &MO,
4017fa27ce4SDimitry Andric                          const DeadLaneDetector::VRegInfo &RegInfo) const;
4027fa27ce4SDimitry Andric 
4037fa27ce4SDimitry Andric   bool isUndefInput(const DeadLaneDetector &DLD, const MachineOperand &MO,
4047fa27ce4SDimitry Andric                     bool *CrossCopy) const;
4057fa27ce4SDimitry Andric 
4067fa27ce4SDimitry Andric   const MachineRegisterInfo *MRI = nullptr;
4077fa27ce4SDimitry Andric   const TargetRegisterInfo *TRI = nullptr;
4087fa27ce4SDimitry Andric };
4097fa27ce4SDimitry Andric 
4107fa27ce4SDimitry Andric } // end anonymous namespace
4117fa27ce4SDimitry Andric 
4127fa27ce4SDimitry Andric char DetectDeadLanes::ID = 0;
4137fa27ce4SDimitry Andric char &llvm::DetectDeadLanesID = DetectDeadLanes::ID;
4147fa27ce4SDimitry Andric 
4157fa27ce4SDimitry Andric INITIALIZE_PASS(DetectDeadLanes, DEBUG_TYPE, "Detect Dead Lanes", false, false)
4167fa27ce4SDimitry Andric 
isUndefRegAtInput(const MachineOperand & MO,const DeadLaneDetector::VRegInfo & RegInfo) const4177fa27ce4SDimitry Andric bool DetectDeadLanes::isUndefRegAtInput(
4187fa27ce4SDimitry Andric     const MachineOperand &MO, const DeadLaneDetector::VRegInfo &RegInfo) const {
41901095a5dSDimitry Andric   unsigned SubReg = MO.getSubReg();
42001095a5dSDimitry Andric   LaneBitmask Mask = TRI->getSubRegIndexLaneMask(SubReg);
421b915e9e0SDimitry Andric   return (RegInfo.DefinedLanes & RegInfo.UsedLanes & Mask).none();
42201095a5dSDimitry Andric }
42301095a5dSDimitry Andric 
isUndefInput(const DeadLaneDetector & DLD,const MachineOperand & MO,bool * CrossCopy) const4247fa27ce4SDimitry Andric bool DetectDeadLanes::isUndefInput(const DeadLaneDetector &DLD,
4257fa27ce4SDimitry Andric                                    const MachineOperand &MO,
42601095a5dSDimitry Andric                                    bool *CrossCopy) const {
42701095a5dSDimitry Andric   if (!MO.isUse())
42801095a5dSDimitry Andric     return false;
42901095a5dSDimitry Andric   const MachineInstr &MI = *MO.getParent();
43001095a5dSDimitry Andric   if (!lowersToCopies(MI))
43101095a5dSDimitry Andric     return false;
43201095a5dSDimitry Andric   const MachineOperand &Def = MI.getOperand(0);
4331d5ae102SDimitry Andric   Register DefReg = Def.getReg();
434e3b55780SDimitry Andric   if (!DefReg.isVirtual())
43501095a5dSDimitry Andric     return false;
4361d5ae102SDimitry Andric   unsigned DefRegIdx = Register::virtReg2Index(DefReg);
4377fa27ce4SDimitry Andric   if (!DLD.isDefinedByCopy(DefRegIdx))
43801095a5dSDimitry Andric     return false;
43901095a5dSDimitry Andric 
4407fa27ce4SDimitry Andric   const DeadLaneDetector::VRegInfo &DefRegInfo = DLD.getVRegInfo(DefRegIdx);
4417fa27ce4SDimitry Andric   LaneBitmask UsedLanes = DLD.transferUsedLanes(MI, DefRegInfo.UsedLanes, MO);
442b915e9e0SDimitry Andric   if (UsedLanes.any())
44301095a5dSDimitry Andric     return false;
44401095a5dSDimitry Andric 
4451d5ae102SDimitry Andric   Register MOReg = MO.getReg();
446e3b55780SDimitry Andric   if (MOReg.isVirtual()) {
44701095a5dSDimitry Andric     const TargetRegisterClass *DstRC = MRI->getRegClass(DefReg);
44801095a5dSDimitry Andric     *CrossCopy = isCrossCopy(*MRI, MI, DstRC, MO);
44901095a5dSDimitry Andric   }
45001095a5dSDimitry Andric   return true;
45101095a5dSDimitry Andric }
45201095a5dSDimitry Andric 
computeSubRegisterLaneBitInfo()4537fa27ce4SDimitry Andric void DeadLaneDetector::computeSubRegisterLaneBitInfo() {
45401095a5dSDimitry Andric   // First pass: Populate defs/uses of vregs with initial values
45501095a5dSDimitry Andric   unsigned NumVirtRegs = MRI->getNumVirtRegs();
45601095a5dSDimitry Andric   for (unsigned RegIdx = 0; RegIdx < NumVirtRegs; ++RegIdx) {
457e3b55780SDimitry Andric     Register Reg = Register::index2VirtReg(RegIdx);
45801095a5dSDimitry Andric 
45901095a5dSDimitry Andric     // Determine used/defined lanes and add copy instructions to worklist.
46001095a5dSDimitry Andric     VRegInfo &Info = VRegInfos[RegIdx];
46101095a5dSDimitry Andric     Info.DefinedLanes = determineInitialDefinedLanes(Reg);
46201095a5dSDimitry Andric     Info.UsedLanes = determineInitialUsedLanes(Reg);
46301095a5dSDimitry Andric   }
46401095a5dSDimitry Andric 
46501095a5dSDimitry Andric   // Iterate as long as defined lanes/used lanes keep changing.
46601095a5dSDimitry Andric   while (!Worklist.empty()) {
46701095a5dSDimitry Andric     unsigned RegIdx = Worklist.front();
46801095a5dSDimitry Andric     Worklist.pop_front();
46901095a5dSDimitry Andric     WorklistMembers.reset(RegIdx);
47001095a5dSDimitry Andric     VRegInfo &Info = VRegInfos[RegIdx];
471e3b55780SDimitry Andric     Register Reg = Register::index2VirtReg(RegIdx);
47201095a5dSDimitry Andric 
47301095a5dSDimitry Andric     // Transfer UsedLanes to operands of DefMI (backwards dataflow).
47401095a5dSDimitry Andric     MachineOperand &Def = *MRI->def_begin(Reg);
47501095a5dSDimitry Andric     const MachineInstr &MI = *Def.getParent();
47601095a5dSDimitry Andric     transferUsedLanesStep(MI, Info.UsedLanes);
47701095a5dSDimitry Andric     // Transfer DefinedLanes to users of Reg (forward dataflow).
47801095a5dSDimitry Andric     for (const MachineOperand &MO : MRI->use_nodbg_operands(Reg))
47901095a5dSDimitry Andric       transferDefinedLanesStep(MO, Info.DefinedLanes);
48001095a5dSDimitry Andric   }
48101095a5dSDimitry Andric 
482344a3780SDimitry Andric   LLVM_DEBUG({
483344a3780SDimitry Andric     dbgs() << "Defined/Used lanes:\n";
484344a3780SDimitry Andric     for (unsigned RegIdx = 0; RegIdx < NumVirtRegs; ++RegIdx) {
485e3b55780SDimitry Andric       Register Reg = Register::index2VirtReg(RegIdx);
48601095a5dSDimitry Andric       const VRegInfo &Info = VRegInfos[RegIdx];
487044eb2f6SDimitry Andric       dbgs() << printReg(Reg, nullptr)
48801095a5dSDimitry Andric              << " Used: " << PrintLaneMask(Info.UsedLanes)
48901095a5dSDimitry Andric              << " Def: " << PrintLaneMask(Info.DefinedLanes) << '\n';
490344a3780SDimitry Andric     }
491344a3780SDimitry Andric     dbgs() << "\n";
492344a3780SDimitry Andric   });
4937fa27ce4SDimitry Andric }
49401095a5dSDimitry Andric 
4957fa27ce4SDimitry Andric std::pair<bool, bool>
modifySubRegisterOperandStatus(const DeadLaneDetector & DLD,MachineFunction & MF)4967fa27ce4SDimitry Andric DetectDeadLanes::modifySubRegisterOperandStatus(const DeadLaneDetector &DLD,
4977fa27ce4SDimitry Andric                                                 MachineFunction &MF) {
498145449b1SDimitry Andric   bool Changed = false;
49901095a5dSDimitry Andric   bool Again = false;
50001095a5dSDimitry Andric   // Mark operands as dead/unused.
50101095a5dSDimitry Andric   for (MachineBasicBlock &MBB : MF) {
50201095a5dSDimitry Andric     for (MachineInstr &MI : MBB) {
50301095a5dSDimitry Andric       for (MachineOperand &MO : MI.operands()) {
50401095a5dSDimitry Andric         if (!MO.isReg())
50501095a5dSDimitry Andric           continue;
5061d5ae102SDimitry Andric         Register Reg = MO.getReg();
507e3b55780SDimitry Andric         if (!Reg.isVirtual())
50801095a5dSDimitry Andric           continue;
5091d5ae102SDimitry Andric         unsigned RegIdx = Register::virtReg2Index(Reg);
5107fa27ce4SDimitry Andric         const DeadLaneDetector::VRegInfo &RegInfo = DLD.getVRegInfo(RegIdx);
511b915e9e0SDimitry Andric         if (MO.isDef() && !MO.isDead() && RegInfo.UsedLanes.none()) {
512eb11fae6SDimitry Andric           LLVM_DEBUG(dbgs()
513eb11fae6SDimitry Andric                      << "Marking operand '" << MO << "' as dead in " << MI);
51401095a5dSDimitry Andric           MO.setIsDead();
515145449b1SDimitry Andric           Changed = true;
51601095a5dSDimitry Andric         }
51701095a5dSDimitry Andric         if (MO.readsReg()) {
51801095a5dSDimitry Andric           bool CrossCopy = false;
51901095a5dSDimitry Andric           if (isUndefRegAtInput(MO, RegInfo)) {
520eb11fae6SDimitry Andric             LLVM_DEBUG(dbgs()
521eb11fae6SDimitry Andric                        << "Marking operand '" << MO << "' as undef in " << MI);
52201095a5dSDimitry Andric             MO.setIsUndef();
523145449b1SDimitry Andric             Changed = true;
5247fa27ce4SDimitry Andric           } else if (isUndefInput(DLD, MO, &CrossCopy)) {
525eb11fae6SDimitry Andric             LLVM_DEBUG(dbgs()
526eb11fae6SDimitry Andric                        << "Marking operand '" << MO << "' as undef in " << MI);
52701095a5dSDimitry Andric             MO.setIsUndef();
528145449b1SDimitry Andric             Changed = true;
52901095a5dSDimitry Andric             if (CrossCopy)
53001095a5dSDimitry Andric               Again = true;
53101095a5dSDimitry Andric           }
53201095a5dSDimitry Andric         }
53301095a5dSDimitry Andric       }
53401095a5dSDimitry Andric     }
53501095a5dSDimitry Andric   }
53601095a5dSDimitry Andric 
537145449b1SDimitry Andric   return std::make_pair(Changed, Again);
53801095a5dSDimitry Andric }
53901095a5dSDimitry Andric 
runOnMachineFunction(MachineFunction & MF)54001095a5dSDimitry Andric bool DetectDeadLanes::runOnMachineFunction(MachineFunction &MF) {
54101095a5dSDimitry Andric   // Don't bother if we won't track subregister liveness later.  This pass is
54201095a5dSDimitry Andric   // required for correctness if subregister liveness is enabled because the
54301095a5dSDimitry Andric   // register coalescer cannot deal with hidden dead defs. However without
54401095a5dSDimitry Andric   // subregister liveness enabled, the expected benefits of this pass are small
54501095a5dSDimitry Andric   // so we safe the compile time.
546b915e9e0SDimitry Andric   MRI = &MF.getRegInfo();
547b915e9e0SDimitry Andric   if (!MRI->subRegLivenessEnabled()) {
548eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "Skipping Detect dead lanes pass\n");
54901095a5dSDimitry Andric     return false;
55001095a5dSDimitry Andric   }
55101095a5dSDimitry Andric 
55201095a5dSDimitry Andric   TRI = MRI->getTargetRegisterInfo();
55301095a5dSDimitry Andric 
5547fa27ce4SDimitry Andric   DeadLaneDetector DLD(MRI, TRI);
55501095a5dSDimitry Andric 
556145449b1SDimitry Andric   bool Changed = false;
55701095a5dSDimitry Andric   bool Again;
55801095a5dSDimitry Andric   do {
5597fa27ce4SDimitry Andric     DLD.computeSubRegisterLaneBitInfo();
560145449b1SDimitry Andric     bool LocalChanged;
5617fa27ce4SDimitry Andric     std::tie(LocalChanged, Again) = modifySubRegisterOperandStatus(DLD, MF);
562145449b1SDimitry Andric     Changed |= LocalChanged;
56301095a5dSDimitry Andric   } while (Again);
56401095a5dSDimitry Andric 
565145449b1SDimitry Andric   return Changed;
56601095a5dSDimitry Andric }
567