10fca6ea1SDimitry Andric //===- InitUndef.cpp - Initialize undef value to pseudo ----===// 20fca6ea1SDimitry Andric // 30fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60fca6ea1SDimitry Andric // 70fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 80fca6ea1SDimitry Andric // 90fca6ea1SDimitry Andric // This file implements a function pass that initializes undef value to 100fca6ea1SDimitry Andric // temporary pseudo instruction to prevent register allocation resulting in a 110fca6ea1SDimitry Andric // constraint violated result for the particular instruction. It also rewrites 120fca6ea1SDimitry Andric // the NoReg tied operand back to an IMPLICIT_DEF. 130fca6ea1SDimitry Andric // 140fca6ea1SDimitry Andric // Certain instructions have register overlapping constraints, and 150fca6ea1SDimitry Andric // will cause illegal instruction trap if violated, we use early clobber to 160fca6ea1SDimitry Andric // model this constraint, but it can't prevent register allocator allocating 170fca6ea1SDimitry Andric // same or overlapped if the input register is undef value, so convert 180fca6ea1SDimitry Andric // IMPLICIT_DEF to temporary pseudo instruction and remove it later could 190fca6ea1SDimitry Andric // prevent that happen, it's not best way to resolve this, and it might 200fca6ea1SDimitry Andric // change the order of program or increase the register pressure, so ideally we 210fca6ea1SDimitry Andric // should model the constraint right, but before we model the constraint right, 220fca6ea1SDimitry Andric // it's the only way to prevent that happen. 230fca6ea1SDimitry Andric // 240fca6ea1SDimitry Andric // When we enable the subregister liveness option, it will also trigger the same 250fca6ea1SDimitry Andric // issue due to the partial of register is undef. If we pseudoinit the whole 260fca6ea1SDimitry Andric // register, then it will generate redundant COPY instruction. Currently, it 270fca6ea1SDimitry Andric // will generate INSERT_SUBREG to make sure the whole register is occupied 280fca6ea1SDimitry Andric // when program encounter operation that has early-clobber constraint. 290fca6ea1SDimitry Andric // 300fca6ea1SDimitry Andric // 310fca6ea1SDimitry Andric // See also: https://github.com/llvm/llvm-project/issues/50157 320fca6ea1SDimitry Andric // 330fca6ea1SDimitry Andric // Additionally, this pass rewrites tied operands of instructions 340fca6ea1SDimitry Andric // from NoReg to IMPLICIT_DEF. (Not that this is a non-overlapping set of 350fca6ea1SDimitry Andric // operands to the above.) We use NoReg to side step a MachineCSE 360fca6ea1SDimitry Andric // optimization quality problem but need to convert back before 370fca6ea1SDimitry Andric // TwoAddressInstruction. See pr64282 for context. 380fca6ea1SDimitry Andric // 390fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 400fca6ea1SDimitry Andric 410fca6ea1SDimitry Andric #include "llvm/ADT/SmallSet.h" 420fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h" 430fca6ea1SDimitry Andric #include "llvm/CodeGen/DetectDeadLanes.h" 440fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 450fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 460fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 470fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 480fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 490fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 500fca6ea1SDimitry Andric #include "llvm/InitializePasses.h" 510fca6ea1SDimitry Andric #include "llvm/MC/MCRegister.h" 520fca6ea1SDimitry Andric #include "llvm/Pass.h" 530fca6ea1SDimitry Andric #include "llvm/Support/Debug.h" 540fca6ea1SDimitry Andric 550fca6ea1SDimitry Andric using namespace llvm; 560fca6ea1SDimitry Andric 570fca6ea1SDimitry Andric #define DEBUG_TYPE "init-undef" 580fca6ea1SDimitry Andric #define INIT_UNDEF_NAME "Init Undef Pass" 590fca6ea1SDimitry Andric 600fca6ea1SDimitry Andric namespace { 610fca6ea1SDimitry Andric 620fca6ea1SDimitry Andric class InitUndef : public MachineFunctionPass { 630fca6ea1SDimitry Andric const TargetInstrInfo *TII; 640fca6ea1SDimitry Andric MachineRegisterInfo *MRI; 650fca6ea1SDimitry Andric const TargetSubtargetInfo *ST; 660fca6ea1SDimitry Andric const TargetRegisterInfo *TRI; 670fca6ea1SDimitry Andric 680fca6ea1SDimitry Andric // Newly added vregs, assumed to be fully rewritten 690fca6ea1SDimitry Andric SmallSet<Register, 8> NewRegs; 700fca6ea1SDimitry Andric SmallVector<MachineInstr *, 8> DeadInsts; 710fca6ea1SDimitry Andric 720fca6ea1SDimitry Andric public: 730fca6ea1SDimitry Andric static char ID; 740fca6ea1SDimitry Andric 750fca6ea1SDimitry Andric InitUndef() : MachineFunctionPass(ID) {} 760fca6ea1SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 770fca6ea1SDimitry Andric 780fca6ea1SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 790fca6ea1SDimitry Andric AU.setPreservesCFG(); 800fca6ea1SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 810fca6ea1SDimitry Andric } 820fca6ea1SDimitry Andric 830fca6ea1SDimitry Andric StringRef getPassName() const override { return INIT_UNDEF_NAME; } 840fca6ea1SDimitry Andric 850fca6ea1SDimitry Andric private: 860fca6ea1SDimitry Andric bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB, 870fca6ea1SDimitry Andric const DeadLaneDetector &DLD); 880fca6ea1SDimitry Andric bool handleSubReg(MachineFunction &MF, MachineInstr &MI, 890fca6ea1SDimitry Andric const DeadLaneDetector &DLD); 900fca6ea1SDimitry Andric bool fixupIllOperand(MachineInstr *MI, MachineOperand &MO); 910fca6ea1SDimitry Andric bool handleReg(MachineInstr *MI); 920fca6ea1SDimitry Andric }; 930fca6ea1SDimitry Andric 940fca6ea1SDimitry Andric } // end anonymous namespace 950fca6ea1SDimitry Andric 960fca6ea1SDimitry Andric char InitUndef::ID = 0; 970fca6ea1SDimitry Andric INITIALIZE_PASS(InitUndef, DEBUG_TYPE, INIT_UNDEF_NAME, false, false) 980fca6ea1SDimitry Andric char &llvm::InitUndefID = InitUndef::ID; 990fca6ea1SDimitry Andric 1000fca6ea1SDimitry Andric static bool isEarlyClobberMI(MachineInstr &MI) { 1010fca6ea1SDimitry Andric return llvm::any_of(MI.defs(), [](const MachineOperand &DefMO) { 1020fca6ea1SDimitry Andric return DefMO.isReg() && DefMO.isEarlyClobber(); 1030fca6ea1SDimitry Andric }); 1040fca6ea1SDimitry Andric } 1050fca6ea1SDimitry Andric 1060fca6ea1SDimitry Andric static bool findImplictDefMIFromReg(Register Reg, MachineRegisterInfo *MRI) { 1070fca6ea1SDimitry Andric for (auto &DefMI : MRI->def_instructions(Reg)) { 1080fca6ea1SDimitry Andric if (DefMI.getOpcode() == TargetOpcode::IMPLICIT_DEF) 1090fca6ea1SDimitry Andric return true; 1100fca6ea1SDimitry Andric } 1110fca6ea1SDimitry Andric return false; 1120fca6ea1SDimitry Andric } 1130fca6ea1SDimitry Andric 1140fca6ea1SDimitry Andric bool InitUndef::handleReg(MachineInstr *MI) { 1150fca6ea1SDimitry Andric bool Changed = false; 1160fca6ea1SDimitry Andric for (auto &UseMO : MI->uses()) { 1170fca6ea1SDimitry Andric if (!UseMO.isReg()) 1180fca6ea1SDimitry Andric continue; 1190fca6ea1SDimitry Andric if (UseMO.isTied()) 1200fca6ea1SDimitry Andric continue; 1210fca6ea1SDimitry Andric if (!UseMO.getReg().isVirtual()) 1220fca6ea1SDimitry Andric continue; 1230fca6ea1SDimitry Andric if (!TRI->doesRegClassHavePseudoInitUndef(MRI->getRegClass(UseMO.getReg()))) 1240fca6ea1SDimitry Andric continue; 1250fca6ea1SDimitry Andric 1260fca6ea1SDimitry Andric if (UseMO.isUndef() || findImplictDefMIFromReg(UseMO.getReg(), MRI)) 1270fca6ea1SDimitry Andric Changed |= fixupIllOperand(MI, UseMO); 1280fca6ea1SDimitry Andric } 1290fca6ea1SDimitry Andric return Changed; 1300fca6ea1SDimitry Andric } 1310fca6ea1SDimitry Andric 1320fca6ea1SDimitry Andric bool InitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI, 1330fca6ea1SDimitry Andric const DeadLaneDetector &DLD) { 1340fca6ea1SDimitry Andric bool Changed = false; 1350fca6ea1SDimitry Andric 1360fca6ea1SDimitry Andric for (MachineOperand &UseMO : MI.uses()) { 1370fca6ea1SDimitry Andric if (!UseMO.isReg()) 1380fca6ea1SDimitry Andric continue; 1390fca6ea1SDimitry Andric if (!UseMO.getReg().isVirtual()) 1400fca6ea1SDimitry Andric continue; 1410fca6ea1SDimitry Andric if (UseMO.isTied()) 1420fca6ea1SDimitry Andric continue; 1430fca6ea1SDimitry Andric if (!TRI->doesRegClassHavePseudoInitUndef(MRI->getRegClass(UseMO.getReg()))) 1440fca6ea1SDimitry Andric continue; 1450fca6ea1SDimitry Andric 1460fca6ea1SDimitry Andric Register Reg = UseMO.getReg(); 1470fca6ea1SDimitry Andric if (NewRegs.count(Reg)) 1480fca6ea1SDimitry Andric continue; 1490fca6ea1SDimitry Andric DeadLaneDetector::VRegInfo Info = 1500fca6ea1SDimitry Andric DLD.getVRegInfo(Register::virtReg2Index(Reg)); 1510fca6ea1SDimitry Andric 1520fca6ea1SDimitry Andric if (Info.UsedLanes == Info.DefinedLanes) 1530fca6ea1SDimitry Andric continue; 1540fca6ea1SDimitry Andric 1550fca6ea1SDimitry Andric const TargetRegisterClass *TargetRegClass = 1560fca6ea1SDimitry Andric TRI->getLargestSuperClass(MRI->getRegClass(Reg)); 1570fca6ea1SDimitry Andric 1580fca6ea1SDimitry Andric LaneBitmask NeedDef = Info.UsedLanes & ~Info.DefinedLanes; 1590fca6ea1SDimitry Andric 1600fca6ea1SDimitry Andric LLVM_DEBUG({ 1610fca6ea1SDimitry Andric dbgs() << "Instruction has undef subregister.\n"; 1620fca6ea1SDimitry Andric dbgs() << printReg(Reg, nullptr) 1630fca6ea1SDimitry Andric << " Used: " << PrintLaneMask(Info.UsedLanes) 1640fca6ea1SDimitry Andric << " Def: " << PrintLaneMask(Info.DefinedLanes) 1650fca6ea1SDimitry Andric << " Need Def: " << PrintLaneMask(NeedDef) << "\n"; 1660fca6ea1SDimitry Andric }); 1670fca6ea1SDimitry Andric 1680fca6ea1SDimitry Andric SmallVector<unsigned> SubRegIndexNeedInsert; 1690fca6ea1SDimitry Andric TRI->getCoveringSubRegIndexes(*MRI, TargetRegClass, NeedDef, 1700fca6ea1SDimitry Andric SubRegIndexNeedInsert); 1710fca6ea1SDimitry Andric 1720fca6ea1SDimitry Andric Register LatestReg = Reg; 1730fca6ea1SDimitry Andric for (auto ind : SubRegIndexNeedInsert) { 1740fca6ea1SDimitry Andric Changed = true; 1750fca6ea1SDimitry Andric const TargetRegisterClass *SubRegClass = TRI->getLargestSuperClass( 1760fca6ea1SDimitry Andric TRI->getSubRegisterClass(TargetRegClass, ind)); 1770fca6ea1SDimitry Andric Register TmpInitSubReg = MRI->createVirtualRegister(SubRegClass); 1780fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << "Register Class ID" << SubRegClass->getID() << "\n"); 1790fca6ea1SDimitry Andric BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(), 1800fca6ea1SDimitry Andric TII->get(TII->getUndefInitOpcode(SubRegClass->getID())), 1810fca6ea1SDimitry Andric TmpInitSubReg); 1820fca6ea1SDimitry Andric Register NewReg = MRI->createVirtualRegister(TargetRegClass); 1830fca6ea1SDimitry Andric BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(), 1840fca6ea1SDimitry Andric TII->get(TargetOpcode::INSERT_SUBREG), NewReg) 1850fca6ea1SDimitry Andric .addReg(LatestReg) 1860fca6ea1SDimitry Andric .addReg(TmpInitSubReg) 1870fca6ea1SDimitry Andric .addImm(ind); 1880fca6ea1SDimitry Andric LatestReg = NewReg; 1890fca6ea1SDimitry Andric } 1900fca6ea1SDimitry Andric 1910fca6ea1SDimitry Andric UseMO.setReg(LatestReg); 1920fca6ea1SDimitry Andric } 1930fca6ea1SDimitry Andric 1940fca6ea1SDimitry Andric return Changed; 1950fca6ea1SDimitry Andric } 1960fca6ea1SDimitry Andric 1970fca6ea1SDimitry Andric bool InitUndef::fixupIllOperand(MachineInstr *MI, MachineOperand &MO) { 1980fca6ea1SDimitry Andric 1990fca6ea1SDimitry Andric LLVM_DEBUG( 2000fca6ea1SDimitry Andric dbgs() << "Emitting PseudoInitUndef Instruction for implicit register " 2010fca6ea1SDimitry Andric << MO.getReg() << '\n'); 2020fca6ea1SDimitry Andric 2030fca6ea1SDimitry Andric const TargetRegisterClass *TargetRegClass = 2040fca6ea1SDimitry Andric TRI->getLargestSuperClass(MRI->getRegClass(MO.getReg())); 2050fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << "Register Class ID" << TargetRegClass->getID() << "\n"); 2060fca6ea1SDimitry Andric unsigned Opcode = TII->getUndefInitOpcode(TargetRegClass->getID()); 2070fca6ea1SDimitry Andric Register NewReg = MRI->createVirtualRegister(TargetRegClass); 2080fca6ea1SDimitry Andric BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(Opcode), NewReg); 2090fca6ea1SDimitry Andric MO.setReg(NewReg); 2100fca6ea1SDimitry Andric if (MO.isUndef()) 2110fca6ea1SDimitry Andric MO.setIsUndef(false); 2120fca6ea1SDimitry Andric return true; 2130fca6ea1SDimitry Andric } 2140fca6ea1SDimitry Andric 2150fca6ea1SDimitry Andric bool InitUndef::processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB, 2160fca6ea1SDimitry Andric const DeadLaneDetector &DLD) { 2170fca6ea1SDimitry Andric bool Changed = false; 2180fca6ea1SDimitry Andric for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { 2190fca6ea1SDimitry Andric MachineInstr &MI = *I; 2200fca6ea1SDimitry Andric 2210fca6ea1SDimitry Andric // If we used NoReg to represent the passthru, switch this back to being 2220fca6ea1SDimitry Andric // an IMPLICIT_DEF before TwoAddressInstructions. 2230fca6ea1SDimitry Andric unsigned UseOpIdx; 2240fca6ea1SDimitry Andric if (MI.getNumDefs() != 0 && MI.isRegTiedToUseOperand(0, &UseOpIdx)) { 2250fca6ea1SDimitry Andric MachineOperand &UseMO = MI.getOperand(UseOpIdx); 2260fca6ea1SDimitry Andric if (UseMO.getReg() == MCRegister::NoRegister) { 2270fca6ea1SDimitry Andric const TargetRegisterClass *RC = 2280fca6ea1SDimitry Andric TII->getRegClass(MI.getDesc(), UseOpIdx, TRI, MF); 2290fca6ea1SDimitry Andric Register NewDest = MRI->createVirtualRegister(RC); 2300fca6ea1SDimitry Andric // We don't have a way to update dead lanes, so keep track of the 2310fca6ea1SDimitry Andric // new register so that we avoid querying it later. 2320fca6ea1SDimitry Andric NewRegs.insert(NewDest); 2330fca6ea1SDimitry Andric BuildMI(MBB, I, I->getDebugLoc(), TII->get(TargetOpcode::IMPLICIT_DEF), 2340fca6ea1SDimitry Andric NewDest); 2350fca6ea1SDimitry Andric UseMO.setReg(NewDest); 2360fca6ea1SDimitry Andric Changed = true; 2370fca6ea1SDimitry Andric } 2380fca6ea1SDimitry Andric } 2390fca6ea1SDimitry Andric 2400fca6ea1SDimitry Andric if (isEarlyClobberMI(MI)) { 2410fca6ea1SDimitry Andric if (MRI->subRegLivenessEnabled()) 2420fca6ea1SDimitry Andric Changed |= handleSubReg(MF, MI, DLD); 2430fca6ea1SDimitry Andric Changed |= handleReg(&MI); 2440fca6ea1SDimitry Andric } 2450fca6ea1SDimitry Andric } 2460fca6ea1SDimitry Andric return Changed; 2470fca6ea1SDimitry Andric } 2480fca6ea1SDimitry Andric 2490fca6ea1SDimitry Andric bool InitUndef::runOnMachineFunction(MachineFunction &MF) { 2500fca6ea1SDimitry Andric ST = &MF.getSubtarget(); 2510fca6ea1SDimitry Andric 2520fca6ea1SDimitry Andric // supportsInitUndef is implemented to reflect if an architecture has support 2530fca6ea1SDimitry Andric // for the InitUndef pass. Support comes from having the relevant Pseudo 2540fca6ea1SDimitry Andric // instructions that can be used to initialize the register. The function 2550fca6ea1SDimitry Andric // returns false by default so requires an implementation per architecture. 2560fca6ea1SDimitry Andric // Support can be added by overriding the function in a way that best fits 2570fca6ea1SDimitry Andric // the architecture. 2580fca6ea1SDimitry Andric if (!ST->supportsInitUndef()) 2590fca6ea1SDimitry Andric return false; 2600fca6ea1SDimitry Andric 2610fca6ea1SDimitry Andric MRI = &MF.getRegInfo(); 2620fca6ea1SDimitry Andric TII = ST->getInstrInfo(); 2630fca6ea1SDimitry Andric TRI = MRI->getTargetRegisterInfo(); 2640fca6ea1SDimitry Andric 2650fca6ea1SDimitry Andric bool Changed = false; 2660fca6ea1SDimitry Andric DeadLaneDetector DLD(MRI, TRI); 2670fca6ea1SDimitry Andric DLD.computeSubRegisterLaneBitInfo(); 2680fca6ea1SDimitry Andric 2690fca6ea1SDimitry Andric for (MachineBasicBlock &BB : MF) 2700fca6ea1SDimitry Andric Changed |= processBasicBlock(MF, BB, DLD); 2710fca6ea1SDimitry Andric 2720fca6ea1SDimitry Andric for (auto *DeadMI : DeadInsts) 2730fca6ea1SDimitry Andric DeadMI->eraseFromParent(); 2740fca6ea1SDimitry Andric DeadInsts.clear(); 275*6e516c87SDimitry Andric NewRegs.clear(); 2760fca6ea1SDimitry Andric 2770fca6ea1SDimitry Andric return Changed; 2780fca6ea1SDimitry Andric } 279