Skip to content

Commit e8427ee

Browse files
committed
[DomTreeUpdater] Move critical edge splitting code to updater
1 parent 87c35d7 commit e8427ee

29 files changed

+329
-314
lines changed

llvm/include/llvm/Analysis/DomTreeUpdater.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class DomTreeUpdater
8383

8484
///@}
8585

86+
/// Debug method to help view the internal state of this class.
87+
LLVM_DUMP_METHOD void dump() const;
88+
8689
private:
8790
class CallBackOnDeletion final : public CallbackVH {
8891
public:
@@ -111,9 +114,6 @@ class DomTreeUpdater
111114

112115
/// Returns true if at least one BasicBlock is deleted.
113116
bool forceFlushDeletedBB();
114-
115-
/// Debug method to help view the internal state of this class.
116-
LLVM_DUMP_METHOD void dump() const;
117117
};
118118

119119
extern template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,

llvm/include/llvm/Analysis/GenericDomTreeUpdater.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ class GenericDomTreeUpdater {
105105
return PendUpdates.size() != PendPDTUpdateIndex;
106106
}
107107

108+
bool hasPendingCriticalEdges() const {
109+
if (!PDT && !DT)
110+
return false;
111+
return !CriticalEdgesToSplit.empty();
112+
}
113+
108114
///@{
109115
/// \name Mutation APIs
110116
///
@@ -146,8 +152,25 @@ class GenericDomTreeUpdater {
146152
/// 2. It is illegal to submit any update that has already been submitted,
147153
/// i.e., you are supposed not to insert an existent edge or delete a
148154
/// nonexistent edge.
155+
/// 3. This kind updates are incompatible with critical edge splitting
156+
/// updates, call this method will apply all critical edge updates in
157+
/// lazy mode. It is not recommended to interleave applyUpdates and
158+
/// applyUpdatesForCriticalEdgeSplitting.
149159
void applyUpdates(ArrayRef<typename DomTreeT::UpdateType> Updates);
150160

161+
/// Apply updates that the critical edge (FromBB, ToBB) has been
162+
/// split with NewBB.
163+
///
164+
/// \note Do not use this method with regular edges.
165+
///
166+
/// \note This kind updates are incompatible with generic updates,
167+
/// call this method will submit all generic updates in lazy mode.
168+
/// It is not recommended to interleave applyUpdates and
169+
/// applyUpdatesForCriticalEdgeSplitting.
170+
void applyUpdatesForCriticalEdgeSplitting(BasicBlockT *FromBB,
171+
BasicBlockT *ToBB,
172+
BasicBlockT *NewBB);
173+
151174
/// Submit updates to all available trees. It will also
152175
/// 1. discard duplicated updates,
153176
/// 2. remove invalid updates. (Invalid updates means deletion of an edge that
@@ -197,6 +220,7 @@ class GenericDomTreeUpdater {
197220
applyDomTreeUpdates();
198221
applyPostDomTreeUpdates();
199222
dropOutOfDateUpdates();
223+
applySplitCriticalEdges();
200224
}
201225

202226
///@}
@@ -243,6 +267,35 @@ class GenericDomTreeUpdater {
243267
/// Drop all updates applied by all available trees and delete BasicBlocks if
244268
/// all available trees are up-to-date.
245269
void dropOutOfDateUpdates();
270+
271+
private:
272+
/// Helper structure used to hold all the basic blocks
273+
/// involved in the split of a critical edge.
274+
struct CriticalEdge {
275+
BasicBlockT *FromBB;
276+
BasicBlockT *ToBB;
277+
BasicBlockT *NewBB;
278+
};
279+
280+
/// Pile up all the critical edges to be split.
281+
/// The splitting of a critical edge is local and thus, it is possible
282+
/// to apply several of those changes at the same time.
283+
SmallVector<CriticalEdge, 32> CriticalEdgesToSplit;
284+
285+
/// Remember all the basic blocks that are inserted during
286+
/// edge splitting.
287+
/// Invariant: NewBBs == all the basic blocks contained in the NewBB
288+
/// field of all the elements of CriticalEdgesToSplit.
289+
/// I.e., forall elt in CriticalEdgesToSplit, it exists BB in NewBBs
290+
/// such as BB == elt.NewBB.
291+
SmallSet<BasicBlockT *, 32> NewBBs;
292+
293+
/// Apply all the recorded critical edges to the DT.
294+
/// This updates the underlying DT information in a way that uses
295+
/// the fast query path of DT as much as possible.
296+
///
297+
/// \post CriticalEdgesToSplit.empty().
298+
void applySplitCriticalEdges();
246299
};
247300

248301
} // namespace llvm

llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
1717
#define LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
1818

19+
#include "llvm/ADT/SmallBitVector.h"
1920
#include "llvm/Analysis/GenericDomTreeUpdater.h"
2021
#include "llvm/Support/Debug.h"
2122
#include "llvm/Support/raw_ostream.h"
@@ -61,6 +62,9 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::applyUpdates(
6162
return;
6263

6364
if (Strategy == UpdateStrategy::Lazy) {
65+
if (!CriticalEdgesToSplit.empty())
66+
applySplitCriticalEdges();
67+
6468
PendUpdates.reserve(PendUpdates.size() + Updates.size());
6569
for (const auto &U : Updates)
6670
if (!isSelfDominance(U))
@@ -136,6 +140,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::getDomTree() {
136140
assert(DT && "Invalid acquisition of a null DomTree");
137141
applyDomTreeUpdates();
138142
dropOutOfDateUpdates();
143+
applySplitCriticalEdges();
139144
return *DT;
140145
}
141146

@@ -145,6 +150,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::getPostDomTree() {
145150
assert(PDT && "Invalid acquisition of a null PostDomTree");
146151
applyPostDomTreeUpdates();
147152
dropOutOfDateUpdates();
153+
applySplitCriticalEdges();
148154
return *PDT;
149155
}
150156

@@ -201,7 +207,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
201207
if (To) {
202208
auto S = To->getName();
203209
if (!To->hasName())
204-
S = "(no_name)";
210+
S = "(no name)";
205211
OS << S << "(" << To << ")\n";
206212
} else {
207213
OS << "(badref)\n";
@@ -229,6 +235,22 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
229235
printUpdates(I, PendUpdates.end());
230236
}
231237

238+
auto printCriticalEdges = [&](const CriticalEdge &E) {
239+
auto FromName = E.FromBB->getName();
240+
if (!E.FromBB->hasName())
241+
FromName = "(no name)";
242+
auto NewName = E.NewBB->getName();
243+
if (!E.NewBB->hasName())
244+
NewName = "(no name)";
245+
auto ToName = E.ToBB->getName();
246+
if (!E.ToBB->hasName())
247+
ToName = "(no name)";
248+
OS << " " << FromName << ", " << NewName << ", " << ToName << '\n';
249+
};
250+
OS << "Critical edges to be split:\n";
251+
for (const auto &E : CriticalEdgesToSplit)
252+
printCriticalEdges(E);
253+
232254
OS << "Pending DeletedBBs:\n";
233255
Index = 0;
234256
for (const auto *BB : DeletedBBs) {
@@ -237,7 +259,7 @@ GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const {
237259
if (BB->hasName())
238260
OS << BB->getName() << "(";
239261
else
240-
OS << "(no_name)(";
262+
OS << "(no name)(";
241263
OS << BB << ")\n";
242264
}
243265
#endif
@@ -348,6 +370,123 @@ void GenericDomTreeUpdater<DerivedT, DomTreeT,
348370
PendPDTUpdateIndex -= dropIndex;
349371
}
350372

373+
template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
374+
void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::
375+
applyUpdatesForCriticalEdgeSplitting(BasicBlockT *FromBB, BasicBlockT *ToBB,
376+
BasicBlockT *NewBB) {
377+
if (!DT && !PDT)
378+
return;
379+
CriticalEdgesToSplit.push_back({FromBB, ToBB, NewBB});
380+
bool Inserted = NewBBs.insert(NewBB).second;
381+
(void)Inserted;
382+
assert(Inserted &&
383+
"A basic block inserted via edge splitting cannot appear twice");
384+
if (Strategy == UpdateStrategy::Lazy) {
385+
applyDomTreeUpdates();
386+
applyPostDomTreeUpdates();
387+
}
388+
if (Strategy == UpdateStrategy::Eager)
389+
applySplitCriticalEdges();
390+
}
391+
392+
template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
393+
void GenericDomTreeUpdater<DerivedT, DomTreeT,
394+
PostDomTreeT>::applySplitCriticalEdges() {
395+
// Bail out early if there is nothing to do.
396+
if (CriticalEdgesToSplit.empty())
397+
return;
398+
399+
// For each element in CriticalEdgesToSplit, remember whether or not element
400+
// is the new immediate domminator of its successor. The mapping is done by
401+
// index, i.e., the information for the ith element of CriticalEdgesToSplit is
402+
// the ith element of IsNewIDom.
403+
SmallBitVector IsNewIDom(CriticalEdgesToSplit.size(), true);
404+
SmallBitVector IsNewIPDom(CriticalEdgesToSplit.size(), true);
405+
size_t Idx = 0;
406+
407+
// Collect all the dominance properties info, before invalidating
408+
// the underlying DT.
409+
for (CriticalEdge &Edge : CriticalEdgesToSplit) {
410+
// Update dominator information.
411+
if (DT) {
412+
BasicBlockT *Succ = Edge.ToBB;
413+
auto *SuccDTNode = DT->getNode(Succ);
414+
415+
for (BasicBlockT *PredBB : predecessors(Succ)) {
416+
if (PredBB == Edge.NewBB)
417+
continue;
418+
// If we are in this situation:
419+
// FromBB1 FromBB2
420+
// + +
421+
// + + + +
422+
// + + + +
423+
// ... Split1 Split2 ...
424+
// + +
425+
// + +
426+
// +
427+
// Succ
428+
// Instead of checking the domiance property with Split2, we check it
429+
// with FromBB2 since Split2 is still unknown of the underlying DT
430+
// structure.
431+
if (NewBBs.count(PredBB)) {
432+
assert(pred_size(PredBB) == 1 && "A basic block resulting from a "
433+
"critical edge split has more "
434+
"than one predecessor!");
435+
PredBB = *pred_begin(PredBB);
436+
}
437+
if (!DT->dominates(SuccDTNode, DT->getNode(PredBB))) {
438+
IsNewIDom[Idx] = false;
439+
break;
440+
}
441+
}
442+
}
443+
444+
// Same as DT version but from another direction.
445+
if (PDT) {
446+
BasicBlockT *Pred = Edge.FromBB;
447+
auto *PredDTNode = PDT->getNode(Pred);
448+
for (BasicBlockT *SuccBB : successors(Pred)) {
449+
if (SuccBB == Edge.NewBB)
450+
continue;
451+
if (NewBBs.count(SuccBB)) {
452+
assert(succ_size(SuccBB) == 1 && "A basic block resulting from a "
453+
"critical edge split has more "
454+
"than one predecessor!");
455+
SuccBB = *succ_begin(SuccBB);
456+
}
457+
if (!PDT->dominates(PredDTNode, PDT->getNode(SuccBB))) {
458+
IsNewIPDom[Idx] = false;
459+
break;
460+
}
461+
}
462+
}
463+
++Idx;
464+
}
465+
466+
// Now, update DT with the collected dominance properties info.
467+
Idx = 0;
468+
for (CriticalEdge &Edge : CriticalEdgesToSplit) {
469+
if (DT) {
470+
// We know FromBB dominates NewBB.
471+
auto *NewDTNode = DT->addNewBlock(Edge.NewBB, Edge.FromBB);
472+
473+
// If all the other predecessors of "Succ" are dominated by "Succ" itself
474+
// then the new block is the new immediate dominator of "Succ". Otherwise,
475+
// the new block doesn't dominate anything.
476+
if (IsNewIDom[Idx])
477+
DT->changeImmediateDominator(DT->getNode(Edge.ToBB), NewDTNode);
478+
}
479+
if (PDT) {
480+
auto *NewPDTNode = PDT->addNewBlock(Edge.NewBB, Edge.ToBB);
481+
if (IsNewIPDom[Idx])
482+
PDT->changeImmediateDominator(PDT->getNode(Edge.FromBB), NewPDTNode);
483+
}
484+
++Idx;
485+
}
486+
NewBBs.clear();
487+
CriticalEdgesToSplit.clear();
488+
}
489+
351490
} // namespace llvm
352491

353492
#endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H

llvm/include/llvm/CodeGen/MachineBasicBlock.h

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
namespace llvm {
3333

3434
class BasicBlock;
35+
class MachineDomTreeUpdater;
3536
class MachineFunction;
3637
class MCSymbol;
3738
class ModuleSlotTracker;
@@ -970,15 +971,17 @@ class MachineBasicBlock
970971
/// MachineLoopInfo, as applicable.
971972
MachineBasicBlock *
972973
SplitCriticalEdge(MachineBasicBlock *Succ, Pass &P,
973-
std::vector<SparseBitVector<>> *LiveInSets = nullptr) {
974-
return SplitCriticalEdge(Succ, &P, nullptr, LiveInSets);
974+
std::vector<SparseBitVector<>> *LiveInSets = nullptr,
975+
MachineDomTreeUpdater *MDTU = nullptr) {
976+
return SplitCriticalEdge(Succ, &P, nullptr, LiveInSets, MDTU);
975977
}
976978

977979
MachineBasicBlock *
978980
SplitCriticalEdge(MachineBasicBlock *Succ,
979981
MachineFunctionAnalysisManager &MFAM,
980-
std::vector<SparseBitVector<>> *LiveInSets = nullptr) {
981-
return SplitCriticalEdge(Succ, nullptr, &MFAM, LiveInSets);
982+
std::vector<SparseBitVector<>> *LiveInSets = nullptr,
983+
MachineDomTreeUpdater *MDTU = nullptr) {
984+
return SplitCriticalEdge(Succ, nullptr, &MFAM, LiveInSets, MDTU);
982985
}
983986

984987
/// Check if the edge between this block and the given successor \p
@@ -1256,10 +1259,9 @@ class MachineBasicBlock
12561259
void removePredecessor(MachineBasicBlock *Pred);
12571260

12581261
// Helper method for new pass manager migration.
1259-
MachineBasicBlock *
1260-
SplitCriticalEdge(MachineBasicBlock *Succ, Pass *P,
1261-
MachineFunctionAnalysisManager *MFAM,
1262-
std::vector<SparseBitVector<>> *LiveInSets);
1262+
MachineBasicBlock *SplitCriticalEdge(
1263+
MachineBasicBlock *Succ, Pass *P, MachineFunctionAnalysisManager *MFAM,
1264+
std::vector<SparseBitVector<>> *LiveInSets, MachineDomTreeUpdater *MDTU);
12631265
};
12641266

12651267
raw_ostream& operator<<(raw_ostream &OS, const MachineBasicBlock &MBB);
@@ -1341,6 +1343,12 @@ inline auto successors(const MachineBasicBlock *BB) { return BB->successors(); }
13411343
inline auto predecessors(const MachineBasicBlock *BB) {
13421344
return BB->predecessors();
13431345
}
1346+
inline auto succ_size(const MachineBasicBlock *BB) { return BB->succ_size(); }
1347+
inline auto pred_size(const MachineBasicBlock *BB) { return BB->pred_size(); }
1348+
inline auto succ_begin(const MachineBasicBlock *BB) { return BB->succ_begin(); }
1349+
inline auto pred_begin(const MachineBasicBlock *BB) { return BB->pred_begin(); }
1350+
inline auto succ_end(const MachineBasicBlock *BB) { return BB->succ_end(); }
1351+
inline auto pred_end(const MachineBasicBlock *BB) { return BB->pred_end(); }
13441352

13451353
/// MachineInstrSpan provides an interface to get an iteration range
13461354
/// containing the instruction it was initialized with, along with all

0 commit comments

Comments
 (0)