Skip to content

Commit

Permalink
[RDA] Avoid full reprocessing of blocks in loops (NFCI)
Browse files Browse the repository at this point in the history
RDA sometimes needs to visit blocks twice, to take into account
reaching defs coming in along loop back edges. Currently it handles
repeated visitation the same way as usual, which means that it will
scan through all instructions and their reg unit defs again. Not
only is this very inefficient, it also means that all reaching defs
in loops are going to be inserted twice.

We can do much better than this. The only thing we need to handle
is a new reaching def from a predecessor, which either needs to be
prepended to the reaching definitions (if there was no reaching def
from a predecessor), or needs to replace an existing predecessor
reaching def, if it is more recent. Since D77508 we only store the
most recent predecessor reaching def, so that's the only one that
may need updating.

This also has the nice side-effect that reaching definitions are
now automatically sorted and unique, so drop the llvm::sort() call
in favor of an assertion.

Differential Revision: https://reviews.llvm.org/D77511
  • Loading branch information
nikic committed Apr 7, 2020
1 parent 76e987b commit 259649a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 3 deletions.
3 changes: 3 additions & 0 deletions llvm/include/llvm/CodeGen/ReachingDefAnalysis.h
Expand Up @@ -207,6 +207,9 @@ class ReachingDefAnalysis : public MachineFunctionPass {
/// Process he given basic block.
void processBasicBlock(const LoopTraversal::TraversedMBBInfo &TraversedMBB);

/// Process block that is part of a loop again.
void reprocessBasicBlock(MachineBasicBlock *MBB);

/// Update def-ages for registers defined by MI.
/// Also break dependencies on partial defs and undef uses.
void processDefs(MachineInstr *);
Expand Down
65 changes: 62 additions & 3 deletions llvm/lib/CodeGen/ReachingDefAnalysis.cpp
Expand Up @@ -137,13 +137,65 @@ void ReachingDefAnalysis::processDefs(MachineInstr *MI) {
++CurInstr;
}

void ReachingDefAnalysis::reprocessBasicBlock(MachineBasicBlock *MBB) {
unsigned MBBNumber = MBB->getNumber();
assert(MBBNumber < MBBReachingDefs.size() &&
"Unexpected basic block number.");

// Count number of non-debug instructions for end of block adjustment.
int NumInsts = 0;
for (const MachineInstr &MI : *MBB)
if (!MI.isDebugInstr())
NumInsts++;

// When reprocessing a block, the only thing we need to do is check whether
// there is now a more recent incoming reaching definition from a predecessor.
for (MachineBasicBlock *pred : MBB->predecessors()) {
assert(unsigned(pred->getNumber()) < MBBOutRegsInfos.size() &&
"Should have pre-allocated MBBInfos for all MBBs");
const LiveRegsDefInfo &Incoming = MBBOutRegsInfos[pred->getNumber()];
// Incoming may be empty for dead predecessors.
if (Incoming.empty())
continue;

for (unsigned Unit = 0; Unit != NumRegUnits; ++Unit) {
int Def = Incoming[Unit];
if (Def == ReachingDefDefaultVal)
continue;

auto Start = MBBReachingDefs[MBBNumber][Unit].begin();
if (Start != MBBReachingDefs[MBBNumber][Unit].end() && *Start < 0) {
if (*Start >= Def)
continue;

// Update existing reaching def from predecessor to a more recent one.
*Start = Def;
} else {
// Insert new reaching def from predecessor.
MBBReachingDefs[MBBNumber][Unit].insert(Start, Def);
}

// Update reaching def at end of of BB. Keep in mind that these are
// adjusted relative to the end of the basic block.
if (MBBOutRegsInfos[MBBNumber][Unit] < Def - NumInsts)
MBBOutRegsInfos[MBBNumber][Unit] = Def - NumInsts;
}
}
}

void ReachingDefAnalysis::processBasicBlock(
const LoopTraversal::TraversedMBBInfo &TraversedMBB) {
MachineBasicBlock *MBB = TraversedMBB.MBB;
LLVM_DEBUG(dbgs() << printMBBReference(*MBB)
<< (!TraversedMBB.IsDone ? ": incomplete\n"
: ": all preds known\n"));

if (!TraversedMBB.PrimaryPass) {
// Reprocess MBB that is part of a loop.
reprocessBasicBlock(MBB);
return;
}

enterBasicBlock(MBB);
for (MachineInstr &MI : *MBB) {
if (!MI.isDebugInstr())
Expand Down Expand Up @@ -188,11 +240,18 @@ void ReachingDefAnalysis::traverse() {
// Traverse the basic blocks.
for (LoopTraversal::TraversedMBBInfo TraversedMBB : TraversedMBBOrder)
processBasicBlock(TraversedMBB);
// Sorting all reaching defs found for a ceartin reg unit in a given BB.
#ifndef NDEBUG
// Make sure reaching defs are sorted and unique.
for (MBBDefsInfo &MBBDefs : MBBReachingDefs) {
for (MBBRegUnitDefs &RegUnitDefs : MBBDefs)
llvm::sort(RegUnitDefs);
for (MBBRegUnitDefs &RegUnitDefs : MBBDefs) {
int LastDef = ReachingDefDefaultVal;
for (int Def : RegUnitDefs) {
assert(Def > LastDef && "Defs must be sorted and unique");
LastDef = Def;
}
}
}
#endif
}

int ReachingDefAnalysis::getReachingDef(MachineInstr *MI, int PhysReg) const {
Expand Down

0 comments on commit 259649a

Please sign in to comment.