Path: blob/main/contrib/llvm-project/llvm/lib/CodeGen/DetectDeadLanes.cpp
35233 views
//===- DetectDeadLanes.cpp - SubRegister Lane Usage Analysis --*- C++ -*---===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8/// \file9/// Analysis that tracks defined/used subregister lanes across COPY instructions10/// and instructions that get lowered to a COPY (PHI, REG_SEQUENCE,11/// INSERT_SUBREG, EXTRACT_SUBREG).12/// The information is used to detect dead definitions and the usage of13/// (completely) undefined values and mark the operands as such.14/// This pass is necessary because the dead/undef status is not obvious anymore15/// when subregisters are involved.16///17/// Example:18/// %0 = some definition19/// %1 = IMPLICIT_DEF20/// %2 = REG_SEQUENCE %0, sub0, %1, sub121/// %3 = EXTRACT_SUBREG %2, sub122/// = use %323/// The %0 definition is dead and %3 contains an undefined value.24//25//===----------------------------------------------------------------------===//2627#include "llvm/CodeGen/DetectDeadLanes.h"28#include "llvm/CodeGen/MachineFunctionPass.h"29#include "llvm/CodeGen/MachineRegisterInfo.h"30#include "llvm/CodeGen/TargetRegisterInfo.h"31#include "llvm/InitializePasses.h"32#include "llvm/Pass.h"33#include "llvm/Support/Debug.h"34#include "llvm/Support/raw_ostream.h"3536using namespace llvm;3738#define DEBUG_TYPE "detect-dead-lanes"3940DeadLaneDetector::DeadLaneDetector(const MachineRegisterInfo *MRI,41const TargetRegisterInfo *TRI)42: MRI(MRI), TRI(TRI) {43unsigned NumVirtRegs = MRI->getNumVirtRegs();44VRegInfos = std::unique_ptr<VRegInfo[]>(new VRegInfo[NumVirtRegs]);45WorklistMembers.resize(NumVirtRegs);46DefinedByCopy.resize(NumVirtRegs);47}4849/// Returns true if \p MI will get lowered to a series of COPY instructions.50/// We call this a COPY-like instruction.51static bool lowersToCopies(const MachineInstr &MI) {52// Note: We could support instructions with MCInstrDesc::isRegSequenceLike(),53// isExtractSubRegLike(), isInsertSubregLike() in the future even though they54// are not lowered to a COPY.55switch (MI.getOpcode()) {56case TargetOpcode::COPY:57case TargetOpcode::PHI:58case TargetOpcode::INSERT_SUBREG:59case TargetOpcode::REG_SEQUENCE:60case TargetOpcode::EXTRACT_SUBREG:61return true;62}63return false;64}6566static bool isCrossCopy(const MachineRegisterInfo &MRI,67const MachineInstr &MI,68const TargetRegisterClass *DstRC,69const MachineOperand &MO) {70assert(lowersToCopies(MI));71Register SrcReg = MO.getReg();72const TargetRegisterClass *SrcRC = MRI.getRegClass(SrcReg);73if (DstRC == SrcRC)74return false;7576unsigned SrcSubIdx = MO.getSubReg();7778const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();79unsigned DstSubIdx = 0;80switch (MI.getOpcode()) {81case TargetOpcode::INSERT_SUBREG:82if (MO.getOperandNo() == 2)83DstSubIdx = MI.getOperand(3).getImm();84break;85case TargetOpcode::REG_SEQUENCE: {86unsigned OpNum = MO.getOperandNo();87DstSubIdx = MI.getOperand(OpNum+1).getImm();88break;89}90case TargetOpcode::EXTRACT_SUBREG: {91unsigned SubReg = MI.getOperand(2).getImm();92SrcSubIdx = TRI.composeSubRegIndices(SubReg, SrcSubIdx);93}94}9596unsigned PreA, PreB; // Unused.97if (SrcSubIdx && DstSubIdx)98return !TRI.getCommonSuperRegClass(SrcRC, SrcSubIdx, DstRC, DstSubIdx, PreA,99PreB);100if (SrcSubIdx)101return !TRI.getMatchingSuperRegClass(SrcRC, DstRC, SrcSubIdx);102if (DstSubIdx)103return !TRI.getMatchingSuperRegClass(DstRC, SrcRC, DstSubIdx);104return !TRI.getCommonSubClass(SrcRC, DstRC);105}106107void DeadLaneDetector::addUsedLanesOnOperand(const MachineOperand &MO,108LaneBitmask UsedLanes) {109if (!MO.readsReg())110return;111Register MOReg = MO.getReg();112if (!MOReg.isVirtual())113return;114115unsigned MOSubReg = MO.getSubReg();116if (MOSubReg != 0)117UsedLanes = TRI->composeSubRegIndexLaneMask(MOSubReg, UsedLanes);118UsedLanes &= MRI->getMaxLaneMaskForVReg(MOReg);119120unsigned MORegIdx = Register::virtReg2Index(MOReg);121DeadLaneDetector::VRegInfo &MORegInfo = VRegInfos[MORegIdx];122LaneBitmask PrevUsedLanes = MORegInfo.UsedLanes;123// Any change at all?124if ((UsedLanes & ~PrevUsedLanes).none())125return;126127// Set UsedLanes and remember instruction for further propagation.128MORegInfo.UsedLanes = PrevUsedLanes | UsedLanes;129if (DefinedByCopy.test(MORegIdx))130PutInWorklist(MORegIdx);131}132133void DeadLaneDetector::transferUsedLanesStep(const MachineInstr &MI,134LaneBitmask UsedLanes) {135for (const MachineOperand &MO : MI.uses()) {136if (!MO.isReg() || !MO.getReg().isVirtual())137continue;138LaneBitmask UsedOnMO = transferUsedLanes(MI, UsedLanes, MO);139addUsedLanesOnOperand(MO, UsedOnMO);140}141}142143LaneBitmask144DeadLaneDetector::transferUsedLanes(const MachineInstr &MI,145LaneBitmask UsedLanes,146const MachineOperand &MO) const {147unsigned OpNum = MO.getOperandNo();148assert(lowersToCopies(MI) &&149DefinedByCopy[Register::virtReg2Index(MI.getOperand(0).getReg())]);150151switch (MI.getOpcode()) {152case TargetOpcode::COPY:153case TargetOpcode::PHI:154return UsedLanes;155case TargetOpcode::REG_SEQUENCE: {156assert(OpNum % 2 == 1);157unsigned SubIdx = MI.getOperand(OpNum + 1).getImm();158return TRI->reverseComposeSubRegIndexLaneMask(SubIdx, UsedLanes);159}160case TargetOpcode::INSERT_SUBREG: {161unsigned SubIdx = MI.getOperand(3).getImm();162LaneBitmask MO2UsedLanes =163TRI->reverseComposeSubRegIndexLaneMask(SubIdx, UsedLanes);164if (OpNum == 2)165return MO2UsedLanes;166167const MachineOperand &Def = MI.getOperand(0);168Register DefReg = Def.getReg();169const TargetRegisterClass *RC = MRI->getRegClass(DefReg);170LaneBitmask MO1UsedLanes;171if (RC->CoveredBySubRegs)172MO1UsedLanes = UsedLanes & ~TRI->getSubRegIndexLaneMask(SubIdx);173else174MO1UsedLanes = RC->LaneMask;175176assert(OpNum == 1);177return MO1UsedLanes;178}179case TargetOpcode::EXTRACT_SUBREG: {180assert(OpNum == 1);181unsigned SubIdx = MI.getOperand(2).getImm();182return TRI->composeSubRegIndexLaneMask(SubIdx, UsedLanes);183}184default:185llvm_unreachable("function must be called with COPY-like instruction");186}187}188189void DeadLaneDetector::transferDefinedLanesStep(const MachineOperand &Use,190LaneBitmask DefinedLanes) {191if (!Use.readsReg())192return;193// Check whether the operand writes a vreg and is part of a COPY-like194// instruction.195const MachineInstr &MI = *Use.getParent();196if (MI.getDesc().getNumDefs() != 1)197return;198// FIXME: PATCHPOINT instructions announce a Def that does not always exist,199// they really need to be modeled differently!200if (MI.getOpcode() == TargetOpcode::PATCHPOINT)201return;202const MachineOperand &Def = *MI.defs().begin();203Register DefReg = Def.getReg();204if (!DefReg.isVirtual())205return;206unsigned DefRegIdx = Register::virtReg2Index(DefReg);207if (!DefinedByCopy.test(DefRegIdx))208return;209210unsigned OpNum = Use.getOperandNo();211DefinedLanes =212TRI->reverseComposeSubRegIndexLaneMask(Use.getSubReg(), DefinedLanes);213DefinedLanes = transferDefinedLanes(Def, OpNum, DefinedLanes);214215VRegInfo &RegInfo = VRegInfos[DefRegIdx];216LaneBitmask PrevDefinedLanes = RegInfo.DefinedLanes;217// Any change at all?218if ((DefinedLanes & ~PrevDefinedLanes).none())219return;220221RegInfo.DefinedLanes = PrevDefinedLanes | DefinedLanes;222PutInWorklist(DefRegIdx);223}224225LaneBitmask DeadLaneDetector::transferDefinedLanes(226const MachineOperand &Def, unsigned OpNum, LaneBitmask DefinedLanes) const {227const MachineInstr &MI = *Def.getParent();228// Translate DefinedLanes if necessary.229switch (MI.getOpcode()) {230case TargetOpcode::REG_SEQUENCE: {231unsigned SubIdx = MI.getOperand(OpNum + 1).getImm();232DefinedLanes = TRI->composeSubRegIndexLaneMask(SubIdx, DefinedLanes);233DefinedLanes &= TRI->getSubRegIndexLaneMask(SubIdx);234break;235}236case TargetOpcode::INSERT_SUBREG: {237unsigned SubIdx = MI.getOperand(3).getImm();238if (OpNum == 2) {239DefinedLanes = TRI->composeSubRegIndexLaneMask(SubIdx, DefinedLanes);240DefinedLanes &= TRI->getSubRegIndexLaneMask(SubIdx);241} else {242assert(OpNum == 1 && "INSERT_SUBREG must have two operands");243// Ignore lanes defined by operand 2.244DefinedLanes &= ~TRI->getSubRegIndexLaneMask(SubIdx);245}246break;247}248case TargetOpcode::EXTRACT_SUBREG: {249unsigned SubIdx = MI.getOperand(2).getImm();250assert(OpNum == 1 && "EXTRACT_SUBREG must have one register operand only");251DefinedLanes = TRI->reverseComposeSubRegIndexLaneMask(SubIdx, DefinedLanes);252break;253}254case TargetOpcode::COPY:255case TargetOpcode::PHI:256break;257default:258llvm_unreachable("function must be called with COPY-like instruction");259}260261assert(Def.getSubReg() == 0 &&262"Should not have subregister defs in machine SSA phase");263DefinedLanes &= MRI->getMaxLaneMaskForVReg(Def.getReg());264return DefinedLanes;265}266267LaneBitmask DeadLaneDetector::determineInitialDefinedLanes(unsigned Reg) {268// Live-In or unused registers have no definition but are considered fully269// defined.270if (!MRI->hasOneDef(Reg))271return LaneBitmask::getAll();272273const MachineOperand &Def = *MRI->def_begin(Reg);274const MachineInstr &DefMI = *Def.getParent();275if (lowersToCopies(DefMI)) {276// Start optimisatically with no used or defined lanes for copy277// instructions. The following dataflow analysis will add more bits.278unsigned RegIdx = Register::virtReg2Index(Reg);279DefinedByCopy.set(RegIdx);280PutInWorklist(RegIdx);281282if (Def.isDead())283return LaneBitmask::getNone();284285// COPY/PHI can copy across unrelated register classes (example: float/int)286// with incompatible subregister structure. Do not include these in the287// dataflow analysis since we cannot transfer lanemasks in a meaningful way.288const TargetRegisterClass *DefRC = MRI->getRegClass(Reg);289290// Determine initially DefinedLanes.291LaneBitmask DefinedLanes;292for (const MachineOperand &MO : DefMI.uses()) {293if (!MO.isReg() || !MO.readsReg())294continue;295Register MOReg = MO.getReg();296if (!MOReg)297continue;298299LaneBitmask MODefinedLanes;300if (MOReg.isPhysical()) {301MODefinedLanes = LaneBitmask::getAll();302} else if (isCrossCopy(*MRI, DefMI, DefRC, MO)) {303MODefinedLanes = LaneBitmask::getAll();304} else {305assert(MOReg.isVirtual());306if (MRI->hasOneDef(MOReg)) {307const MachineOperand &MODef = *MRI->def_begin(MOReg);308const MachineInstr &MODefMI = *MODef.getParent();309// Bits from copy-like operations will be added later.310if (lowersToCopies(MODefMI) || MODefMI.isImplicitDef())311continue;312}313unsigned MOSubReg = MO.getSubReg();314MODefinedLanes = MRI->getMaxLaneMaskForVReg(MOReg);315MODefinedLanes = TRI->reverseComposeSubRegIndexLaneMask(316MOSubReg, MODefinedLanes);317}318319unsigned OpNum = MO.getOperandNo();320DefinedLanes |= transferDefinedLanes(Def, OpNum, MODefinedLanes);321}322return DefinedLanes;323}324if (DefMI.isImplicitDef() || Def.isDead())325return LaneBitmask::getNone();326327assert(Def.getSubReg() == 0 &&328"Should not have subregister defs in machine SSA phase");329return MRI->getMaxLaneMaskForVReg(Reg);330}331332LaneBitmask DeadLaneDetector::determineInitialUsedLanes(unsigned Reg) {333LaneBitmask UsedLanes = LaneBitmask::getNone();334for (const MachineOperand &MO : MRI->use_nodbg_operands(Reg)) {335if (!MO.readsReg())336continue;337338const MachineInstr &UseMI = *MO.getParent();339if (UseMI.isKill())340continue;341342unsigned SubReg = MO.getSubReg();343if (lowersToCopies(UseMI)) {344assert(UseMI.getDesc().getNumDefs() == 1);345const MachineOperand &Def = *UseMI.defs().begin();346Register DefReg = Def.getReg();347// The used lanes of COPY-like instruction operands are determined by the348// following dataflow analysis.349if (DefReg.isVirtual()) {350// But ignore copies across incompatible register classes.351bool CrossCopy = false;352if (lowersToCopies(UseMI)) {353const TargetRegisterClass *DstRC = MRI->getRegClass(DefReg);354CrossCopy = isCrossCopy(*MRI, UseMI, DstRC, MO);355if (CrossCopy)356LLVM_DEBUG(dbgs() << "Copy across incompatible classes: " << UseMI);357}358359if (!CrossCopy)360continue;361}362}363364// Shortcut: All lanes are used.365if (SubReg == 0)366return MRI->getMaxLaneMaskForVReg(Reg);367368UsedLanes |= TRI->getSubRegIndexLaneMask(SubReg);369}370return UsedLanes;371}372373namespace {374375class DetectDeadLanes : public MachineFunctionPass {376public:377bool runOnMachineFunction(MachineFunction &MF) override;378379static char ID;380DetectDeadLanes() : MachineFunctionPass(ID) {}381382StringRef getPassName() const override { return "Detect Dead Lanes"; }383384void getAnalysisUsage(AnalysisUsage &AU) const override {385AU.setPreservesCFG();386MachineFunctionPass::getAnalysisUsage(AU);387}388389private:390/// update the operand status.391/// The first return value shows whether MF been changed.392/// The second return value indicates we need to call393/// DeadLaneDetector::computeSubRegisterLaneBitInfo and this function again394/// to propagate changes.395std::pair<bool, bool>396modifySubRegisterOperandStatus(const DeadLaneDetector &DLD,397MachineFunction &MF);398399bool isUndefRegAtInput(const MachineOperand &MO,400const DeadLaneDetector::VRegInfo &RegInfo) const;401402bool isUndefInput(const DeadLaneDetector &DLD, const MachineOperand &MO,403bool *CrossCopy) const;404405const MachineRegisterInfo *MRI = nullptr;406const TargetRegisterInfo *TRI = nullptr;407};408409} // end anonymous namespace410411char DetectDeadLanes::ID = 0;412char &llvm::DetectDeadLanesID = DetectDeadLanes::ID;413414INITIALIZE_PASS(DetectDeadLanes, DEBUG_TYPE, "Detect Dead Lanes", false, false)415416bool DetectDeadLanes::isUndefRegAtInput(417const MachineOperand &MO, const DeadLaneDetector::VRegInfo &RegInfo) const {418unsigned SubReg = MO.getSubReg();419LaneBitmask Mask = TRI->getSubRegIndexLaneMask(SubReg);420return (RegInfo.DefinedLanes & RegInfo.UsedLanes & Mask).none();421}422423bool DetectDeadLanes::isUndefInput(const DeadLaneDetector &DLD,424const MachineOperand &MO,425bool *CrossCopy) const {426if (!MO.isUse())427return false;428const MachineInstr &MI = *MO.getParent();429if (!lowersToCopies(MI))430return false;431const MachineOperand &Def = MI.getOperand(0);432Register DefReg = Def.getReg();433if (!DefReg.isVirtual())434return false;435unsigned DefRegIdx = Register::virtReg2Index(DefReg);436if (!DLD.isDefinedByCopy(DefRegIdx))437return false;438439const DeadLaneDetector::VRegInfo &DefRegInfo = DLD.getVRegInfo(DefRegIdx);440LaneBitmask UsedLanes = DLD.transferUsedLanes(MI, DefRegInfo.UsedLanes, MO);441if (UsedLanes.any())442return false;443444Register MOReg = MO.getReg();445if (MOReg.isVirtual()) {446const TargetRegisterClass *DstRC = MRI->getRegClass(DefReg);447*CrossCopy = isCrossCopy(*MRI, MI, DstRC, MO);448}449return true;450}451452void DeadLaneDetector::computeSubRegisterLaneBitInfo() {453// First pass: Populate defs/uses of vregs with initial values454unsigned NumVirtRegs = MRI->getNumVirtRegs();455for (unsigned RegIdx = 0; RegIdx < NumVirtRegs; ++RegIdx) {456Register Reg = Register::index2VirtReg(RegIdx);457458// Determine used/defined lanes and add copy instructions to worklist.459VRegInfo &Info = VRegInfos[RegIdx];460Info.DefinedLanes = determineInitialDefinedLanes(Reg);461Info.UsedLanes = determineInitialUsedLanes(Reg);462}463464// Iterate as long as defined lanes/used lanes keep changing.465while (!Worklist.empty()) {466unsigned RegIdx = Worklist.front();467Worklist.pop_front();468WorklistMembers.reset(RegIdx);469VRegInfo &Info = VRegInfos[RegIdx];470Register Reg = Register::index2VirtReg(RegIdx);471472// Transfer UsedLanes to operands of DefMI (backwards dataflow).473MachineOperand &Def = *MRI->def_begin(Reg);474const MachineInstr &MI = *Def.getParent();475transferUsedLanesStep(MI, Info.UsedLanes);476// Transfer DefinedLanes to users of Reg (forward dataflow).477for (const MachineOperand &MO : MRI->use_nodbg_operands(Reg))478transferDefinedLanesStep(MO, Info.DefinedLanes);479}480481LLVM_DEBUG({482dbgs() << "Defined/Used lanes:\n";483for (unsigned RegIdx = 0; RegIdx < NumVirtRegs; ++RegIdx) {484Register Reg = Register::index2VirtReg(RegIdx);485const VRegInfo &Info = VRegInfos[RegIdx];486dbgs() << printReg(Reg, nullptr)487<< " Used: " << PrintLaneMask(Info.UsedLanes)488<< " Def: " << PrintLaneMask(Info.DefinedLanes) << '\n';489}490dbgs() << "\n";491});492}493494std::pair<bool, bool>495DetectDeadLanes::modifySubRegisterOperandStatus(const DeadLaneDetector &DLD,496MachineFunction &MF) {497bool Changed = false;498bool Again = false;499// Mark operands as dead/unused.500for (MachineBasicBlock &MBB : MF) {501for (MachineInstr &MI : MBB) {502for (MachineOperand &MO : MI.operands()) {503if (!MO.isReg())504continue;505Register Reg = MO.getReg();506if (!Reg.isVirtual())507continue;508unsigned RegIdx = Register::virtReg2Index(Reg);509const DeadLaneDetector::VRegInfo &RegInfo = DLD.getVRegInfo(RegIdx);510if (MO.isDef() && !MO.isDead() && RegInfo.UsedLanes.none()) {511LLVM_DEBUG(dbgs()512<< "Marking operand '" << MO << "' as dead in " << MI);513MO.setIsDead();514Changed = true;515}516if (MO.readsReg()) {517bool CrossCopy = false;518if (isUndefRegAtInput(MO, RegInfo)) {519LLVM_DEBUG(dbgs()520<< "Marking operand '" << MO << "' as undef in " << MI);521MO.setIsUndef();522Changed = true;523} else if (isUndefInput(DLD, MO, &CrossCopy)) {524LLVM_DEBUG(dbgs()525<< "Marking operand '" << MO << "' as undef in " << MI);526MO.setIsUndef();527Changed = true;528if (CrossCopy)529Again = true;530}531}532}533}534}535536return std::make_pair(Changed, Again);537}538539bool DetectDeadLanes::runOnMachineFunction(MachineFunction &MF) {540// Don't bother if we won't track subregister liveness later. This pass is541// required for correctness if subregister liveness is enabled because the542// register coalescer cannot deal with hidden dead defs. However without543// subregister liveness enabled, the expected benefits of this pass are small544// so we safe the compile time.545MRI = &MF.getRegInfo();546if (!MRI->subRegLivenessEnabled()) {547LLVM_DEBUG(dbgs() << "Skipping Detect dead lanes pass\n");548return false;549}550551TRI = MRI->getTargetRegisterInfo();552553DeadLaneDetector DLD(MRI, TRI);554555bool Changed = false;556bool Again;557do {558DLD.computeSubRegisterLaneBitInfo();559bool LocalChanged;560std::tie(LocalChanged, Again) = modifySubRegisterOperandStatus(DLD, MF);561Changed |= LocalChanged;562} while (Again);563564return Changed;565}566567568