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