xref: /src/contrib/llvm-project/llvm/lib/CodeGen/OptimizePHIs.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1044eb2f6SDimitry Andric //===- OptimizePHIs.cpp - Optimize machine instruction PHIs ---------------===//
26fe5c7aaSRoman Divacky //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66fe5c7aaSRoman Divacky //
76fe5c7aaSRoman Divacky //===----------------------------------------------------------------------===//
86fe5c7aaSRoman Divacky //
96fe5c7aaSRoman Divacky // This pass optimizes machine instruction PHIs to take advantage of
106fe5c7aaSRoman Divacky // opportunities created during DAG legalization.
116fe5c7aaSRoman Divacky //
126fe5c7aaSRoman Divacky //===----------------------------------------------------------------------===//
136fe5c7aaSRoman Divacky 
144a16efa3SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
154a16efa3SDimitry Andric #include "llvm/ADT/Statistic.h"
16044eb2f6SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
17044eb2f6SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
186fe5c7aaSRoman Divacky #include "llvm/CodeGen/MachineFunctionPass.h"
196fe5c7aaSRoman Divacky #include "llvm/CodeGen/MachineInstr.h"
20044eb2f6SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
216fe5c7aaSRoman Divacky #include "llvm/CodeGen/MachineRegisterInfo.h"
22044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
23706b4fc4SDimitry Andric #include "llvm/InitializePasses.h"
24044eb2f6SDimitry Andric #include "llvm/Pass.h"
25044eb2f6SDimitry Andric #include <cassert>
26044eb2f6SDimitry Andric 
276fe5c7aaSRoman Divacky using namespace llvm;
286fe5c7aaSRoman Divacky 
29ab44ce3dSDimitry Andric #define DEBUG_TYPE "opt-phis"
305ca98fd9SDimitry Andric 
316fe5c7aaSRoman Divacky STATISTIC(NumPHICycles, "Number of PHI cycles replaced");
326fe5c7aaSRoman Divacky STATISTIC(NumDeadPHICycles, "Number of dead PHI cycles");
336fe5c7aaSRoman Divacky 
346fe5c7aaSRoman Divacky namespace {
35044eb2f6SDimitry Andric 
366fe5c7aaSRoman Divacky   class OptimizePHIs : public MachineFunctionPass {
377fa27ce4SDimitry Andric     MachineRegisterInfo *MRI = nullptr;
387fa27ce4SDimitry Andric     const TargetInstrInfo *TII = nullptr;
396fe5c7aaSRoman Divacky 
406fe5c7aaSRoman Divacky   public:
416fe5c7aaSRoman Divacky     static char ID; // Pass identification
42044eb2f6SDimitry Andric 
OptimizePHIs()43cf099d11SDimitry Andric     OptimizePHIs() : MachineFunctionPass(ID) {
44cf099d11SDimitry Andric       initializeOptimizePHIsPass(*PassRegistry::getPassRegistry());
45cf099d11SDimitry Andric     }
466fe5c7aaSRoman Divacky 
47eb11fae6SDimitry Andric     bool runOnMachineFunction(MachineFunction &Fn) override;
486fe5c7aaSRoman Divacky 
getAnalysisUsage(AnalysisUsage & AU) const495ca98fd9SDimitry Andric     void getAnalysisUsage(AnalysisUsage &AU) const override {
506fe5c7aaSRoman Divacky       AU.setPreservesCFG();
516fe5c7aaSRoman Divacky       MachineFunctionPass::getAnalysisUsage(AU);
526fe5c7aaSRoman Divacky     }
536fe5c7aaSRoman Divacky 
546fe5c7aaSRoman Divacky   private:
55044eb2f6SDimitry Andric     using InstrSet = SmallPtrSet<MachineInstr *, 16>;
56044eb2f6SDimitry Andric     using InstrSetIterator = SmallPtrSetIterator<MachineInstr *>;
576fe5c7aaSRoman Divacky 
586fe5c7aaSRoman Divacky     bool IsSingleValuePHICycle(MachineInstr *MI, unsigned &SingleValReg,
596fe5c7aaSRoman Divacky                                InstrSet &PHIsInCycle);
606fe5c7aaSRoman Divacky     bool IsDeadPHICycle(MachineInstr *MI, InstrSet &PHIsInCycle);
616fe5c7aaSRoman Divacky     bool OptimizeBB(MachineBasicBlock &MBB);
626fe5c7aaSRoman Divacky   };
63044eb2f6SDimitry Andric 
64044eb2f6SDimitry Andric } // end anonymous namespace
656fe5c7aaSRoman Divacky 
666fe5c7aaSRoman Divacky char OptimizePHIs::ID = 0;
67044eb2f6SDimitry Andric 
6863faed5bSDimitry Andric char &llvm::OptimizePHIsID = OptimizePHIs::ID;
69044eb2f6SDimitry Andric 
70ab44ce3dSDimitry Andric INITIALIZE_PASS(OptimizePHIs, DEBUG_TYPE,
71cf099d11SDimitry Andric                 "Optimize machine instruction PHIs", false, false)
726fe5c7aaSRoman Divacky 
runOnMachineFunction(MachineFunction & Fn)736fe5c7aaSRoman Divacky bool OptimizePHIs::runOnMachineFunction(MachineFunction &Fn) {
74044eb2f6SDimitry Andric   if (skipFunction(Fn.getFunction()))
755ca98fd9SDimitry Andric     return false;
765ca98fd9SDimitry Andric 
776fe5c7aaSRoman Divacky   MRI = &Fn.getRegInfo();
7867c32a98SDimitry Andric   TII = Fn.getSubtarget().getInstrInfo();
796fe5c7aaSRoman Divacky 
806fe5c7aaSRoman Divacky   // Find dead PHI cycles and PHI cycles that can be replaced by a single
816fe5c7aaSRoman Divacky   // value.  InstCombine does these optimizations, but DAG legalization may
826fe5c7aaSRoman Divacky   // introduce new opportunities, e.g., when i64 values are split up for
836fe5c7aaSRoman Divacky   // 32-bit targets.
846fe5c7aaSRoman Divacky   bool Changed = false;
85344a3780SDimitry Andric   for (MachineBasicBlock &MBB : Fn)
86344a3780SDimitry Andric     Changed |= OptimizeBB(MBB);
876fe5c7aaSRoman Divacky 
886fe5c7aaSRoman Divacky   return Changed;
896fe5c7aaSRoman Divacky }
906fe5c7aaSRoman Divacky 
916fe5c7aaSRoman Divacky /// IsSingleValuePHICycle - Check if MI is a PHI where all the source operands
926fe5c7aaSRoman Divacky /// are copies of SingleValReg, possibly via copies through other PHIs. If
936fe5c7aaSRoman Divacky /// SingleValReg is zero on entry, it is set to the register with the single
946fe5c7aaSRoman Divacky /// non-copy value. PHIsInCycle is a set used to keep track of the PHIs that
95d8e91e46SDimitry Andric /// have been scanned. PHIs may be grouped by cycle, several cycles or chains.
IsSingleValuePHICycle(MachineInstr * MI,unsigned & SingleValReg,InstrSet & PHIsInCycle)966fe5c7aaSRoman Divacky bool OptimizePHIs::IsSingleValuePHICycle(MachineInstr *MI,
976fe5c7aaSRoman Divacky                                          unsigned &SingleValReg,
986fe5c7aaSRoman Divacky                                          InstrSet &PHIsInCycle) {
996fe5c7aaSRoman Divacky   assert(MI->isPHI() && "IsSingleValuePHICycle expects a PHI instruction");
1001d5ae102SDimitry Andric   Register DstReg = MI->getOperand(0).getReg();
1016fe5c7aaSRoman Divacky 
1026fe5c7aaSRoman Divacky   // See if we already saw this register.
10367c32a98SDimitry Andric   if (!PHIsInCycle.insert(MI).second)
1046fe5c7aaSRoman Divacky     return true;
1056fe5c7aaSRoman Divacky 
1066fe5c7aaSRoman Divacky   // Don't scan crazily complex things.
1076fe5c7aaSRoman Divacky   if (PHIsInCycle.size() == 16)
1086fe5c7aaSRoman Divacky     return false;
1096fe5c7aaSRoman Divacky 
1106fe5c7aaSRoman Divacky   // Scan the PHI operands.
1116fe5c7aaSRoman Divacky   for (unsigned i = 1; i != MI->getNumOperands(); i += 2) {
1121d5ae102SDimitry Andric     Register SrcReg = MI->getOperand(i).getReg();
1136fe5c7aaSRoman Divacky     if (SrcReg == DstReg)
1146fe5c7aaSRoman Divacky       continue;
1156fe5c7aaSRoman Divacky     MachineInstr *SrcMI = MRI->getVRegDef(SrcReg);
1166fe5c7aaSRoman Divacky 
1176fe5c7aaSRoman Divacky     // Skip over register-to-register moves.
1181d5ae102SDimitry Andric     if (SrcMI && SrcMI->isCopy() && !SrcMI->getOperand(0).getSubReg() &&
11966e41e3cSRoman Divacky         !SrcMI->getOperand(1).getSubReg() &&
120e3b55780SDimitry Andric         SrcMI->getOperand(1).getReg().isVirtual()) {
121d8e91e46SDimitry Andric       SrcReg = SrcMI->getOperand(1).getReg();
122d8e91e46SDimitry Andric       SrcMI = MRI->getVRegDef(SrcReg);
123d8e91e46SDimitry Andric     }
1246fe5c7aaSRoman Divacky     if (!SrcMI)
1256fe5c7aaSRoman Divacky       return false;
1266fe5c7aaSRoman Divacky 
1276fe5c7aaSRoman Divacky     if (SrcMI->isPHI()) {
1286fe5c7aaSRoman Divacky       if (!IsSingleValuePHICycle(SrcMI, SingleValReg, PHIsInCycle))
1296fe5c7aaSRoman Divacky         return false;
1306fe5c7aaSRoman Divacky     } else {
1316fe5c7aaSRoman Divacky       // Fail if there is more than one non-phi/non-move register.
132d8e91e46SDimitry Andric       if (SingleValReg != 0 && SingleValReg != SrcReg)
1336fe5c7aaSRoman Divacky         return false;
1346fe5c7aaSRoman Divacky       SingleValReg = SrcReg;
1356fe5c7aaSRoman Divacky     }
1366fe5c7aaSRoman Divacky   }
1376fe5c7aaSRoman Divacky   return true;
1386fe5c7aaSRoman Divacky }
1396fe5c7aaSRoman Divacky 
1406fe5c7aaSRoman Divacky /// IsDeadPHICycle - Check if the register defined by a PHI is only used by
1416fe5c7aaSRoman Divacky /// other PHIs in a cycle.
IsDeadPHICycle(MachineInstr * MI,InstrSet & PHIsInCycle)1426fe5c7aaSRoman Divacky bool OptimizePHIs::IsDeadPHICycle(MachineInstr *MI, InstrSet &PHIsInCycle) {
1436fe5c7aaSRoman Divacky   assert(MI->isPHI() && "IsDeadPHICycle expects a PHI instruction");
1441d5ae102SDimitry Andric   Register DstReg = MI->getOperand(0).getReg();
145e3b55780SDimitry Andric   assert(DstReg.isVirtual() && "PHI destination is not a virtual register");
1466fe5c7aaSRoman Divacky 
1476fe5c7aaSRoman Divacky   // See if we already saw this register.
14867c32a98SDimitry Andric   if (!PHIsInCycle.insert(MI).second)
1496fe5c7aaSRoman Divacky     return true;
1506fe5c7aaSRoman Divacky 
1516fe5c7aaSRoman Divacky   // Don't scan crazily complex things.
1526fe5c7aaSRoman Divacky   if (PHIsInCycle.size() == 16)
1536fe5c7aaSRoman Divacky     return false;
1546fe5c7aaSRoman Divacky 
155044eb2f6SDimitry Andric   for (MachineInstr &UseMI : MRI->use_nodbg_instructions(DstReg)) {
1565ca98fd9SDimitry Andric     if (!UseMI.isPHI() || !IsDeadPHICycle(&UseMI, PHIsInCycle))
1576fe5c7aaSRoman Divacky       return false;
1586fe5c7aaSRoman Divacky   }
1596fe5c7aaSRoman Divacky 
1606fe5c7aaSRoman Divacky   return true;
1616fe5c7aaSRoman Divacky }
1626fe5c7aaSRoman Divacky 
1636fe5c7aaSRoman Divacky /// OptimizeBB - Remove dead PHI cycles and PHI cycles that can be replaced by
1646fe5c7aaSRoman Divacky /// a single value.
OptimizeBB(MachineBasicBlock & MBB)1656fe5c7aaSRoman Divacky bool OptimizePHIs::OptimizeBB(MachineBasicBlock &MBB) {
1666fe5c7aaSRoman Divacky   bool Changed = false;
1676fe5c7aaSRoman Divacky   for (MachineBasicBlock::iterator
1686fe5c7aaSRoman Divacky          MII = MBB.begin(), E = MBB.end(); MII != E; ) {
1696fe5c7aaSRoman Divacky     MachineInstr *MI = &*MII++;
1706fe5c7aaSRoman Divacky     if (!MI->isPHI())
1716fe5c7aaSRoman Divacky       break;
1726fe5c7aaSRoman Divacky 
1736fe5c7aaSRoman Divacky     // Check for single-value PHI cycles.
1746fe5c7aaSRoman Divacky     unsigned SingleValReg = 0;
1756fe5c7aaSRoman Divacky     InstrSet PHIsInCycle;
1766fe5c7aaSRoman Divacky     if (IsSingleValuePHICycle(MI, SingleValReg, PHIsInCycle) &&
1776fe5c7aaSRoman Divacky         SingleValReg != 0) {
1781d5ae102SDimitry Andric       Register OldReg = MI->getOperand(0).getReg();
17963faed5bSDimitry Andric       if (!MRI->constrainRegClass(SingleValReg, MRI->getRegClass(OldReg)))
18063faed5bSDimitry Andric         continue;
18163faed5bSDimitry Andric 
18263faed5bSDimitry Andric       MRI->replaceRegWith(OldReg, SingleValReg);
1836fe5c7aaSRoman Divacky       MI->eraseFromParent();
184e6d15924SDimitry Andric 
185e6d15924SDimitry Andric       // The kill flags on OldReg and SingleValReg may no longer be correct.
186e6d15924SDimitry Andric       MRI->clearKillFlags(SingleValReg);
187e6d15924SDimitry Andric 
1886fe5c7aaSRoman Divacky       ++NumPHICycles;
1896fe5c7aaSRoman Divacky       Changed = true;
1906fe5c7aaSRoman Divacky       continue;
1916fe5c7aaSRoman Divacky     }
1926fe5c7aaSRoman Divacky 
1936fe5c7aaSRoman Divacky     // Check for dead PHI cycles.
1946fe5c7aaSRoman Divacky     PHIsInCycle.clear();
1956fe5c7aaSRoman Divacky     if (IsDeadPHICycle(MI, PHIsInCycle)) {
196344a3780SDimitry Andric       for (MachineInstr *PhiMI : PHIsInCycle) {
197b915e9e0SDimitry Andric         if (MII == PhiMI)
1986fe5c7aaSRoman Divacky           ++MII;
1996fe5c7aaSRoman Divacky         PhiMI->eraseFromParent();
2006fe5c7aaSRoman Divacky       }
2016fe5c7aaSRoman Divacky       ++NumDeadPHICycles;
2026fe5c7aaSRoman Divacky       Changed = true;
2036fe5c7aaSRoman Divacky     }
2046fe5c7aaSRoman Divacky   }
2056fe5c7aaSRoman Divacky   return Changed;
2066fe5c7aaSRoman Divacky }
207