mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 07:26:09 +00:00

This change initializes the members TSI, LI, DT, PSI, and ORE pointer feilds of the SelectOptimize class to nullptr. Reviewed By: LuoYuanke Differential Revision: https://reviews.llvm.org/D148303
567 lines
19 KiB
C++
567 lines
19 KiB
C++
//===- DetectDeadLanes.cpp - SubRegister Lane Usage Analysis --*- C++ -*---===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
/// \file
|
|
/// Analysis that tracks defined/used subregister lanes across COPY instructions
|
|
/// and instructions that get lowered to a COPY (PHI, REG_SEQUENCE,
|
|
/// INSERT_SUBREG, EXTRACT_SUBREG).
|
|
/// The information is used to detect dead definitions and the usage of
|
|
/// (completely) undefined values and mark the operands as such.
|
|
/// This pass is necessary because the dead/undef status is not obvious anymore
|
|
/// when subregisters are involved.
|
|
///
|
|
/// Example:
|
|
/// %0 = some definition
|
|
/// %1 = IMPLICIT_DEF
|
|
/// %2 = REG_SEQUENCE %0, sub0, %1, sub1
|
|
/// %3 = EXTRACT_SUBREG %2, sub1
|
|
/// = use %3
|
|
/// The %0 definition is dead and %3 contains an undefined value.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/CodeGen/DetectDeadLanes.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
|
#include "llvm/InitializePasses.h"
|
|
#include "llvm/Pass.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "detect-dead-lanes"
|
|
|
|
DeadLaneDetector::DeadLaneDetector(const MachineRegisterInfo *MRI,
|
|
const TargetRegisterInfo *TRI)
|
|
: MRI(MRI), TRI(TRI) {
|
|
unsigned NumVirtRegs = MRI->getNumVirtRegs();
|
|
VRegInfos = std::unique_ptr<VRegInfo[]>(new VRegInfo[NumVirtRegs]);
|
|
WorklistMembers.resize(NumVirtRegs);
|
|
DefinedByCopy.resize(NumVirtRegs);
|
|
}
|
|
|
|
/// Returns true if \p MI will get lowered to a series of COPY instructions.
|
|
/// We call this a COPY-like instruction.
|
|
static bool lowersToCopies(const MachineInstr &MI) {
|
|
// Note: We could support instructions with MCInstrDesc::isRegSequenceLike(),
|
|
// isExtractSubRegLike(), isInsertSubregLike() in the future even though they
|
|
// are not lowered to a COPY.
|
|
switch (MI.getOpcode()) {
|
|
case TargetOpcode::COPY:
|
|
case TargetOpcode::PHI:
|
|
case TargetOpcode::INSERT_SUBREG:
|
|
case TargetOpcode::REG_SEQUENCE:
|
|
case TargetOpcode::EXTRACT_SUBREG:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool isCrossCopy(const MachineRegisterInfo &MRI,
|
|
const MachineInstr &MI,
|
|
const TargetRegisterClass *DstRC,
|
|
const MachineOperand &MO) {
|
|
assert(lowersToCopies(MI));
|
|
Register SrcReg = MO.getReg();
|
|
const TargetRegisterClass *SrcRC = MRI.getRegClass(SrcReg);
|
|
if (DstRC == SrcRC)
|
|
return false;
|
|
|
|
unsigned SrcSubIdx = MO.getSubReg();
|
|
|
|
const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
|
|
unsigned DstSubIdx = 0;
|
|
switch (MI.getOpcode()) {
|
|
case TargetOpcode::INSERT_SUBREG:
|
|
if (MO.getOperandNo() == 2)
|
|
DstSubIdx = MI.getOperand(3).getImm();
|
|
break;
|
|
case TargetOpcode::REG_SEQUENCE: {
|
|
unsigned OpNum = MO.getOperandNo();
|
|
DstSubIdx = MI.getOperand(OpNum+1).getImm();
|
|
break;
|
|
}
|
|
case TargetOpcode::EXTRACT_SUBREG: {
|
|
unsigned SubReg = MI.getOperand(2).getImm();
|
|
SrcSubIdx = TRI.composeSubRegIndices(SubReg, SrcSubIdx);
|
|
}
|
|
}
|
|
|
|
unsigned PreA, PreB; // Unused.
|
|
if (SrcSubIdx && DstSubIdx)
|
|
return !TRI.getCommonSuperRegClass(SrcRC, SrcSubIdx, DstRC, DstSubIdx, PreA,
|
|
PreB);
|
|
if (SrcSubIdx)
|
|
return !TRI.getMatchingSuperRegClass(SrcRC, DstRC, SrcSubIdx);
|
|
if (DstSubIdx)
|
|
return !TRI.getMatchingSuperRegClass(DstRC, SrcRC, DstSubIdx);
|
|
return !TRI.getCommonSubClass(SrcRC, DstRC);
|
|
}
|
|
|
|
void DeadLaneDetector::addUsedLanesOnOperand(const MachineOperand &MO,
|
|
LaneBitmask UsedLanes) {
|
|
if (!MO.readsReg())
|
|
return;
|
|
Register MOReg = MO.getReg();
|
|
if (!MOReg.isVirtual())
|
|
return;
|
|
|
|
unsigned MOSubReg = MO.getSubReg();
|
|
if (MOSubReg != 0)
|
|
UsedLanes = TRI->composeSubRegIndexLaneMask(MOSubReg, UsedLanes);
|
|
UsedLanes &= MRI->getMaxLaneMaskForVReg(MOReg);
|
|
|
|
unsigned MORegIdx = Register::virtReg2Index(MOReg);
|
|
DeadLaneDetector::VRegInfo &MORegInfo = VRegInfos[MORegIdx];
|
|
LaneBitmask PrevUsedLanes = MORegInfo.UsedLanes;
|
|
// Any change at all?
|
|
if ((UsedLanes & ~PrevUsedLanes).none())
|
|
return;
|
|
|
|
// Set UsedLanes and remember instruction for further propagation.
|
|
MORegInfo.UsedLanes = PrevUsedLanes | UsedLanes;
|
|
if (DefinedByCopy.test(MORegIdx))
|
|
PutInWorklist(MORegIdx);
|
|
}
|
|
|
|
void DeadLaneDetector::transferUsedLanesStep(const MachineInstr &MI,
|
|
LaneBitmask UsedLanes) {
|
|
for (const MachineOperand &MO : MI.uses()) {
|
|
if (!MO.isReg() || !MO.getReg().isVirtual())
|
|
continue;
|
|
LaneBitmask UsedOnMO = transferUsedLanes(MI, UsedLanes, MO);
|
|
addUsedLanesOnOperand(MO, UsedOnMO);
|
|
}
|
|
}
|
|
|
|
LaneBitmask
|
|
DeadLaneDetector::transferUsedLanes(const MachineInstr &MI,
|
|
LaneBitmask UsedLanes,
|
|
const MachineOperand &MO) const {
|
|
unsigned OpNum = MO.getOperandNo();
|
|
assert(lowersToCopies(MI) &&
|
|
DefinedByCopy[Register::virtReg2Index(MI.getOperand(0).getReg())]);
|
|
|
|
switch (MI.getOpcode()) {
|
|
case TargetOpcode::COPY:
|
|
case TargetOpcode::PHI:
|
|
return UsedLanes;
|
|
case TargetOpcode::REG_SEQUENCE: {
|
|
assert(OpNum % 2 == 1);
|
|
unsigned SubIdx = MI.getOperand(OpNum + 1).getImm();
|
|
return TRI->reverseComposeSubRegIndexLaneMask(SubIdx, UsedLanes);
|
|
}
|
|
case TargetOpcode::INSERT_SUBREG: {
|
|
unsigned SubIdx = MI.getOperand(3).getImm();
|
|
LaneBitmask MO2UsedLanes =
|
|
TRI->reverseComposeSubRegIndexLaneMask(SubIdx, UsedLanes);
|
|
if (OpNum == 2)
|
|
return MO2UsedLanes;
|
|
|
|
const MachineOperand &Def = MI.getOperand(0);
|
|
Register DefReg = Def.getReg();
|
|
const TargetRegisterClass *RC = MRI->getRegClass(DefReg);
|
|
LaneBitmask MO1UsedLanes;
|
|
if (RC->CoveredBySubRegs)
|
|
MO1UsedLanes = UsedLanes & ~TRI->getSubRegIndexLaneMask(SubIdx);
|
|
else
|
|
MO1UsedLanes = RC->LaneMask;
|
|
|
|
assert(OpNum == 1);
|
|
return MO1UsedLanes;
|
|
}
|
|
case TargetOpcode::EXTRACT_SUBREG: {
|
|
assert(OpNum == 1);
|
|
unsigned SubIdx = MI.getOperand(2).getImm();
|
|
return TRI->composeSubRegIndexLaneMask(SubIdx, UsedLanes);
|
|
}
|
|
default:
|
|
llvm_unreachable("function must be called with COPY-like instruction");
|
|
}
|
|
}
|
|
|
|
void DeadLaneDetector::transferDefinedLanesStep(const MachineOperand &Use,
|
|
LaneBitmask DefinedLanes) {
|
|
if (!Use.readsReg())
|
|
return;
|
|
// Check whether the operand writes a vreg and is part of a COPY-like
|
|
// instruction.
|
|
const MachineInstr &MI = *Use.getParent();
|
|
if (MI.getDesc().getNumDefs() != 1)
|
|
return;
|
|
// FIXME: PATCHPOINT instructions announce a Def that does not always exist,
|
|
// they really need to be modeled differently!
|
|
if (MI.getOpcode() == TargetOpcode::PATCHPOINT)
|
|
return;
|
|
const MachineOperand &Def = *MI.defs().begin();
|
|
Register DefReg = Def.getReg();
|
|
if (!DefReg.isVirtual())
|
|
return;
|
|
unsigned DefRegIdx = Register::virtReg2Index(DefReg);
|
|
if (!DefinedByCopy.test(DefRegIdx))
|
|
return;
|
|
|
|
unsigned OpNum = Use.getOperandNo();
|
|
DefinedLanes =
|
|
TRI->reverseComposeSubRegIndexLaneMask(Use.getSubReg(), DefinedLanes);
|
|
DefinedLanes = transferDefinedLanes(Def, OpNum, DefinedLanes);
|
|
|
|
VRegInfo &RegInfo = VRegInfos[DefRegIdx];
|
|
LaneBitmask PrevDefinedLanes = RegInfo.DefinedLanes;
|
|
// Any change at all?
|
|
if ((DefinedLanes & ~PrevDefinedLanes).none())
|
|
return;
|
|
|
|
RegInfo.DefinedLanes = PrevDefinedLanes | DefinedLanes;
|
|
PutInWorklist(DefRegIdx);
|
|
}
|
|
|
|
LaneBitmask DeadLaneDetector::transferDefinedLanes(
|
|
const MachineOperand &Def, unsigned OpNum, LaneBitmask DefinedLanes) const {
|
|
const MachineInstr &MI = *Def.getParent();
|
|
// Translate DefinedLanes if necessary.
|
|
switch (MI.getOpcode()) {
|
|
case TargetOpcode::REG_SEQUENCE: {
|
|
unsigned SubIdx = MI.getOperand(OpNum + 1).getImm();
|
|
DefinedLanes = TRI->composeSubRegIndexLaneMask(SubIdx, DefinedLanes);
|
|
DefinedLanes &= TRI->getSubRegIndexLaneMask(SubIdx);
|
|
break;
|
|
}
|
|
case TargetOpcode::INSERT_SUBREG: {
|
|
unsigned SubIdx = MI.getOperand(3).getImm();
|
|
if (OpNum == 2) {
|
|
DefinedLanes = TRI->composeSubRegIndexLaneMask(SubIdx, DefinedLanes);
|
|
DefinedLanes &= TRI->getSubRegIndexLaneMask(SubIdx);
|
|
} else {
|
|
assert(OpNum == 1 && "INSERT_SUBREG must have two operands");
|
|
// Ignore lanes defined by operand 2.
|
|
DefinedLanes &= ~TRI->getSubRegIndexLaneMask(SubIdx);
|
|
}
|
|
break;
|
|
}
|
|
case TargetOpcode::EXTRACT_SUBREG: {
|
|
unsigned SubIdx = MI.getOperand(2).getImm();
|
|
assert(OpNum == 1 && "EXTRACT_SUBREG must have one register operand only");
|
|
DefinedLanes = TRI->reverseComposeSubRegIndexLaneMask(SubIdx, DefinedLanes);
|
|
break;
|
|
}
|
|
case TargetOpcode::COPY:
|
|
case TargetOpcode::PHI:
|
|
break;
|
|
default:
|
|
llvm_unreachable("function must be called with COPY-like instruction");
|
|
}
|
|
|
|
assert(Def.getSubReg() == 0 &&
|
|
"Should not have subregister defs in machine SSA phase");
|
|
DefinedLanes &= MRI->getMaxLaneMaskForVReg(Def.getReg());
|
|
return DefinedLanes;
|
|
}
|
|
|
|
LaneBitmask DeadLaneDetector::determineInitialDefinedLanes(unsigned Reg) {
|
|
// Live-In or unused registers have no definition but are considered fully
|
|
// defined.
|
|
if (!MRI->hasOneDef(Reg))
|
|
return LaneBitmask::getAll();
|
|
|
|
const MachineOperand &Def = *MRI->def_begin(Reg);
|
|
const MachineInstr &DefMI = *Def.getParent();
|
|
if (lowersToCopies(DefMI)) {
|
|
// Start optimisatically with no used or defined lanes for copy
|
|
// instructions. The following dataflow analysis will add more bits.
|
|
unsigned RegIdx = Register::virtReg2Index(Reg);
|
|
DefinedByCopy.set(RegIdx);
|
|
PutInWorklist(RegIdx);
|
|
|
|
if (Def.isDead())
|
|
return LaneBitmask::getNone();
|
|
|
|
// COPY/PHI can copy across unrelated register classes (example: float/int)
|
|
// with incompatible subregister structure. Do not include these in the
|
|
// dataflow analysis since we cannot transfer lanemasks in a meaningful way.
|
|
const TargetRegisterClass *DefRC = MRI->getRegClass(Reg);
|
|
|
|
// Determine initially DefinedLanes.
|
|
LaneBitmask DefinedLanes;
|
|
for (const MachineOperand &MO : DefMI.uses()) {
|
|
if (!MO.isReg() || !MO.readsReg())
|
|
continue;
|
|
Register MOReg = MO.getReg();
|
|
if (!MOReg)
|
|
continue;
|
|
|
|
LaneBitmask MODefinedLanes;
|
|
if (MOReg.isPhysical()) {
|
|
MODefinedLanes = LaneBitmask::getAll();
|
|
} else if (isCrossCopy(*MRI, DefMI, DefRC, MO)) {
|
|
MODefinedLanes = LaneBitmask::getAll();
|
|
} else {
|
|
assert(MOReg.isVirtual());
|
|
if (MRI->hasOneDef(MOReg)) {
|
|
const MachineOperand &MODef = *MRI->def_begin(MOReg);
|
|
const MachineInstr &MODefMI = *MODef.getParent();
|
|
// Bits from copy-like operations will be added later.
|
|
if (lowersToCopies(MODefMI) || MODefMI.isImplicitDef())
|
|
continue;
|
|
}
|
|
unsigned MOSubReg = MO.getSubReg();
|
|
MODefinedLanes = MRI->getMaxLaneMaskForVReg(MOReg);
|
|
MODefinedLanes = TRI->reverseComposeSubRegIndexLaneMask(
|
|
MOSubReg, MODefinedLanes);
|
|
}
|
|
|
|
unsigned OpNum = MO.getOperandNo();
|
|
DefinedLanes |= transferDefinedLanes(Def, OpNum, MODefinedLanes);
|
|
}
|
|
return DefinedLanes;
|
|
}
|
|
if (DefMI.isImplicitDef() || Def.isDead())
|
|
return LaneBitmask::getNone();
|
|
|
|
assert(Def.getSubReg() == 0 &&
|
|
"Should not have subregister defs in machine SSA phase");
|
|
return MRI->getMaxLaneMaskForVReg(Reg);
|
|
}
|
|
|
|
LaneBitmask DeadLaneDetector::determineInitialUsedLanes(unsigned Reg) {
|
|
LaneBitmask UsedLanes = LaneBitmask::getNone();
|
|
for (const MachineOperand &MO : MRI->use_nodbg_operands(Reg)) {
|
|
if (!MO.readsReg())
|
|
continue;
|
|
|
|
const MachineInstr &UseMI = *MO.getParent();
|
|
if (UseMI.isKill())
|
|
continue;
|
|
|
|
unsigned SubReg = MO.getSubReg();
|
|
if (lowersToCopies(UseMI)) {
|
|
assert(UseMI.getDesc().getNumDefs() == 1);
|
|
const MachineOperand &Def = *UseMI.defs().begin();
|
|
Register DefReg = Def.getReg();
|
|
// The used lanes of COPY-like instruction operands are determined by the
|
|
// following dataflow analysis.
|
|
if (DefReg.isVirtual()) {
|
|
// But ignore copies across incompatible register classes.
|
|
bool CrossCopy = false;
|
|
if (lowersToCopies(UseMI)) {
|
|
const TargetRegisterClass *DstRC = MRI->getRegClass(DefReg);
|
|
CrossCopy = isCrossCopy(*MRI, UseMI, DstRC, MO);
|
|
if (CrossCopy)
|
|
LLVM_DEBUG(dbgs() << "Copy across incompatible classes: " << UseMI);
|
|
}
|
|
|
|
if (!CrossCopy)
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Shortcut: All lanes are used.
|
|
if (SubReg == 0)
|
|
return MRI->getMaxLaneMaskForVReg(Reg);
|
|
|
|
UsedLanes |= TRI->getSubRegIndexLaneMask(SubReg);
|
|
}
|
|
return UsedLanes;
|
|
}
|
|
|
|
namespace {
|
|
|
|
class DetectDeadLanes : public MachineFunctionPass {
|
|
public:
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
|
|
static char ID;
|
|
DetectDeadLanes() : MachineFunctionPass(ID) {}
|
|
|
|
StringRef getPassName() const override { return "Detect Dead Lanes"; }
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesCFG();
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
private:
|
|
/// update the operand status.
|
|
/// The first return value shows whether MF been changed.
|
|
/// The second return value indicates we need to call
|
|
/// DeadLaneDetector::computeSubRegisterLaneBitInfo and this function again
|
|
/// to propagate changes.
|
|
std::pair<bool, bool>
|
|
modifySubRegisterOperandStatus(const DeadLaneDetector &DLD,
|
|
MachineFunction &MF);
|
|
|
|
bool isUndefRegAtInput(const MachineOperand &MO,
|
|
const DeadLaneDetector::VRegInfo &RegInfo) const;
|
|
|
|
bool isUndefInput(const DeadLaneDetector &DLD, const MachineOperand &MO,
|
|
bool *CrossCopy) const;
|
|
|
|
const MachineRegisterInfo *MRI = nullptr;
|
|
const TargetRegisterInfo *TRI = nullptr;
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
char DetectDeadLanes::ID = 0;
|
|
char &llvm::DetectDeadLanesID = DetectDeadLanes::ID;
|
|
|
|
INITIALIZE_PASS(DetectDeadLanes, DEBUG_TYPE, "Detect Dead Lanes", false, false)
|
|
|
|
bool DetectDeadLanes::isUndefRegAtInput(
|
|
const MachineOperand &MO, const DeadLaneDetector::VRegInfo &RegInfo) const {
|
|
unsigned SubReg = MO.getSubReg();
|
|
LaneBitmask Mask = TRI->getSubRegIndexLaneMask(SubReg);
|
|
return (RegInfo.DefinedLanes & RegInfo.UsedLanes & Mask).none();
|
|
}
|
|
|
|
bool DetectDeadLanes::isUndefInput(const DeadLaneDetector &DLD,
|
|
const MachineOperand &MO,
|
|
bool *CrossCopy) const {
|
|
if (!MO.isUse())
|
|
return false;
|
|
const MachineInstr &MI = *MO.getParent();
|
|
if (!lowersToCopies(MI))
|
|
return false;
|
|
const MachineOperand &Def = MI.getOperand(0);
|
|
Register DefReg = Def.getReg();
|
|
if (!DefReg.isVirtual())
|
|
return false;
|
|
unsigned DefRegIdx = Register::virtReg2Index(DefReg);
|
|
if (!DLD.isDefinedByCopy(DefRegIdx))
|
|
return false;
|
|
|
|
const DeadLaneDetector::VRegInfo &DefRegInfo = DLD.getVRegInfo(DefRegIdx);
|
|
LaneBitmask UsedLanes = DLD.transferUsedLanes(MI, DefRegInfo.UsedLanes, MO);
|
|
if (UsedLanes.any())
|
|
return false;
|
|
|
|
Register MOReg = MO.getReg();
|
|
if (MOReg.isVirtual()) {
|
|
const TargetRegisterClass *DstRC = MRI->getRegClass(DefReg);
|
|
*CrossCopy = isCrossCopy(*MRI, MI, DstRC, MO);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void DeadLaneDetector::computeSubRegisterLaneBitInfo() {
|
|
// First pass: Populate defs/uses of vregs with initial values
|
|
unsigned NumVirtRegs = MRI->getNumVirtRegs();
|
|
for (unsigned RegIdx = 0; RegIdx < NumVirtRegs; ++RegIdx) {
|
|
Register Reg = Register::index2VirtReg(RegIdx);
|
|
|
|
// Determine used/defined lanes and add copy instructions to worklist.
|
|
VRegInfo &Info = VRegInfos[RegIdx];
|
|
Info.DefinedLanes = determineInitialDefinedLanes(Reg);
|
|
Info.UsedLanes = determineInitialUsedLanes(Reg);
|
|
}
|
|
|
|
// Iterate as long as defined lanes/used lanes keep changing.
|
|
while (!Worklist.empty()) {
|
|
unsigned RegIdx = Worklist.front();
|
|
Worklist.pop_front();
|
|
WorklistMembers.reset(RegIdx);
|
|
VRegInfo &Info = VRegInfos[RegIdx];
|
|
Register Reg = Register::index2VirtReg(RegIdx);
|
|
|
|
// Transfer UsedLanes to operands of DefMI (backwards dataflow).
|
|
MachineOperand &Def = *MRI->def_begin(Reg);
|
|
const MachineInstr &MI = *Def.getParent();
|
|
transferUsedLanesStep(MI, Info.UsedLanes);
|
|
// Transfer DefinedLanes to users of Reg (forward dataflow).
|
|
for (const MachineOperand &MO : MRI->use_nodbg_operands(Reg))
|
|
transferDefinedLanesStep(MO, Info.DefinedLanes);
|
|
}
|
|
|
|
LLVM_DEBUG({
|
|
dbgs() << "Defined/Used lanes:\n";
|
|
for (unsigned RegIdx = 0; RegIdx < NumVirtRegs; ++RegIdx) {
|
|
Register Reg = Register::index2VirtReg(RegIdx);
|
|
const VRegInfo &Info = VRegInfos[RegIdx];
|
|
dbgs() << printReg(Reg, nullptr)
|
|
<< " Used: " << PrintLaneMask(Info.UsedLanes)
|
|
<< " Def: " << PrintLaneMask(Info.DefinedLanes) << '\n';
|
|
}
|
|
dbgs() << "\n";
|
|
});
|
|
}
|
|
|
|
std::pair<bool, bool>
|
|
DetectDeadLanes::modifySubRegisterOperandStatus(const DeadLaneDetector &DLD,
|
|
MachineFunction &MF) {
|
|
bool Changed = false;
|
|
bool Again = false;
|
|
// Mark operands as dead/unused.
|
|
for (MachineBasicBlock &MBB : MF) {
|
|
for (MachineInstr &MI : MBB) {
|
|
for (MachineOperand &MO : MI.operands()) {
|
|
if (!MO.isReg())
|
|
continue;
|
|
Register Reg = MO.getReg();
|
|
if (!Reg.isVirtual())
|
|
continue;
|
|
unsigned RegIdx = Register::virtReg2Index(Reg);
|
|
const DeadLaneDetector::VRegInfo &RegInfo = DLD.getVRegInfo(RegIdx);
|
|
if (MO.isDef() && !MO.isDead() && RegInfo.UsedLanes.none()) {
|
|
LLVM_DEBUG(dbgs()
|
|
<< "Marking operand '" << MO << "' as dead in " << MI);
|
|
MO.setIsDead();
|
|
Changed = true;
|
|
}
|
|
if (MO.readsReg()) {
|
|
bool CrossCopy = false;
|
|
if (isUndefRegAtInput(MO, RegInfo)) {
|
|
LLVM_DEBUG(dbgs()
|
|
<< "Marking operand '" << MO << "' as undef in " << MI);
|
|
MO.setIsUndef();
|
|
Changed = true;
|
|
} else if (isUndefInput(DLD, MO, &CrossCopy)) {
|
|
LLVM_DEBUG(dbgs()
|
|
<< "Marking operand '" << MO << "' as undef in " << MI);
|
|
MO.setIsUndef();
|
|
Changed = true;
|
|
if (CrossCopy)
|
|
Again = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return std::make_pair(Changed, Again);
|
|
}
|
|
|
|
bool DetectDeadLanes::runOnMachineFunction(MachineFunction &MF) {
|
|
// Don't bother if we won't track subregister liveness later. This pass is
|
|
// required for correctness if subregister liveness is enabled because the
|
|
// register coalescer cannot deal with hidden dead defs. However without
|
|
// subregister liveness enabled, the expected benefits of this pass are small
|
|
// so we safe the compile time.
|
|
MRI = &MF.getRegInfo();
|
|
if (!MRI->subRegLivenessEnabled()) {
|
|
LLVM_DEBUG(dbgs() << "Skipping Detect dead lanes pass\n");
|
|
return false;
|
|
}
|
|
|
|
TRI = MRI->getTargetRegisterInfo();
|
|
|
|
DeadLaneDetector DLD(MRI, TRI);
|
|
|
|
bool Changed = false;
|
|
bool Again;
|
|
do {
|
|
DLD.computeSubRegisterLaneBitInfo();
|
|
bool LocalChanged;
|
|
std::tie(LocalChanged, Again) = modifySubRegisterOperandStatus(DLD, MF);
|
|
Changed |= LocalChanged;
|
|
} while (Again);
|
|
|
|
return Changed;
|
|
}
|