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