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