xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/OptimizePHIs.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===- OptimizePHIs.cpp - Optimize machine instruction PHIs ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass optimizes machine instruction PHIs to take advantage of
100b57cec5SDimitry Andric // opportunities created during DAG legalization.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
150b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
23480093f4SDimitry Andric #include "llvm/InitializePasses.h"
240b57cec5SDimitry Andric #include "llvm/Pass.h"
250b57cec5SDimitry Andric #include <cassert>
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace llvm;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric #define DEBUG_TYPE "opt-phis"
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric STATISTIC(NumPHICycles, "Number of PHI cycles replaced");
320b57cec5SDimitry Andric STATISTIC(NumDeadPHICycles, "Number of dead PHI cycles");
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric namespace {
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   class OptimizePHIs : public MachineFunctionPass {
37*06c3fb27SDimitry Andric     MachineRegisterInfo *MRI = nullptr;
38*06c3fb27SDimitry Andric     const TargetInstrInfo *TII = nullptr;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   public:
410b57cec5SDimitry Andric     static char ID; // Pass identification
420b57cec5SDimitry Andric 
OptimizePHIs()430b57cec5SDimitry Andric     OptimizePHIs() : MachineFunctionPass(ID) {
440b57cec5SDimitry Andric       initializeOptimizePHIsPass(*PassRegistry::getPassRegistry());
450b57cec5SDimitry Andric     }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &Fn) override;
480b57cec5SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const490b57cec5SDimitry Andric     void getAnalysisUsage(AnalysisUsage &AU) const override {
500b57cec5SDimitry Andric       AU.setPreservesCFG();
510b57cec5SDimitry Andric       MachineFunctionPass::getAnalysisUsage(AU);
520b57cec5SDimitry Andric     }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   private:
550b57cec5SDimitry Andric     using InstrSet = SmallPtrSet<MachineInstr *, 16>;
560b57cec5SDimitry Andric     using InstrSetIterator = SmallPtrSetIterator<MachineInstr *>;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric     bool IsSingleValuePHICycle(MachineInstr *MI, unsigned &SingleValReg,
590b57cec5SDimitry Andric                                InstrSet &PHIsInCycle);
600b57cec5SDimitry Andric     bool IsDeadPHICycle(MachineInstr *MI, InstrSet &PHIsInCycle);
610b57cec5SDimitry Andric     bool OptimizeBB(MachineBasicBlock &MBB);
620b57cec5SDimitry Andric   };
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric } // end anonymous namespace
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric char OptimizePHIs::ID = 0;
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric char &llvm::OptimizePHIsID = OptimizePHIs::ID;
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric INITIALIZE_PASS(OptimizePHIs, DEBUG_TYPE,
710b57cec5SDimitry Andric                 "Optimize machine instruction PHIs", false, false)
720b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & Fn)730b57cec5SDimitry Andric bool OptimizePHIs::runOnMachineFunction(MachineFunction &Fn) {
740b57cec5SDimitry Andric   if (skipFunction(Fn.getFunction()))
750b57cec5SDimitry Andric     return false;
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   MRI = &Fn.getRegInfo();
780b57cec5SDimitry Andric   TII = Fn.getSubtarget().getInstrInfo();
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   // Find dead PHI cycles and PHI cycles that can be replaced by a single
810b57cec5SDimitry Andric   // value.  InstCombine does these optimizations, but DAG legalization may
820b57cec5SDimitry Andric   // introduce new opportunities, e.g., when i64 values are split up for
830b57cec5SDimitry Andric   // 32-bit targets.
840b57cec5SDimitry Andric   bool Changed = false;
85fe6060f1SDimitry Andric   for (MachineBasicBlock &MBB : Fn)
86fe6060f1SDimitry Andric     Changed |= OptimizeBB(MBB);
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   return Changed;
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric /// IsSingleValuePHICycle - Check if MI is a PHI where all the source operands
920b57cec5SDimitry Andric /// are copies of SingleValReg, possibly via copies through other PHIs. If
930b57cec5SDimitry Andric /// SingleValReg is zero on entry, it is set to the register with the single
940b57cec5SDimitry Andric /// non-copy value. PHIsInCycle is a set used to keep track of the PHIs that
950b57cec5SDimitry Andric /// have been scanned. PHIs may be grouped by cycle, several cycles or chains.
IsSingleValuePHICycle(MachineInstr * MI,unsigned & SingleValReg,InstrSet & PHIsInCycle)960b57cec5SDimitry Andric bool OptimizePHIs::IsSingleValuePHICycle(MachineInstr *MI,
970b57cec5SDimitry Andric                                          unsigned &SingleValReg,
980b57cec5SDimitry Andric                                          InstrSet &PHIsInCycle) {
990b57cec5SDimitry Andric   assert(MI->isPHI() && "IsSingleValuePHICycle expects a PHI instruction");
1008bcb0991SDimitry Andric   Register DstReg = MI->getOperand(0).getReg();
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   // See if we already saw this register.
1030b57cec5SDimitry Andric   if (!PHIsInCycle.insert(MI).second)
1040b57cec5SDimitry Andric     return true;
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   // Don't scan crazily complex things.
1070b57cec5SDimitry Andric   if (PHIsInCycle.size() == 16)
1080b57cec5SDimitry Andric     return false;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   // Scan the PHI operands.
1110b57cec5SDimitry Andric   for (unsigned i = 1; i != MI->getNumOperands(); i += 2) {
1128bcb0991SDimitry Andric     Register SrcReg = MI->getOperand(i).getReg();
1130b57cec5SDimitry Andric     if (SrcReg == DstReg)
1140b57cec5SDimitry Andric       continue;
1150b57cec5SDimitry Andric     MachineInstr *SrcMI = MRI->getVRegDef(SrcReg);
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric     // Skip over register-to-register moves.
1188bcb0991SDimitry Andric     if (SrcMI && SrcMI->isCopy() && !SrcMI->getOperand(0).getSubReg() &&
1190b57cec5SDimitry Andric         !SrcMI->getOperand(1).getSubReg() &&
120bdd1243dSDimitry Andric         SrcMI->getOperand(1).getReg().isVirtual()) {
1210b57cec5SDimitry Andric       SrcReg = SrcMI->getOperand(1).getReg();
1220b57cec5SDimitry Andric       SrcMI = MRI->getVRegDef(SrcReg);
1230b57cec5SDimitry Andric     }
1240b57cec5SDimitry Andric     if (!SrcMI)
1250b57cec5SDimitry Andric       return false;
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric     if (SrcMI->isPHI()) {
1280b57cec5SDimitry Andric       if (!IsSingleValuePHICycle(SrcMI, SingleValReg, PHIsInCycle))
1290b57cec5SDimitry Andric         return false;
1300b57cec5SDimitry Andric     } else {
1310b57cec5SDimitry Andric       // Fail if there is more than one non-phi/non-move register.
1320b57cec5SDimitry Andric       if (SingleValReg != 0 && SingleValReg != SrcReg)
1330b57cec5SDimitry Andric         return false;
1340b57cec5SDimitry Andric       SingleValReg = SrcReg;
1350b57cec5SDimitry Andric     }
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric   return true;
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric /// IsDeadPHICycle - Check if the register defined by a PHI is only used by
1410b57cec5SDimitry Andric /// other PHIs in a cycle.
IsDeadPHICycle(MachineInstr * MI,InstrSet & PHIsInCycle)1420b57cec5SDimitry Andric bool OptimizePHIs::IsDeadPHICycle(MachineInstr *MI, InstrSet &PHIsInCycle) {
1430b57cec5SDimitry Andric   assert(MI->isPHI() && "IsDeadPHICycle expects a PHI instruction");
1448bcb0991SDimitry Andric   Register DstReg = MI->getOperand(0).getReg();
145bdd1243dSDimitry Andric   assert(DstReg.isVirtual() && "PHI destination is not a virtual register");
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   // See if we already saw this register.
1480b57cec5SDimitry Andric   if (!PHIsInCycle.insert(MI).second)
1490b57cec5SDimitry Andric     return true;
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   // Don't scan crazily complex things.
1520b57cec5SDimitry Andric   if (PHIsInCycle.size() == 16)
1530b57cec5SDimitry Andric     return false;
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   for (MachineInstr &UseMI : MRI->use_nodbg_instructions(DstReg)) {
1560b57cec5SDimitry Andric     if (!UseMI.isPHI() || !IsDeadPHICycle(&UseMI, PHIsInCycle))
1570b57cec5SDimitry Andric       return false;
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   return true;
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric /// OptimizeBB - Remove dead PHI cycles and PHI cycles that can be replaced by
1640b57cec5SDimitry Andric /// a single value.
OptimizeBB(MachineBasicBlock & MBB)1650b57cec5SDimitry Andric bool OptimizePHIs::OptimizeBB(MachineBasicBlock &MBB) {
1660b57cec5SDimitry Andric   bool Changed = false;
1670b57cec5SDimitry Andric   for (MachineBasicBlock::iterator
1680b57cec5SDimitry Andric          MII = MBB.begin(), E = MBB.end(); MII != E; ) {
1690b57cec5SDimitry Andric     MachineInstr *MI = &*MII++;
1700b57cec5SDimitry Andric     if (!MI->isPHI())
1710b57cec5SDimitry Andric       break;
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric     // Check for single-value PHI cycles.
1740b57cec5SDimitry Andric     unsigned SingleValReg = 0;
1750b57cec5SDimitry Andric     InstrSet PHIsInCycle;
1760b57cec5SDimitry Andric     if (IsSingleValuePHICycle(MI, SingleValReg, PHIsInCycle) &&
1770b57cec5SDimitry Andric         SingleValReg != 0) {
1788bcb0991SDimitry Andric       Register OldReg = MI->getOperand(0).getReg();
1790b57cec5SDimitry Andric       if (!MRI->constrainRegClass(SingleValReg, MRI->getRegClass(OldReg)))
1800b57cec5SDimitry Andric         continue;
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric       MRI->replaceRegWith(OldReg, SingleValReg);
1830b57cec5SDimitry Andric       MI->eraseFromParent();
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric       // The kill flags on OldReg and SingleValReg may no longer be correct.
1860b57cec5SDimitry Andric       MRI->clearKillFlags(SingleValReg);
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric       ++NumPHICycles;
1890b57cec5SDimitry Andric       Changed = true;
1900b57cec5SDimitry Andric       continue;
1910b57cec5SDimitry Andric     }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric     // Check for dead PHI cycles.
1940b57cec5SDimitry Andric     PHIsInCycle.clear();
1950b57cec5SDimitry Andric     if (IsDeadPHICycle(MI, PHIsInCycle)) {
196fe6060f1SDimitry Andric       for (MachineInstr *PhiMI : PHIsInCycle) {
1970b57cec5SDimitry Andric         if (MII == PhiMI)
1980b57cec5SDimitry Andric           ++MII;
1990b57cec5SDimitry Andric         PhiMI->eraseFromParent();
2000b57cec5SDimitry Andric       }
2010b57cec5SDimitry Andric       ++NumDeadPHICycles;
2020b57cec5SDimitry Andric       Changed = true;
2030b57cec5SDimitry Andric     }
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric   return Changed;
2060b57cec5SDimitry Andric }
207