xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/InitUndef.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- InitUndef.cpp - Initialize undef value to pseudo ----===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // This file implements a function pass that initializes undef value to
10*0fca6ea1SDimitry Andric // temporary pseudo instruction to prevent register allocation resulting in a
11*0fca6ea1SDimitry Andric // constraint violated result for the particular instruction. It also rewrites
12*0fca6ea1SDimitry Andric // the NoReg tied operand back to an IMPLICIT_DEF.
13*0fca6ea1SDimitry Andric //
14*0fca6ea1SDimitry Andric // Certain instructions have register overlapping constraints, and
15*0fca6ea1SDimitry Andric // will cause illegal instruction trap if violated, we use early clobber to
16*0fca6ea1SDimitry Andric // model this constraint, but it can't prevent register allocator allocating
17*0fca6ea1SDimitry Andric // same or overlapped if the input register is undef value, so convert
18*0fca6ea1SDimitry Andric // IMPLICIT_DEF to temporary pseudo instruction and remove it later could
19*0fca6ea1SDimitry Andric // prevent that happen, it's not best way to resolve this, and it might
20*0fca6ea1SDimitry Andric // change the order of program or increase the register pressure, so ideally we
21*0fca6ea1SDimitry Andric // should model the constraint right, but before we model the constraint right,
22*0fca6ea1SDimitry Andric // it's the only way to prevent that happen.
23*0fca6ea1SDimitry Andric //
24*0fca6ea1SDimitry Andric // When we enable the subregister liveness option, it will also trigger the same
25*0fca6ea1SDimitry Andric // issue due to the partial of register is undef. If we pseudoinit the whole
26*0fca6ea1SDimitry Andric // register, then it will generate redundant COPY instruction. Currently, it
27*0fca6ea1SDimitry Andric // will generate INSERT_SUBREG to make sure the whole register is occupied
28*0fca6ea1SDimitry Andric // when program encounter operation that has early-clobber constraint.
29*0fca6ea1SDimitry Andric //
30*0fca6ea1SDimitry Andric //
31*0fca6ea1SDimitry Andric // See also: https://github.com/llvm/llvm-project/issues/50157
32*0fca6ea1SDimitry Andric //
33*0fca6ea1SDimitry Andric // Additionally, this pass rewrites tied operands of instructions
34*0fca6ea1SDimitry Andric // from NoReg to IMPLICIT_DEF.  (Not that this is a non-overlapping set of
35*0fca6ea1SDimitry Andric // operands to the above.)  We use NoReg to side step a MachineCSE
36*0fca6ea1SDimitry Andric // optimization quality problem but need to convert back before
37*0fca6ea1SDimitry Andric // TwoAddressInstruction.  See pr64282 for context.
38*0fca6ea1SDimitry Andric //
39*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
40*0fca6ea1SDimitry Andric 
41*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallSet.h"
42*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h"
43*0fca6ea1SDimitry Andric #include "llvm/CodeGen/DetectDeadLanes.h"
44*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
45*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
46*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
47*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
48*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
49*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
50*0fca6ea1SDimitry Andric #include "llvm/InitializePasses.h"
51*0fca6ea1SDimitry Andric #include "llvm/MC/MCRegister.h"
52*0fca6ea1SDimitry Andric #include "llvm/Pass.h"
53*0fca6ea1SDimitry Andric #include "llvm/Support/Debug.h"
54*0fca6ea1SDimitry Andric 
55*0fca6ea1SDimitry Andric using namespace llvm;
56*0fca6ea1SDimitry Andric 
57*0fca6ea1SDimitry Andric #define DEBUG_TYPE "init-undef"
58*0fca6ea1SDimitry Andric #define INIT_UNDEF_NAME "Init Undef Pass"
59*0fca6ea1SDimitry Andric 
60*0fca6ea1SDimitry Andric namespace {
61*0fca6ea1SDimitry Andric 
62*0fca6ea1SDimitry Andric class InitUndef : public MachineFunctionPass {
63*0fca6ea1SDimitry Andric   const TargetInstrInfo *TII;
64*0fca6ea1SDimitry Andric   MachineRegisterInfo *MRI;
65*0fca6ea1SDimitry Andric   const TargetSubtargetInfo *ST;
66*0fca6ea1SDimitry Andric   const TargetRegisterInfo *TRI;
67*0fca6ea1SDimitry Andric 
68*0fca6ea1SDimitry Andric   // Newly added vregs, assumed to be fully rewritten
69*0fca6ea1SDimitry Andric   SmallSet<Register, 8> NewRegs;
70*0fca6ea1SDimitry Andric   SmallVector<MachineInstr *, 8> DeadInsts;
71*0fca6ea1SDimitry Andric 
72*0fca6ea1SDimitry Andric public:
73*0fca6ea1SDimitry Andric   static char ID;
74*0fca6ea1SDimitry Andric 
75*0fca6ea1SDimitry Andric   InitUndef() : MachineFunctionPass(ID) {}
76*0fca6ea1SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
77*0fca6ea1SDimitry Andric 
78*0fca6ea1SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
79*0fca6ea1SDimitry Andric     AU.setPreservesCFG();
80*0fca6ea1SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
81*0fca6ea1SDimitry Andric   }
82*0fca6ea1SDimitry Andric 
83*0fca6ea1SDimitry Andric   StringRef getPassName() const override { return INIT_UNDEF_NAME; }
84*0fca6ea1SDimitry Andric 
85*0fca6ea1SDimitry Andric private:
86*0fca6ea1SDimitry Andric   bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB,
87*0fca6ea1SDimitry Andric                          const DeadLaneDetector &DLD);
88*0fca6ea1SDimitry Andric   bool handleSubReg(MachineFunction &MF, MachineInstr &MI,
89*0fca6ea1SDimitry Andric                     const DeadLaneDetector &DLD);
90*0fca6ea1SDimitry Andric   bool fixupIllOperand(MachineInstr *MI, MachineOperand &MO);
91*0fca6ea1SDimitry Andric   bool handleReg(MachineInstr *MI);
92*0fca6ea1SDimitry Andric };
93*0fca6ea1SDimitry Andric 
94*0fca6ea1SDimitry Andric } // end anonymous namespace
95*0fca6ea1SDimitry Andric 
96*0fca6ea1SDimitry Andric char InitUndef::ID = 0;
97*0fca6ea1SDimitry Andric INITIALIZE_PASS(InitUndef, DEBUG_TYPE, INIT_UNDEF_NAME, false, false)
98*0fca6ea1SDimitry Andric char &llvm::InitUndefID = InitUndef::ID;
99*0fca6ea1SDimitry Andric 
100*0fca6ea1SDimitry Andric static bool isEarlyClobberMI(MachineInstr &MI) {
101*0fca6ea1SDimitry Andric   return llvm::any_of(MI.defs(), [](const MachineOperand &DefMO) {
102*0fca6ea1SDimitry Andric     return DefMO.isReg() && DefMO.isEarlyClobber();
103*0fca6ea1SDimitry Andric   });
104*0fca6ea1SDimitry Andric }
105*0fca6ea1SDimitry Andric 
106*0fca6ea1SDimitry Andric static bool findImplictDefMIFromReg(Register Reg, MachineRegisterInfo *MRI) {
107*0fca6ea1SDimitry Andric   for (auto &DefMI : MRI->def_instructions(Reg)) {
108*0fca6ea1SDimitry Andric     if (DefMI.getOpcode() == TargetOpcode::IMPLICIT_DEF)
109*0fca6ea1SDimitry Andric       return true;
110*0fca6ea1SDimitry Andric   }
111*0fca6ea1SDimitry Andric   return false;
112*0fca6ea1SDimitry Andric }
113*0fca6ea1SDimitry Andric 
114*0fca6ea1SDimitry Andric bool InitUndef::handleReg(MachineInstr *MI) {
115*0fca6ea1SDimitry Andric   bool Changed = false;
116*0fca6ea1SDimitry Andric   for (auto &UseMO : MI->uses()) {
117*0fca6ea1SDimitry Andric     if (!UseMO.isReg())
118*0fca6ea1SDimitry Andric       continue;
119*0fca6ea1SDimitry Andric     if (UseMO.isTied())
120*0fca6ea1SDimitry Andric       continue;
121*0fca6ea1SDimitry Andric     if (!UseMO.getReg().isVirtual())
122*0fca6ea1SDimitry Andric       continue;
123*0fca6ea1SDimitry Andric     if (!TRI->doesRegClassHavePseudoInitUndef(MRI->getRegClass(UseMO.getReg())))
124*0fca6ea1SDimitry Andric       continue;
125*0fca6ea1SDimitry Andric 
126*0fca6ea1SDimitry Andric     if (UseMO.isUndef() || findImplictDefMIFromReg(UseMO.getReg(), MRI))
127*0fca6ea1SDimitry Andric       Changed |= fixupIllOperand(MI, UseMO);
128*0fca6ea1SDimitry Andric   }
129*0fca6ea1SDimitry Andric   return Changed;
130*0fca6ea1SDimitry Andric }
131*0fca6ea1SDimitry Andric 
132*0fca6ea1SDimitry Andric bool InitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
133*0fca6ea1SDimitry Andric                              const DeadLaneDetector &DLD) {
134*0fca6ea1SDimitry Andric   bool Changed = false;
135*0fca6ea1SDimitry Andric 
136*0fca6ea1SDimitry Andric   for (MachineOperand &UseMO : MI.uses()) {
137*0fca6ea1SDimitry Andric     if (!UseMO.isReg())
138*0fca6ea1SDimitry Andric       continue;
139*0fca6ea1SDimitry Andric     if (!UseMO.getReg().isVirtual())
140*0fca6ea1SDimitry Andric       continue;
141*0fca6ea1SDimitry Andric     if (UseMO.isTied())
142*0fca6ea1SDimitry Andric       continue;
143*0fca6ea1SDimitry Andric     if (!TRI->doesRegClassHavePseudoInitUndef(MRI->getRegClass(UseMO.getReg())))
144*0fca6ea1SDimitry Andric       continue;
145*0fca6ea1SDimitry Andric 
146*0fca6ea1SDimitry Andric     Register Reg = UseMO.getReg();
147*0fca6ea1SDimitry Andric     if (NewRegs.count(Reg))
148*0fca6ea1SDimitry Andric       continue;
149*0fca6ea1SDimitry Andric     DeadLaneDetector::VRegInfo Info =
150*0fca6ea1SDimitry Andric         DLD.getVRegInfo(Register::virtReg2Index(Reg));
151*0fca6ea1SDimitry Andric 
152*0fca6ea1SDimitry Andric     if (Info.UsedLanes == Info.DefinedLanes)
153*0fca6ea1SDimitry Andric       continue;
154*0fca6ea1SDimitry Andric 
155*0fca6ea1SDimitry Andric     const TargetRegisterClass *TargetRegClass =
156*0fca6ea1SDimitry Andric         TRI->getLargestSuperClass(MRI->getRegClass(Reg));
157*0fca6ea1SDimitry Andric 
158*0fca6ea1SDimitry Andric     LaneBitmask NeedDef = Info.UsedLanes & ~Info.DefinedLanes;
159*0fca6ea1SDimitry Andric 
160*0fca6ea1SDimitry Andric     LLVM_DEBUG({
161*0fca6ea1SDimitry Andric       dbgs() << "Instruction has undef subregister.\n";
162*0fca6ea1SDimitry Andric       dbgs() << printReg(Reg, nullptr)
163*0fca6ea1SDimitry Andric              << " Used: " << PrintLaneMask(Info.UsedLanes)
164*0fca6ea1SDimitry Andric              << " Def: " << PrintLaneMask(Info.DefinedLanes)
165*0fca6ea1SDimitry Andric              << " Need Def: " << PrintLaneMask(NeedDef) << "\n";
166*0fca6ea1SDimitry Andric     });
167*0fca6ea1SDimitry Andric 
168*0fca6ea1SDimitry Andric     SmallVector<unsigned> SubRegIndexNeedInsert;
169*0fca6ea1SDimitry Andric     TRI->getCoveringSubRegIndexes(*MRI, TargetRegClass, NeedDef,
170*0fca6ea1SDimitry Andric                                   SubRegIndexNeedInsert);
171*0fca6ea1SDimitry Andric 
172*0fca6ea1SDimitry Andric     Register LatestReg = Reg;
173*0fca6ea1SDimitry Andric     for (auto ind : SubRegIndexNeedInsert) {
174*0fca6ea1SDimitry Andric       Changed = true;
175*0fca6ea1SDimitry Andric       const TargetRegisterClass *SubRegClass = TRI->getLargestSuperClass(
176*0fca6ea1SDimitry Andric           TRI->getSubRegisterClass(TargetRegClass, ind));
177*0fca6ea1SDimitry Andric       Register TmpInitSubReg = MRI->createVirtualRegister(SubRegClass);
178*0fca6ea1SDimitry Andric       LLVM_DEBUG(dbgs() << "Register Class ID" << SubRegClass->getID() << "\n");
179*0fca6ea1SDimitry Andric       BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
180*0fca6ea1SDimitry Andric               TII->get(TII->getUndefInitOpcode(SubRegClass->getID())),
181*0fca6ea1SDimitry Andric               TmpInitSubReg);
182*0fca6ea1SDimitry Andric       Register NewReg = MRI->createVirtualRegister(TargetRegClass);
183*0fca6ea1SDimitry Andric       BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
184*0fca6ea1SDimitry Andric               TII->get(TargetOpcode::INSERT_SUBREG), NewReg)
185*0fca6ea1SDimitry Andric           .addReg(LatestReg)
186*0fca6ea1SDimitry Andric           .addReg(TmpInitSubReg)
187*0fca6ea1SDimitry Andric           .addImm(ind);
188*0fca6ea1SDimitry Andric       LatestReg = NewReg;
189*0fca6ea1SDimitry Andric     }
190*0fca6ea1SDimitry Andric 
191*0fca6ea1SDimitry Andric     UseMO.setReg(LatestReg);
192*0fca6ea1SDimitry Andric   }
193*0fca6ea1SDimitry Andric 
194*0fca6ea1SDimitry Andric   return Changed;
195*0fca6ea1SDimitry Andric }
196*0fca6ea1SDimitry Andric 
197*0fca6ea1SDimitry Andric bool InitUndef::fixupIllOperand(MachineInstr *MI, MachineOperand &MO) {
198*0fca6ea1SDimitry Andric 
199*0fca6ea1SDimitry Andric   LLVM_DEBUG(
200*0fca6ea1SDimitry Andric       dbgs() << "Emitting PseudoInitUndef Instruction for implicit register "
201*0fca6ea1SDimitry Andric              << MO.getReg() << '\n');
202*0fca6ea1SDimitry Andric 
203*0fca6ea1SDimitry Andric   const TargetRegisterClass *TargetRegClass =
204*0fca6ea1SDimitry Andric       TRI->getLargestSuperClass(MRI->getRegClass(MO.getReg()));
205*0fca6ea1SDimitry Andric   LLVM_DEBUG(dbgs() << "Register Class ID" << TargetRegClass->getID() << "\n");
206*0fca6ea1SDimitry Andric   unsigned Opcode = TII->getUndefInitOpcode(TargetRegClass->getID());
207*0fca6ea1SDimitry Andric   Register NewReg = MRI->createVirtualRegister(TargetRegClass);
208*0fca6ea1SDimitry Andric   BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(Opcode), NewReg);
209*0fca6ea1SDimitry Andric   MO.setReg(NewReg);
210*0fca6ea1SDimitry Andric   if (MO.isUndef())
211*0fca6ea1SDimitry Andric     MO.setIsUndef(false);
212*0fca6ea1SDimitry Andric   return true;
213*0fca6ea1SDimitry Andric }
214*0fca6ea1SDimitry Andric 
215*0fca6ea1SDimitry Andric bool InitUndef::processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB,
216*0fca6ea1SDimitry Andric                                   const DeadLaneDetector &DLD) {
217*0fca6ea1SDimitry Andric   bool Changed = false;
218*0fca6ea1SDimitry Andric   for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
219*0fca6ea1SDimitry Andric     MachineInstr &MI = *I;
220*0fca6ea1SDimitry Andric 
221*0fca6ea1SDimitry Andric     // If we used NoReg to represent the passthru, switch this back to being
222*0fca6ea1SDimitry Andric     // an IMPLICIT_DEF before TwoAddressInstructions.
223*0fca6ea1SDimitry Andric     unsigned UseOpIdx;
224*0fca6ea1SDimitry Andric     if (MI.getNumDefs() != 0 && MI.isRegTiedToUseOperand(0, &UseOpIdx)) {
225*0fca6ea1SDimitry Andric       MachineOperand &UseMO = MI.getOperand(UseOpIdx);
226*0fca6ea1SDimitry Andric       if (UseMO.getReg() == MCRegister::NoRegister) {
227*0fca6ea1SDimitry Andric         const TargetRegisterClass *RC =
228*0fca6ea1SDimitry Andric             TII->getRegClass(MI.getDesc(), UseOpIdx, TRI, MF);
229*0fca6ea1SDimitry Andric         Register NewDest = MRI->createVirtualRegister(RC);
230*0fca6ea1SDimitry Andric         // We don't have a way to update dead lanes, so keep track of the
231*0fca6ea1SDimitry Andric         // new register so that we avoid querying it later.
232*0fca6ea1SDimitry Andric         NewRegs.insert(NewDest);
233*0fca6ea1SDimitry Andric         BuildMI(MBB, I, I->getDebugLoc(), TII->get(TargetOpcode::IMPLICIT_DEF),
234*0fca6ea1SDimitry Andric                 NewDest);
235*0fca6ea1SDimitry Andric         UseMO.setReg(NewDest);
236*0fca6ea1SDimitry Andric         Changed = true;
237*0fca6ea1SDimitry Andric       }
238*0fca6ea1SDimitry Andric     }
239*0fca6ea1SDimitry Andric 
240*0fca6ea1SDimitry Andric     if (isEarlyClobberMI(MI)) {
241*0fca6ea1SDimitry Andric       if (MRI->subRegLivenessEnabled())
242*0fca6ea1SDimitry Andric         Changed |= handleSubReg(MF, MI, DLD);
243*0fca6ea1SDimitry Andric       Changed |= handleReg(&MI);
244*0fca6ea1SDimitry Andric     }
245*0fca6ea1SDimitry Andric   }
246*0fca6ea1SDimitry Andric   return Changed;
247*0fca6ea1SDimitry Andric }
248*0fca6ea1SDimitry Andric 
249*0fca6ea1SDimitry Andric bool InitUndef::runOnMachineFunction(MachineFunction &MF) {
250*0fca6ea1SDimitry Andric   ST = &MF.getSubtarget();
251*0fca6ea1SDimitry Andric 
252*0fca6ea1SDimitry Andric   // supportsInitUndef is implemented to reflect if an architecture has support
253*0fca6ea1SDimitry Andric   // for the InitUndef pass. Support comes from having the relevant Pseudo
254*0fca6ea1SDimitry Andric   // instructions that can be used to initialize the register. The function
255*0fca6ea1SDimitry Andric   // returns false by default so requires an implementation per architecture.
256*0fca6ea1SDimitry Andric   // Support can be added by overriding the function in a way that best fits
257*0fca6ea1SDimitry Andric   // the architecture.
258*0fca6ea1SDimitry Andric   if (!ST->supportsInitUndef())
259*0fca6ea1SDimitry Andric     return false;
260*0fca6ea1SDimitry Andric 
261*0fca6ea1SDimitry Andric   MRI = &MF.getRegInfo();
262*0fca6ea1SDimitry Andric   TII = ST->getInstrInfo();
263*0fca6ea1SDimitry Andric   TRI = MRI->getTargetRegisterInfo();
264*0fca6ea1SDimitry Andric 
265*0fca6ea1SDimitry Andric   bool Changed = false;
266*0fca6ea1SDimitry Andric   DeadLaneDetector DLD(MRI, TRI);
267*0fca6ea1SDimitry Andric   DLD.computeSubRegisterLaneBitInfo();
268*0fca6ea1SDimitry Andric 
269*0fca6ea1SDimitry Andric   for (MachineBasicBlock &BB : MF)
270*0fca6ea1SDimitry Andric     Changed |= processBasicBlock(MF, BB, DLD);
271*0fca6ea1SDimitry Andric 
272*0fca6ea1SDimitry Andric   for (auto *DeadMI : DeadInsts)
273*0fca6ea1SDimitry Andric     DeadMI->eraseFromParent();
274*0fca6ea1SDimitry Andric   DeadInsts.clear();
275*0fca6ea1SDimitry Andric 
276*0fca6ea1SDimitry Andric   return Changed;
277*0fca6ea1SDimitry Andric }
278