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