xref: /src/contrib/llvm-project/llvm/lib/CodeGen/InitUndef.cpp (revision 6e516c87b6d779911edde7481d8aef165b837a03)
1ac9a064cSDimitry Andric //===- InitUndef.cpp - Initialize undef value to pseudo ----===//
27fa27ce4SDimitry Andric //
37fa27ce4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47fa27ce4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
57fa27ce4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67fa27ce4SDimitry Andric //
77fa27ce4SDimitry Andric //===----------------------------------------------------------------------===//
87fa27ce4SDimitry Andric //
9ac9a064cSDimitry Andric // This file implements a function pass that initializes undef value to
10ac9a064cSDimitry Andric // temporary pseudo instruction to prevent register allocation resulting in a
11ac9a064cSDimitry Andric // constraint violated result for the particular instruction. It also rewrites
12ac9a064cSDimitry Andric // the NoReg tied operand back to an IMPLICIT_DEF.
137fa27ce4SDimitry Andric //
14ac9a064cSDimitry Andric // Certain instructions have register overlapping constraints, and
15ac9a064cSDimitry Andric // will cause illegal instruction trap if violated, we use early clobber to
16ac9a064cSDimitry Andric // model this constraint, but it can't prevent register allocator allocating
17ac9a064cSDimitry Andric // same or overlapped if the input register is undef value, so convert
18ac9a064cSDimitry Andric // IMPLICIT_DEF to temporary pseudo instruction and remove it later could
19ac9a064cSDimitry Andric // prevent that happen, it's not best way to resolve this, and it might
207fa27ce4SDimitry Andric // change the order of program or increase the register pressure, so ideally we
217fa27ce4SDimitry Andric // should model the constraint right, but before we model the constraint right,
227fa27ce4SDimitry Andric // it's the only way to prevent that happen.
237fa27ce4SDimitry Andric //
24ac9a064cSDimitry Andric // When we enable the subregister liveness option, it will also trigger the same
257fa27ce4SDimitry Andric // issue due to the partial of register is undef. If we pseudoinit the whole
267fa27ce4SDimitry Andric // register, then it will generate redundant COPY instruction. Currently, it
277fa27ce4SDimitry Andric // will generate INSERT_SUBREG to make sure the whole register is occupied
287fa27ce4SDimitry Andric // when program encounter operation that has early-clobber constraint.
297fa27ce4SDimitry Andric //
307fa27ce4SDimitry Andric //
317fa27ce4SDimitry Andric // See also: https://github.com/llvm/llvm-project/issues/50157
327fa27ce4SDimitry Andric //
33ac9a064cSDimitry Andric // Additionally, this pass rewrites tied operands of instructions
34b1c73532SDimitry Andric // from NoReg to IMPLICIT_DEF.  (Not that this is a non-overlapping set of
35b1c73532SDimitry Andric // operands to the above.)  We use NoReg to side step a MachineCSE
36b1c73532SDimitry Andric // optimization quality problem but need to convert back before
37b1c73532SDimitry Andric // TwoAddressInstruction.  See pr64282 for context.
38b1c73532SDimitry Andric //
397fa27ce4SDimitry Andric //===----------------------------------------------------------------------===//
407fa27ce4SDimitry Andric 
41b1c73532SDimitry Andric #include "llvm/ADT/SmallSet.h"
42b1c73532SDimitry Andric #include "llvm/ADT/SmallVector.h"
437fa27ce4SDimitry Andric #include "llvm/CodeGen/DetectDeadLanes.h"
44ac9a064cSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
457fa27ce4SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
46ac9a064cSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
47ac9a064cSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
48ac9a064cSDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
49ac9a064cSDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
50ac9a064cSDimitry Andric #include "llvm/InitializePasses.h"
51ac9a064cSDimitry Andric #include "llvm/MC/MCRegister.h"
52ac9a064cSDimitry Andric #include "llvm/Pass.h"
53ac9a064cSDimitry Andric #include "llvm/Support/Debug.h"
54ac9a064cSDimitry Andric 
557fa27ce4SDimitry Andric using namespace llvm;
567fa27ce4SDimitry Andric 
57ac9a064cSDimitry Andric #define DEBUG_TYPE "init-undef"
58ac9a064cSDimitry Andric #define INIT_UNDEF_NAME "Init Undef Pass"
597fa27ce4SDimitry Andric 
607fa27ce4SDimitry Andric namespace {
617fa27ce4SDimitry Andric 
62ac9a064cSDimitry Andric class InitUndef : public MachineFunctionPass {
637fa27ce4SDimitry Andric   const TargetInstrInfo *TII;
647fa27ce4SDimitry Andric   MachineRegisterInfo *MRI;
65ac9a064cSDimitry Andric   const TargetSubtargetInfo *ST;
667fa27ce4SDimitry Andric   const TargetRegisterInfo *TRI;
677fa27ce4SDimitry Andric 
68b1c73532SDimitry Andric   // Newly added vregs, assumed to be fully rewritten
69b1c73532SDimitry Andric   SmallSet<Register, 8> NewRegs;
70b1c73532SDimitry Andric   SmallVector<MachineInstr *, 8> DeadInsts;
71b1c73532SDimitry Andric 
727fa27ce4SDimitry Andric public:
737fa27ce4SDimitry Andric   static char ID;
747fa27ce4SDimitry Andric 
InitUndef()75ac9a064cSDimitry Andric   InitUndef() : MachineFunctionPass(ID) {}
767fa27ce4SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
777fa27ce4SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const787fa27ce4SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
797fa27ce4SDimitry Andric     AU.setPreservesCFG();
807fa27ce4SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
817fa27ce4SDimitry Andric   }
827fa27ce4SDimitry Andric 
getPassName() const83ac9a064cSDimitry Andric   StringRef getPassName() const override { return INIT_UNDEF_NAME; }
847fa27ce4SDimitry Andric 
857fa27ce4SDimitry Andric private:
867fa27ce4SDimitry Andric   bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB,
877fa27ce4SDimitry Andric                          const DeadLaneDetector &DLD);
887fa27ce4SDimitry Andric   bool handleSubReg(MachineFunction &MF, MachineInstr &MI,
897fa27ce4SDimitry Andric                     const DeadLaneDetector &DLD);
90b1c73532SDimitry Andric   bool fixupIllOperand(MachineInstr *MI, MachineOperand &MO);
91b1c73532SDimitry Andric   bool handleReg(MachineInstr *MI);
927fa27ce4SDimitry Andric };
937fa27ce4SDimitry Andric 
947fa27ce4SDimitry Andric } // end anonymous namespace
957fa27ce4SDimitry Andric 
96ac9a064cSDimitry Andric char InitUndef::ID = 0;
97ac9a064cSDimitry Andric INITIALIZE_PASS(InitUndef, DEBUG_TYPE, INIT_UNDEF_NAME, false, false)
98ac9a064cSDimitry Andric char &llvm::InitUndefID = InitUndef::ID;
997fa27ce4SDimitry Andric 
isEarlyClobberMI(MachineInstr & MI)1007fa27ce4SDimitry Andric static bool isEarlyClobberMI(MachineInstr &MI) {
1017fa27ce4SDimitry Andric   return llvm::any_of(MI.defs(), [](const MachineOperand &DefMO) {
1027fa27ce4SDimitry Andric     return DefMO.isReg() && DefMO.isEarlyClobber();
1037fa27ce4SDimitry Andric   });
1047fa27ce4SDimitry Andric }
1057fa27ce4SDimitry Andric 
findImplictDefMIFromReg(Register Reg,MachineRegisterInfo * MRI)106b1c73532SDimitry Andric static bool findImplictDefMIFromReg(Register Reg, MachineRegisterInfo *MRI) {
107b1c73532SDimitry Andric   for (auto &DefMI : MRI->def_instructions(Reg)) {
108b1c73532SDimitry Andric     if (DefMI.getOpcode() == TargetOpcode::IMPLICIT_DEF)
109b1c73532SDimitry Andric       return true;
110b1c73532SDimitry Andric   }
111b1c73532SDimitry Andric   return false;
112b1c73532SDimitry Andric }
113b1c73532SDimitry Andric 
handleReg(MachineInstr * MI)114ac9a064cSDimitry Andric bool InitUndef::handleReg(MachineInstr *MI) {
115b1c73532SDimitry Andric   bool Changed = false;
116b1c73532SDimitry Andric   for (auto &UseMO : MI->uses()) {
117b1c73532SDimitry Andric     if (!UseMO.isReg())
118b1c73532SDimitry Andric       continue;
119b1c73532SDimitry Andric     if (UseMO.isTied())
120b1c73532SDimitry Andric       continue;
121b1c73532SDimitry Andric     if (!UseMO.getReg().isVirtual())
122b1c73532SDimitry Andric       continue;
123ac9a064cSDimitry Andric     if (!TRI->doesRegClassHavePseudoInitUndef(MRI->getRegClass(UseMO.getReg())))
124b1c73532SDimitry Andric       continue;
125b1c73532SDimitry Andric 
126b1c73532SDimitry Andric     if (UseMO.isUndef() || findImplictDefMIFromReg(UseMO.getReg(), MRI))
127b1c73532SDimitry Andric       Changed |= fixupIllOperand(MI, UseMO);
128b1c73532SDimitry Andric   }
129b1c73532SDimitry Andric   return Changed;
130b1c73532SDimitry Andric }
131b1c73532SDimitry Andric 
handleSubReg(MachineFunction & MF,MachineInstr & MI,const DeadLaneDetector & DLD)132ac9a064cSDimitry Andric bool InitUndef::handleSubReg(MachineFunction &MF, MachineInstr &MI,
1337fa27ce4SDimitry Andric                              const DeadLaneDetector &DLD) {
1347fa27ce4SDimitry Andric   bool Changed = false;
1357fa27ce4SDimitry Andric 
1367fa27ce4SDimitry Andric   for (MachineOperand &UseMO : MI.uses()) {
1377fa27ce4SDimitry Andric     if (!UseMO.isReg())
1387fa27ce4SDimitry Andric       continue;
1397fa27ce4SDimitry Andric     if (!UseMO.getReg().isVirtual())
1407fa27ce4SDimitry Andric       continue;
141b1c73532SDimitry Andric     if (UseMO.isTied())
142b1c73532SDimitry Andric       continue;
143ac9a064cSDimitry Andric     if (!TRI->doesRegClassHavePseudoInitUndef(MRI->getRegClass(UseMO.getReg())))
144ac9a064cSDimitry Andric       continue;
1457fa27ce4SDimitry Andric 
1467fa27ce4SDimitry Andric     Register Reg = UseMO.getReg();
147b1c73532SDimitry Andric     if (NewRegs.count(Reg))
148b1c73532SDimitry Andric       continue;
1497fa27ce4SDimitry Andric     DeadLaneDetector::VRegInfo Info =
1507fa27ce4SDimitry Andric         DLD.getVRegInfo(Register::virtReg2Index(Reg));
1517fa27ce4SDimitry Andric 
1527fa27ce4SDimitry Andric     if (Info.UsedLanes == Info.DefinedLanes)
1537fa27ce4SDimitry Andric       continue;
1547fa27ce4SDimitry Andric 
1557fa27ce4SDimitry Andric     const TargetRegisterClass *TargetRegClass =
156ac9a064cSDimitry Andric         TRI->getLargestSuperClass(MRI->getRegClass(Reg));
1577fa27ce4SDimitry Andric 
1587fa27ce4SDimitry Andric     LaneBitmask NeedDef = Info.UsedLanes & ~Info.DefinedLanes;
1597fa27ce4SDimitry Andric 
1607fa27ce4SDimitry Andric     LLVM_DEBUG({
1617fa27ce4SDimitry Andric       dbgs() << "Instruction has undef subregister.\n";
1627fa27ce4SDimitry Andric       dbgs() << printReg(Reg, nullptr)
1637fa27ce4SDimitry Andric              << " Used: " << PrintLaneMask(Info.UsedLanes)
1647fa27ce4SDimitry Andric              << " Def: " << PrintLaneMask(Info.DefinedLanes)
1657fa27ce4SDimitry Andric              << " Need Def: " << PrintLaneMask(NeedDef) << "\n";
1667fa27ce4SDimitry Andric     });
1677fa27ce4SDimitry Andric 
1687fa27ce4SDimitry Andric     SmallVector<unsigned> SubRegIndexNeedInsert;
1697fa27ce4SDimitry Andric     TRI->getCoveringSubRegIndexes(*MRI, TargetRegClass, NeedDef,
1707fa27ce4SDimitry Andric                                   SubRegIndexNeedInsert);
1717fa27ce4SDimitry Andric 
1727fa27ce4SDimitry Andric     Register LatestReg = Reg;
1737fa27ce4SDimitry Andric     for (auto ind : SubRegIndexNeedInsert) {
1747fa27ce4SDimitry Andric       Changed = true;
175ac9a064cSDimitry Andric       const TargetRegisterClass *SubRegClass = TRI->getLargestSuperClass(
176ac9a064cSDimitry Andric           TRI->getSubRegisterClass(TargetRegClass, ind));
1777fa27ce4SDimitry Andric       Register TmpInitSubReg = MRI->createVirtualRegister(SubRegClass);
178ac9a064cSDimitry Andric       LLVM_DEBUG(dbgs() << "Register Class ID" << SubRegClass->getID() << "\n");
1797fa27ce4SDimitry Andric       BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
180ac9a064cSDimitry Andric               TII->get(TII->getUndefInitOpcode(SubRegClass->getID())),
1817fa27ce4SDimitry Andric               TmpInitSubReg);
1827fa27ce4SDimitry Andric       Register NewReg = MRI->createVirtualRegister(TargetRegClass);
1837fa27ce4SDimitry Andric       BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
1847fa27ce4SDimitry Andric               TII->get(TargetOpcode::INSERT_SUBREG), NewReg)
1857fa27ce4SDimitry Andric           .addReg(LatestReg)
1867fa27ce4SDimitry Andric           .addReg(TmpInitSubReg)
1877fa27ce4SDimitry Andric           .addImm(ind);
1887fa27ce4SDimitry Andric       LatestReg = NewReg;
1897fa27ce4SDimitry Andric     }
1907fa27ce4SDimitry Andric 
1917fa27ce4SDimitry Andric     UseMO.setReg(LatestReg);
1927fa27ce4SDimitry Andric   }
1937fa27ce4SDimitry Andric 
1947fa27ce4SDimitry Andric   return Changed;
1957fa27ce4SDimitry Andric }
1967fa27ce4SDimitry Andric 
fixupIllOperand(MachineInstr * MI,MachineOperand & MO)197ac9a064cSDimitry Andric bool InitUndef::fixupIllOperand(MachineInstr *MI, MachineOperand &MO) {
198b1c73532SDimitry Andric 
199b1c73532SDimitry Andric   LLVM_DEBUG(
200ac9a064cSDimitry Andric       dbgs() << "Emitting PseudoInitUndef Instruction for implicit register "
201b1c73532SDimitry Andric              << MO.getReg() << '\n');
202b1c73532SDimitry Andric 
203b1c73532SDimitry Andric   const TargetRegisterClass *TargetRegClass =
204ac9a064cSDimitry Andric       TRI->getLargestSuperClass(MRI->getRegClass(MO.getReg()));
205ac9a064cSDimitry Andric   LLVM_DEBUG(dbgs() << "Register Class ID" << TargetRegClass->getID() << "\n");
206ac9a064cSDimitry Andric   unsigned Opcode = TII->getUndefInitOpcode(TargetRegClass->getID());
207b1c73532SDimitry Andric   Register NewReg = MRI->createVirtualRegister(TargetRegClass);
208b1c73532SDimitry Andric   BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(Opcode), NewReg);
209b1c73532SDimitry Andric   MO.setReg(NewReg);
210b1c73532SDimitry Andric   if (MO.isUndef())
211b1c73532SDimitry Andric     MO.setIsUndef(false);
212b1c73532SDimitry Andric   return true;
213b1c73532SDimitry Andric }
214b1c73532SDimitry Andric 
processBasicBlock(MachineFunction & MF,MachineBasicBlock & MBB,const DeadLaneDetector & DLD)215ac9a064cSDimitry Andric bool InitUndef::processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB,
2167fa27ce4SDimitry Andric                                   const DeadLaneDetector &DLD) {
2177fa27ce4SDimitry Andric   bool Changed = false;
2187fa27ce4SDimitry Andric   for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
2197fa27ce4SDimitry Andric     MachineInstr &MI = *I;
220b1c73532SDimitry Andric 
221b1c73532SDimitry Andric     // If we used NoReg to represent the passthru, switch this back to being
222b1c73532SDimitry Andric     // an IMPLICIT_DEF before TwoAddressInstructions.
223b1c73532SDimitry Andric     unsigned UseOpIdx;
224b1c73532SDimitry Andric     if (MI.getNumDefs() != 0 && MI.isRegTiedToUseOperand(0, &UseOpIdx)) {
225b1c73532SDimitry Andric       MachineOperand &UseMO = MI.getOperand(UseOpIdx);
226ac9a064cSDimitry Andric       if (UseMO.getReg() == MCRegister::NoRegister) {
227b1c73532SDimitry Andric         const TargetRegisterClass *RC =
228b1c73532SDimitry Andric             TII->getRegClass(MI.getDesc(), UseOpIdx, TRI, MF);
229b1c73532SDimitry Andric         Register NewDest = MRI->createVirtualRegister(RC);
230b1c73532SDimitry Andric         // We don't have a way to update dead lanes, so keep track of the
231b1c73532SDimitry Andric         // new register so that we avoid querying it later.
232b1c73532SDimitry Andric         NewRegs.insert(NewDest);
233ac9a064cSDimitry Andric         BuildMI(MBB, I, I->getDebugLoc(), TII->get(TargetOpcode::IMPLICIT_DEF),
234ac9a064cSDimitry Andric                 NewDest);
235b1c73532SDimitry Andric         UseMO.setReg(NewDest);
236b1c73532SDimitry Andric         Changed = true;
237b1c73532SDimitry Andric       }
238b1c73532SDimitry Andric     }
239b1c73532SDimitry Andric 
240b1c73532SDimitry Andric     if (isEarlyClobberMI(MI)) {
241ac9a064cSDimitry Andric       if (MRI->subRegLivenessEnabled())
2427fa27ce4SDimitry Andric         Changed |= handleSubReg(MF, MI, DLD);
243b1c73532SDimitry Andric       Changed |= handleReg(&MI);
2447fa27ce4SDimitry Andric     }
2457fa27ce4SDimitry Andric   }
2467fa27ce4SDimitry Andric   return Changed;
2477fa27ce4SDimitry Andric }
2487fa27ce4SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)249ac9a064cSDimitry Andric bool InitUndef::runOnMachineFunction(MachineFunction &MF) {
250ac9a064cSDimitry Andric   ST = &MF.getSubtarget();
251ac9a064cSDimitry Andric 
252ac9a064cSDimitry Andric   // supportsInitUndef is implemented to reflect if an architecture has support
253ac9a064cSDimitry Andric   // for the InitUndef pass. Support comes from having the relevant Pseudo
254ac9a064cSDimitry Andric   // instructions that can be used to initialize the register. The function
255ac9a064cSDimitry Andric   // returns false by default so requires an implementation per architecture.
256ac9a064cSDimitry Andric   // Support can be added by overriding the function in a way that best fits
257ac9a064cSDimitry Andric   // the architecture.
258ac9a064cSDimitry Andric   if (!ST->supportsInitUndef())
2597fa27ce4SDimitry Andric     return false;
2607fa27ce4SDimitry Andric 
2617fa27ce4SDimitry Andric   MRI = &MF.getRegInfo();
2627fa27ce4SDimitry Andric   TII = ST->getInstrInfo();
2637fa27ce4SDimitry Andric   TRI = MRI->getTargetRegisterInfo();
2647fa27ce4SDimitry Andric 
2657fa27ce4SDimitry Andric   bool Changed = false;
2667fa27ce4SDimitry Andric   DeadLaneDetector DLD(MRI, TRI);
2677fa27ce4SDimitry Andric   DLD.computeSubRegisterLaneBitInfo();
2687fa27ce4SDimitry Andric 
2697fa27ce4SDimitry Andric   for (MachineBasicBlock &BB : MF)
2707fa27ce4SDimitry Andric     Changed |= processBasicBlock(MF, BB, DLD);
2717fa27ce4SDimitry Andric 
272b1c73532SDimitry Andric   for (auto *DeadMI : DeadInsts)
273b1c73532SDimitry Andric     DeadMI->eraseFromParent();
274b1c73532SDimitry Andric   DeadInsts.clear();
27503706295SDimitry Andric   NewRegs.clear();
276b1c73532SDimitry Andric 
2777fa27ce4SDimitry Andric   return Changed;
2787fa27ce4SDimitry Andric }
279