1 //===- RISCVRVVInitUndef.cpp - Initialize undef vector value to pseudo ----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements a function pass that initializes undef vector value to 10 // temporary pseudo instruction and remove it in expandpseudo pass to prevent 11 // register allocation resulting in a constraint violated result for vector 12 // instruction. 13 // 14 // RISC-V vector instruction has register overlapping constraint for certain 15 // instructions, and will cause illegal instruction trap if violated, we use 16 // early clobber to model this constraint, but it can't prevent register 17 // allocator allocated same or overlapped if the input register is undef value, 18 // so convert IMPLICIT_DEF to temporary pseudo instruction and remove it later 19 // could prevent that happen, it's not best way to resolve this, and it might 20 // change the order of program or increase the register pressure, so ideally we 21 // should model the constraint right, but before we model the constraint right, 22 // it's the only way to prevent that happen. 23 // 24 // When we enable the subregister liveness option, it will also trigger same 25 // issue due to the partial of register is undef. If we pseudoinit the whole 26 // register, then it will generate redundant COPY instruction. Currently, it 27 // will generate INSERT_SUBREG to make sure the whole register is occupied 28 // when program encounter operation that has early-clobber constraint. 29 // 30 // 31 // See also: https://github.com/llvm/llvm-project/issues/50157 32 // 33 //===----------------------------------------------------------------------===// 34 35 #include "RISCV.h" 36 #include "RISCVSubtarget.h" 37 #include "llvm/CodeGen/DetectDeadLanes.h" 38 #include "llvm/CodeGen/MachineFunctionPass.h" 39 using namespace llvm; 40 41 #define DEBUG_TYPE "riscv-init-undef" 42 #define RISCV_INIT_UNDEF_NAME "RISC-V init undef pass" 43 44 namespace { 45 46 class RISCVInitUndef : public MachineFunctionPass { 47 const TargetInstrInfo *TII; 48 MachineRegisterInfo *MRI; 49 const RISCVSubtarget *ST; 50 const TargetRegisterInfo *TRI; 51 52 public: 53 static char ID; 54 55 RISCVInitUndef() : MachineFunctionPass(ID) { 56 initializeRISCVInitUndefPass(*PassRegistry::getPassRegistry()); 57 } 58 bool runOnMachineFunction(MachineFunction &MF) override; 59 60 void getAnalysisUsage(AnalysisUsage &AU) const override { 61 AU.setPreservesCFG(); 62 MachineFunctionPass::getAnalysisUsage(AU); 63 } 64 65 StringRef getPassName() const override { return RISCV_INIT_UNDEF_NAME; } 66 67 private: 68 bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB, 69 const DeadLaneDetector &DLD); 70 bool handleImplicitDef(MachineBasicBlock &MBB, 71 MachineBasicBlock::iterator &Inst); 72 bool isVectorRegClass(const Register R); 73 const TargetRegisterClass * 74 getVRLargestSuperClass(const TargetRegisterClass *RC) const; 75 bool handleSubReg(MachineFunction &MF, MachineInstr &MI, 76 const DeadLaneDetector &DLD); 77 }; 78 79 } // end anonymous namespace 80 81 char RISCVInitUndef::ID = 0; 82 INITIALIZE_PASS(RISCVInitUndef, DEBUG_TYPE, RISCV_INIT_UNDEF_NAME, false, false) 83 char &llvm::RISCVInitUndefID = RISCVInitUndef::ID; 84 85 const TargetRegisterClass * 86 RISCVInitUndef::getVRLargestSuperClass(const TargetRegisterClass *RC) const { 87 if (RISCV::VRM8RegClass.hasSubClassEq(RC)) 88 return &RISCV::VRM8RegClass; 89 if (RISCV::VRM4RegClass.hasSubClassEq(RC)) 90 return &RISCV::VRM4RegClass; 91 if (RISCV::VRM2RegClass.hasSubClassEq(RC)) 92 return &RISCV::VRM2RegClass; 93 if (RISCV::VRRegClass.hasSubClassEq(RC)) 94 return &RISCV::VRRegClass; 95 return RC; 96 } 97 98 bool RISCVInitUndef::isVectorRegClass(const Register R) { 99 const TargetRegisterClass *RC = MRI->getRegClass(R); 100 return RISCV::VRRegClass.hasSubClassEq(RC) || 101 RISCV::VRM2RegClass.hasSubClassEq(RC) || 102 RISCV::VRM4RegClass.hasSubClassEq(RC) || 103 RISCV::VRM8RegClass.hasSubClassEq(RC); 104 } 105 106 static unsigned getUndefInitOpcode(unsigned RegClassID) { 107 switch (RegClassID) { 108 case RISCV::VRRegClassID: 109 return RISCV::PseudoRVVInitUndefM1; 110 case RISCV::VRM2RegClassID: 111 return RISCV::PseudoRVVInitUndefM2; 112 case RISCV::VRM4RegClassID: 113 return RISCV::PseudoRVVInitUndefM4; 114 case RISCV::VRM8RegClassID: 115 return RISCV::PseudoRVVInitUndefM8; 116 default: 117 llvm_unreachable("Unexpected register class."); 118 } 119 } 120 121 bool RISCVInitUndef::handleImplicitDef(MachineBasicBlock &MBB, 122 MachineBasicBlock::iterator &Inst) { 123 const TargetRegisterInfo &TRI = 124 *MBB.getParent()->getSubtarget().getRegisterInfo(); 125 126 assert(Inst->getOpcode() == TargetOpcode::IMPLICIT_DEF); 127 128 Register Reg = Inst->getOperand(0).getReg(); 129 if (!Reg.isVirtual()) 130 return false; 131 132 bool NeedPseudoInit = false; 133 SmallVector<MachineOperand *, 1> UseMOs; 134 for (MachineOperand &MO : MRI->use_nodbg_operands(Reg)) { 135 MachineInstr *UserMI = MO.getParent(); 136 137 bool HasEarlyClobber = false; 138 bool TiedToDef = false; 139 for (MachineOperand &UserMO : UserMI->operands()) { 140 if (!UserMO.isReg()) 141 continue; 142 if (UserMO.isEarlyClobber()) 143 HasEarlyClobber = true; 144 if (UserMO.isUse() && UserMO.isTied() && 145 TRI.regsOverlap(UserMO.getReg(), Reg)) 146 TiedToDef = true; 147 } 148 if (HasEarlyClobber && !TiedToDef) { 149 NeedPseudoInit = true; 150 UseMOs.push_back(&MO); 151 } 152 } 153 154 if (!NeedPseudoInit) 155 return false; 156 157 LLVM_DEBUG( 158 dbgs() << "Emitting PseudoRVVInitUndef for implicit vector register " 159 << Reg << '\n'); 160 161 unsigned RegClassID = getVRLargestSuperClass(MRI->getRegClass(Reg))->getID(); 162 unsigned Opcode = getUndefInitOpcode(RegClassID); 163 164 BuildMI(MBB, Inst, Inst->getDebugLoc(), TII->get(Opcode), Reg); 165 166 Inst = MBB.erase(Inst); 167 168 for (auto MO : UseMOs) 169 MO->setIsUndef(false); 170 171 return true; 172 } 173 174 static bool isEarlyClobberMI(MachineInstr &MI) { 175 return llvm::any_of(MI.defs(), [](const MachineOperand &DefMO) { 176 return DefMO.isReg() && DefMO.isEarlyClobber(); 177 }); 178 } 179 180 bool RISCVInitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI, 181 const DeadLaneDetector &DLD) { 182 bool Changed = false; 183 184 for (MachineOperand &UseMO : MI.uses()) { 185 if (!UseMO.isReg()) 186 continue; 187 if (!UseMO.getReg().isVirtual()) 188 continue; 189 190 Register Reg = UseMO.getReg(); 191 DeadLaneDetector::VRegInfo Info = 192 DLD.getVRegInfo(Register::virtReg2Index(Reg)); 193 194 if (Info.UsedLanes == Info.DefinedLanes) 195 continue; 196 197 const TargetRegisterClass *TargetRegClass = 198 getVRLargestSuperClass(MRI->getRegClass(Reg)); 199 200 LaneBitmask NeedDef = Info.UsedLanes & ~Info.DefinedLanes; 201 202 LLVM_DEBUG({ 203 dbgs() << "Instruction has undef subregister.\n"; 204 dbgs() << printReg(Reg, nullptr) 205 << " Used: " << PrintLaneMask(Info.UsedLanes) 206 << " Def: " << PrintLaneMask(Info.DefinedLanes) 207 << " Need Def: " << PrintLaneMask(NeedDef) << "\n"; 208 }); 209 210 SmallVector<unsigned> SubRegIndexNeedInsert; 211 TRI->getCoveringSubRegIndexes(*MRI, TargetRegClass, NeedDef, 212 SubRegIndexNeedInsert); 213 214 Register LatestReg = Reg; 215 for (auto ind : SubRegIndexNeedInsert) { 216 Changed = true; 217 const TargetRegisterClass *SubRegClass = 218 getVRLargestSuperClass(TRI->getSubRegisterClass(TargetRegClass, ind)); 219 Register TmpInitSubReg = MRI->createVirtualRegister(SubRegClass); 220 BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(), 221 TII->get(getUndefInitOpcode(SubRegClass->getID())), 222 TmpInitSubReg); 223 Register NewReg = MRI->createVirtualRegister(TargetRegClass); 224 BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(), 225 TII->get(TargetOpcode::INSERT_SUBREG), NewReg) 226 .addReg(LatestReg) 227 .addReg(TmpInitSubReg) 228 .addImm(ind); 229 LatestReg = NewReg; 230 } 231 232 UseMO.setReg(LatestReg); 233 } 234 235 return Changed; 236 } 237 238 bool RISCVInitUndef::processBasicBlock(MachineFunction &MF, 239 MachineBasicBlock &MBB, 240 const DeadLaneDetector &DLD) { 241 bool Changed = false; 242 for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { 243 MachineInstr &MI = *I; 244 if (ST->enableSubRegLiveness() && isEarlyClobberMI(MI)) 245 Changed |= handleSubReg(MF, MI, DLD); 246 if (MI.isImplicitDef()) { 247 auto DstReg = MI.getOperand(0).getReg(); 248 if (isVectorRegClass(DstReg)) 249 Changed |= handleImplicitDef(MBB, I); 250 } 251 } 252 return Changed; 253 } 254 255 bool RISCVInitUndef::runOnMachineFunction(MachineFunction &MF) { 256 ST = &MF.getSubtarget<RISCVSubtarget>(); 257 if (!ST->hasVInstructions()) 258 return false; 259 260 MRI = &MF.getRegInfo(); 261 TII = ST->getInstrInfo(); 262 TRI = MRI->getTargetRegisterInfo(); 263 264 bool Changed = false; 265 DeadLaneDetector DLD(MRI, TRI); 266 DLD.computeSubRegisterLaneBitInfo(); 267 268 for (MachineBasicBlock &BB : MF) 269 Changed |= processBasicBlock(MF, BB, DLD); 270 271 return Changed; 272 } 273 274 FunctionPass *llvm::createRISCVInitUndefPass() { return new RISCVInitUndef(); } 275