xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/GlobalISel/Localizer.cpp (revision 297eecfb02bb25902531dbb5c3b9a88caf8adf29)
10b57cec5SDimitry Andric //===- Localizer.cpp ---------------------- Localize some instrs -*- C++ -*-==//
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 /// \file
90b57cec5SDimitry Andric /// This file implements the Localizer class.
100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/Localizer.h"
130b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
14e8d8bef9SDimitry Andric #include "llvm/ADT/STLExtras.h"
15480093f4SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
16*297eecfbSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
1781ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
195ffd83dbSDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
20480093f4SDimitry Andric #include "llvm/InitializePasses.h"
210b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric #define DEBUG_TYPE "localizer"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric char Localizer::ID = 0;
280b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(Localizer, DEBUG_TYPE,
290b57cec5SDimitry Andric                       "Move/duplicate certain instructions close to their use",
300b57cec5SDimitry Andric                       false, false)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)310b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
320b57cec5SDimitry Andric INITIALIZE_PASS_END(Localizer, DEBUG_TYPE,
330b57cec5SDimitry Andric                     "Move/duplicate certain instructions close to their use",
340b57cec5SDimitry Andric                     false, false)
350b57cec5SDimitry Andric 
36480093f4SDimitry Andric Localizer::Localizer(std::function<bool(const MachineFunction &)> F)
37480093f4SDimitry Andric     : MachineFunctionPass(ID), DoNotRunPass(F) {}
38480093f4SDimitry Andric 
Localizer()39480093f4SDimitry Andric Localizer::Localizer()
40480093f4SDimitry Andric     : Localizer([](const MachineFunction &) { return false; }) {}
410b57cec5SDimitry Andric 
init(MachineFunction & MF)420b57cec5SDimitry Andric void Localizer::init(MachineFunction &MF) {
430b57cec5SDimitry Andric   MRI = &MF.getRegInfo();
440b57cec5SDimitry Andric   TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(MF.getFunction());
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const470b57cec5SDimitry Andric void Localizer::getAnalysisUsage(AnalysisUsage &AU) const {
480b57cec5SDimitry Andric   AU.addRequired<TargetTransformInfoWrapperPass>();
490b57cec5SDimitry Andric   getSelectionDAGFallbackAnalysisUsage(AU);
500b57cec5SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric 
isLocalUse(MachineOperand & MOUse,const MachineInstr & Def,MachineBasicBlock * & InsertMBB)530b57cec5SDimitry Andric bool Localizer::isLocalUse(MachineOperand &MOUse, const MachineInstr &Def,
540b57cec5SDimitry Andric                            MachineBasicBlock *&InsertMBB) {
550b57cec5SDimitry Andric   MachineInstr &MIUse = *MOUse.getParent();
560b57cec5SDimitry Andric   InsertMBB = MIUse.getParent();
570b57cec5SDimitry Andric   if (MIUse.isPHI())
5806c3fb27SDimitry Andric     InsertMBB = MIUse.getOperand(MOUse.getOperandNo() + 1).getMBB();
590b57cec5SDimitry Andric   return InsertMBB == Def.getParent();
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
getNumPhiUses(MachineOperand & Op) const62*297eecfbSDimitry Andric unsigned Localizer::getNumPhiUses(MachineOperand &Op) const {
63*297eecfbSDimitry Andric   auto *MI = dyn_cast<GPhi>(&*Op.getParent());
64*297eecfbSDimitry Andric   if (!MI)
65*297eecfbSDimitry Andric     return 0;
66e8d8bef9SDimitry Andric 
67e8d8bef9SDimitry Andric   Register SrcReg = Op.getReg();
68*297eecfbSDimitry Andric   unsigned NumUses = 0;
69*297eecfbSDimitry Andric   for (unsigned I = 0, NumVals = MI->getNumIncomingValues(); I < NumVals; ++I) {
70*297eecfbSDimitry Andric     if (MI->getIncomingValue(I) == SrcReg)
71*297eecfbSDimitry Andric       ++NumUses;
72e8d8bef9SDimitry Andric   }
73*297eecfbSDimitry Andric   return NumUses;
74e8d8bef9SDimitry Andric }
75e8d8bef9SDimitry Andric 
localizeInterBlock(MachineFunction & MF,LocalizedSetVecT & LocalizedInstrs)760b57cec5SDimitry Andric bool Localizer::localizeInterBlock(MachineFunction &MF,
770b57cec5SDimitry Andric                                    LocalizedSetVecT &LocalizedInstrs) {
780b57cec5SDimitry Andric   bool Changed = false;
790b57cec5SDimitry Andric   DenseMap<std::pair<MachineBasicBlock *, unsigned>, unsigned> MBBWithLocalDef;
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   // Since the IRTranslator only emits constants into the entry block, and the
820b57cec5SDimitry Andric   // rest of the GISel pipeline generally emits constants close to their users,
830b57cec5SDimitry Andric   // we only localize instructions in the entry block here. This might change if
840b57cec5SDimitry Andric   // we start doing CSE across blocks.
850b57cec5SDimitry Andric   auto &MBB = MF.front();
865ffd83dbSDimitry Andric   auto &TL = *MF.getSubtarget().getTargetLowering();
87fe6060f1SDimitry Andric   for (MachineInstr &MI : llvm::reverse(MBB)) {
885ffd83dbSDimitry Andric     if (!TL.shouldLocalize(MI, TTI))
890b57cec5SDimitry Andric       continue;
900b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Should localize: " << MI);
910b57cec5SDimitry Andric     assert(MI.getDesc().getNumDefs() == 1 &&
920b57cec5SDimitry Andric            "More than one definition not supported yet");
938bcb0991SDimitry Andric     Register Reg = MI.getOperand(0).getReg();
940b57cec5SDimitry Andric     // Check if all the users of MI are local.
950b57cec5SDimitry Andric     // We are going to invalidation the list of use operands, so we
960b57cec5SDimitry Andric     // can't use range iterator.
97349cc55cSDimitry Andric     for (MachineOperand &MOUse :
98349cc55cSDimitry Andric          llvm::make_early_inc_range(MRI->use_operands(Reg))) {
990b57cec5SDimitry Andric       // Check if the use is already local.
1000b57cec5SDimitry Andric       MachineBasicBlock *InsertMBB;
1010b57cec5SDimitry Andric       LLVM_DEBUG(MachineInstr &MIUse = *MOUse.getParent();
1020b57cec5SDimitry Andric                  dbgs() << "Checking use: " << MIUse
10306c3fb27SDimitry Andric                         << " #Opd: " << MOUse.getOperandNo() << '\n');
1045ffd83dbSDimitry Andric       if (isLocalUse(MOUse, MI, InsertMBB)) {
1055ffd83dbSDimitry Andric         // Even if we're in the same block, if the block is very large we could
1065ffd83dbSDimitry Andric         // still have many long live ranges. Try to do intra-block localization
1075ffd83dbSDimitry Andric         // too.
1085ffd83dbSDimitry Andric         LocalizedInstrs.insert(&MI);
1090b57cec5SDimitry Andric         continue;
1105ffd83dbSDimitry Andric       }
111e8d8bef9SDimitry Andric 
112*297eecfbSDimitry Andric       // PHIs look like a single user but can use the same register in multiple
113*297eecfbSDimitry Andric       // edges, causing remat into each predecessor. Allow this to a certain
114*297eecfbSDimitry Andric       // extent.
115*297eecfbSDimitry Andric       unsigned NumPhiUses = getNumPhiUses(MOUse);
116*297eecfbSDimitry Andric       const unsigned PhiThreshold = 2; // FIXME: Tune this more.
117*297eecfbSDimitry Andric       if (NumPhiUses > PhiThreshold)
118e8d8bef9SDimitry Andric         continue;
119e8d8bef9SDimitry Andric 
1200b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Fixing non-local use\n");
1210b57cec5SDimitry Andric       Changed = true;
1220b57cec5SDimitry Andric       auto MBBAndReg = std::make_pair(InsertMBB, Reg);
1230b57cec5SDimitry Andric       auto NewVRegIt = MBBWithLocalDef.find(MBBAndReg);
1240b57cec5SDimitry Andric       if (NewVRegIt == MBBWithLocalDef.end()) {
1250b57cec5SDimitry Andric         // Create the localized instruction.
1260b57cec5SDimitry Andric         MachineInstr *LocalizedMI = MF.CloneMachineInstr(&MI);
1270b57cec5SDimitry Andric         LocalizedInstrs.insert(LocalizedMI);
1280b57cec5SDimitry Andric         MachineInstr &UseMI = *MOUse.getParent();
1290b57cec5SDimitry Andric         if (MRI->hasOneUse(Reg) && !UseMI.isPHI())
13004eeddc0SDimitry Andric           InsertMBB->insert(UseMI, LocalizedMI);
1310b57cec5SDimitry Andric         else
1320b57cec5SDimitry Andric           InsertMBB->insert(InsertMBB->SkipPHIsAndLabels(InsertMBB->begin()),
1330b57cec5SDimitry Andric                             LocalizedMI);
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric         // Set a new register for the definition.
13604eeddc0SDimitry Andric         Register NewReg = MRI->cloneVirtualRegister(Reg);
1370b57cec5SDimitry Andric         LocalizedMI->getOperand(0).setReg(NewReg);
1380b57cec5SDimitry Andric         NewVRegIt =
1390b57cec5SDimitry Andric             MBBWithLocalDef.insert(std::make_pair(MBBAndReg, NewReg)).first;
1400b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "Inserted: " << *LocalizedMI);
1410b57cec5SDimitry Andric       }
1420b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Update use with: " << printReg(NewVRegIt->second)
1430b57cec5SDimitry Andric                         << '\n');
1440b57cec5SDimitry Andric       // Update the user reg.
1450b57cec5SDimitry Andric       MOUse.setReg(NewVRegIt->second);
1460b57cec5SDimitry Andric     }
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric   return Changed;
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
localizeIntraBlock(LocalizedSetVecT & LocalizedInstrs)1510b57cec5SDimitry Andric bool Localizer::localizeIntraBlock(LocalizedSetVecT &LocalizedInstrs) {
1520b57cec5SDimitry Andric   bool Changed = false;
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   // For each already-localized instruction which has multiple users, then we
1550b57cec5SDimitry Andric   // scan the block top down from the current position until we hit one of them.
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric   // FIXME: Consider doing inst duplication if live ranges are very long due to
1580b57cec5SDimitry Andric   // many users, but this case may be better served by regalloc improvements.
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   for (MachineInstr *MI : LocalizedInstrs) {
1618bcb0991SDimitry Andric     Register Reg = MI->getOperand(0).getReg();
1620b57cec5SDimitry Andric     MachineBasicBlock &MBB = *MI->getParent();
1630b57cec5SDimitry Andric     // All of the user MIs of this reg.
1640b57cec5SDimitry Andric     SmallPtrSet<MachineInstr *, 32> Users;
1650b57cec5SDimitry Andric     for (MachineInstr &UseMI : MRI->use_nodbg_instructions(Reg)) {
1660b57cec5SDimitry Andric       if (!UseMI.isPHI())
1670b57cec5SDimitry Andric         Users.insert(&UseMI);
1680b57cec5SDimitry Andric     }
1690b57cec5SDimitry Andric     MachineBasicBlock::iterator II(MI);
170*297eecfbSDimitry Andric     // If all the users were PHIs then they're not going to be in our block, we
171*297eecfbSDimitry Andric     // may still benefit from sinking, especially since the value might be live
172*297eecfbSDimitry Andric     // across a call.
173*297eecfbSDimitry Andric     if (Users.empty()) {
174*297eecfbSDimitry Andric       // Make sure we don't sink in between two terminator sequences by scanning
175*297eecfbSDimitry Andric       // forward, not backward.
176*297eecfbSDimitry Andric       II = MBB.getFirstTerminatorForward();
177*297eecfbSDimitry Andric       LLVM_DEBUG(dbgs() << "Only phi users: moving inst to end: " << *MI);
178*297eecfbSDimitry Andric     } else {
1790b57cec5SDimitry Andric       ++II;
1800b57cec5SDimitry Andric       while (II != MBB.end() && !Users.count(&*II))
1810b57cec5SDimitry Andric         ++II;
1820b57cec5SDimitry Andric       assert(II != MBB.end() && "Didn't find the user in the MBB");
183*297eecfbSDimitry Andric       LLVM_DEBUG(dbgs() << "Intra-block: moving " << *MI << " before " << *II);
184*297eecfbSDimitry Andric     }
18504eeddc0SDimitry Andric 
1860b57cec5SDimitry Andric     MI->removeFromParent();
1870b57cec5SDimitry Andric     MBB.insert(II, MI);
1880b57cec5SDimitry Andric     Changed = true;
189bdd1243dSDimitry Andric 
190bdd1243dSDimitry Andric     // If the instruction (constant) being localized has single user, we can
191bdd1243dSDimitry Andric     // propagate debug location from user.
192bdd1243dSDimitry Andric     if (Users.size() == 1) {
193bdd1243dSDimitry Andric       const auto &DefDL = MI->getDebugLoc();
194bdd1243dSDimitry Andric       const auto &UserDL = (*Users.begin())->getDebugLoc();
195bdd1243dSDimitry Andric 
196bdd1243dSDimitry Andric       if ((!DefDL || DefDL.getLine() == 0) && UserDL && UserDL.getLine() != 0) {
197bdd1243dSDimitry Andric         MI->setDebugLoc(UserDL);
198bdd1243dSDimitry Andric       }
199bdd1243dSDimitry Andric     }
2000b57cec5SDimitry Andric   }
2010b57cec5SDimitry Andric   return Changed;
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)2040b57cec5SDimitry Andric bool Localizer::runOnMachineFunction(MachineFunction &MF) {
2050b57cec5SDimitry Andric   // If the ISel pipeline failed, do not bother running that pass.
2060b57cec5SDimitry Andric   if (MF.getProperties().hasProperty(
2070b57cec5SDimitry Andric           MachineFunctionProperties::Property::FailedISel))
2080b57cec5SDimitry Andric     return false;
2090b57cec5SDimitry Andric 
210480093f4SDimitry Andric   // Don't run the pass if the target asked so.
211480093f4SDimitry Andric   if (DoNotRunPass(MF))
212480093f4SDimitry Andric     return false;
213480093f4SDimitry Andric 
2140b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Localize instructions for: " << MF.getName() << '\n');
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   init(MF);
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   // Keep track of the instructions we localized. We'll do a second pass of
2190b57cec5SDimitry Andric   // intra-block localization to further reduce live ranges.
2200b57cec5SDimitry Andric   LocalizedSetVecT LocalizedInstrs;
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric   bool Changed = localizeInterBlock(MF, LocalizedInstrs);
2238bcb0991SDimitry Andric   Changed |= localizeIntraBlock(LocalizedInstrs);
2248bcb0991SDimitry Andric   return Changed;
2250b57cec5SDimitry Andric }
226