Skip to content

Commit e5755c6

Browse files
authored
Merge pull request swiftlang#33113 from atrick/silopt-critedge
SILCloner: fix critical edge handling; remove previous workarounds
2 parents 5268b02 + 1220c03 commit e5755c6

28 files changed

+859
-765
lines changed

include/swift/SIL/SILCloner.h

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
#define SWIFT_SIL_SILCLONER_H
1919

2020
#include "swift/AST/ProtocolConformance.h"
21-
#include "swift/SIL/SILOpenedArchetypesTracker.h"
21+
#include "swift/SIL/BasicBlockUtils.h"
22+
#include "swift/SIL/Dominance.h"
2223
#include "swift/SIL/SILBuilder.h"
2324
#include "swift/SIL/SILDebugScope.h"
25+
#include "swift/SIL/SILOpenedArchetypesTracker.h"
2426
#include "swift/SIL/SILVisitor.h"
2527

2628
namespace swift {
@@ -44,6 +46,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
4446
/// MARK: Context shared with CRTP extensions.
4547

4648
SILBuilder Builder;
49+
DominanceInfo *DomTree = nullptr;
4750
TypeSubstitutionMap OpenedExistentialSubs;
4851
SILOpenedArchetypesTracker OpenedArchetypesTracker;
4952

@@ -75,12 +78,15 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
7578
using SILInstructionVisitor<ImplClass>::asImpl;
7679

7780
explicit SILCloner(SILFunction &F,
78-
SILOpenedArchetypesTracker &OpenedArchetypesTracker)
79-
: Builder(F), OpenedArchetypesTracker(OpenedArchetypesTracker) {
81+
SILOpenedArchetypesTracker &OpenedArchetypesTracker,
82+
DominanceInfo *DT = nullptr)
83+
: Builder(F), DomTree(DT),
84+
OpenedArchetypesTracker(OpenedArchetypesTracker) {
8085
Builder.setOpenedArchetypesTracker(&OpenedArchetypesTracker);
8186
}
8287

83-
explicit SILCloner(SILFunction &F) : Builder(F), OpenedArchetypesTracker(&F) {
88+
explicit SILCloner(SILFunction &F, DominanceInfo *DT = nullptr)
89+
: Builder(F), DomTree(DT), OpenedArchetypesTracker(&F) {
8490
Builder.setOpenedArchetypesTracker(&OpenedArchetypesTracker);
8591
}
8692

@@ -442,8 +448,9 @@ class SILClonerWithScopes : public SILCloner<ImplClass> {
442448
public:
443449
SILClonerWithScopes(SILFunction &To,
444450
SILOpenedArchetypesTracker &OpenedArchetypesTracker,
451+
DominanceInfo *DT = nullptr,
445452
bool Disable = false)
446-
: SILCloner<ImplClass>(To, OpenedArchetypesTracker) {
453+
: SILCloner<ImplClass>(To, OpenedArchetypesTracker, DT) {
447454

448455
// We only want to do this when we generate cloned functions, not
449456
// when we inline.
@@ -694,17 +701,36 @@ void SILCloner<ImplClass>::visitBlocksDepthFirst(SILBasicBlock *startBB) {
694701
asImpl().visitInstructionsInBlock(BB);
695702

696703
unsigned dfsSuccStartIdx = dfsWorklist.size();
697-
for (auto &succ : BB->getSuccessors()) {
704+
705+
// splitEdge may rewrite BB's successors during this loop.
706+
for (unsigned succIdx = 0, numSucc = BB->getSuccessors().size();
707+
succIdx != numSucc; ++succIdx) {
708+
698709
// Only visit a successor that has not already been visited and was not
699710
// premapped by the client.
700-
if (BBMap.count(succ))
701-
continue;
702-
711+
if (BBMap.count(BB->getSuccessors()[succIdx])) {
712+
// After cloning BB, this successor may be a new CFG merge. If it is
713+
// valid to branch directly from the BB to its clone do nothing; if not,
714+
// split the edge from BB->succ and clone the new block.
715+
//
716+
// A CFG merge may require new block arguments, so check for both a
717+
// critical edge and the ability to add branch arguments (BranchInst).
718+
if (BB->getSingleSuccessorBlock()
719+
&& isa<BranchInst>(BB->getTerminator())) {
720+
continue;
721+
}
722+
// This predecessor has multiple successors, so cloning it without
723+
// cloning its successors would create a critical edge.
724+
splitEdge(BB->getTerminator(), succIdx, DomTree);
725+
assert(!BBMap.count(BB->getSuccessors()[succIdx]));
726+
}
703727
// Map the successor to a new BB. Layout the cloned blocks in the order
704728
// they are visited and cloned.
705729
lastClonedBB =
706730
getBuilder().getFunction().createBasicBlockAfter(lastClonedBB);
707731

732+
// After splitting, BB has stable successors.
733+
auto &succ = BB->getSuccessors()[succIdx];
708734
BBMap.insert(std::make_pair(succ.getBB(), lastClonedBB));
709735

710736
dfsWorklist.push_back(succ);

include/swift/SIL/TypeSubstCloner.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,9 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
144144
SILFunction &From,
145145
SubstitutionMap ApplySubs,
146146
SILOpenedArchetypesTracker &OpenedArchetypesTracker,
147+
DominanceInfo *DT = nullptr,
147148
bool Inlining = false)
148-
: SILClonerWithScopes<ImplClass>(To, OpenedArchetypesTracker, Inlining),
149+
: SILClonerWithScopes<ImplClass>(To, OpenedArchetypesTracker, DT, Inlining),
149150
SwiftMod(From.getModule().getSwiftModule()),
150151
SubsMap(ApplySubs),
151152
Original(From),

include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@ class SinkAddressProjections {
136136
/// block's branch to jump to the newly cloned block, call cloneBranchTarget
137137
/// instead.
138138
///
139-
/// After cloning, call splitCriticalEdges, then updateSSAAfterCloning. This is
140-
/// decoupled from cloning becaused some clients perform CFG edges updates after
141-
/// cloning but before splitting CFG edges.
139+
/// After cloning, call updateSSAAfterCloning. This is decoupled from cloning
140+
/// becaused some clients perform CFG edges updates after cloning but before
141+
/// splitting CFG edges.
142142
class BasicBlockCloner : public SILCloner<BasicBlockCloner> {
143143
using SuperTy = SILCloner<BasicBlockCloner>;
144144
friend class SILCloner<BasicBlockCloner>;
@@ -225,12 +225,7 @@ class BasicBlockCloner : public SILCloner<BasicBlockCloner> {
225225

226226
bool wasCloned() { return isBlockCloned(origBB); }
227227

228-
/// Call this after processing all instructions to fix the control flow
229-
/// graph. The branch cloner may have left critical edges.
230-
bool splitCriticalEdges(DominanceInfo *domInfo, SILLoopInfo *loopInfo);
231-
232-
/// Helper function to perform SSA updates after calling both
233-
/// cloneBranchTarget and splitCriticalEdges.
228+
/// Helper function to perform SSA updates after calling cloneBranchTarget.
234229
void updateSSAAfterCloning();
235230

236231
protected:

lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -430,37 +430,24 @@ namespace {
430430
/// in a set of basic blocks. Updates the dominator tree with the cloned blocks.
431431
/// However, the client needs to update the dominator of the exit blocks.
432432
///
433-
/// FIXME: SILCloner is used to cloned CFG regions by multiple clients. All
434-
/// functionality for generating valid SIL (including the DomTree) should be
435-
/// handled by the common SILCloner.
433+
/// FIXME: All functionality for generating valid SIL (including the DomTree)
434+
/// should be handled by the common SILCloner. Currently, SILCloner only updates
435+
/// the DomTree for original (non-cloned) blocks when splitting edges. The
436+
/// cloned blocks won't be mapped to dominator nodes until fixDomTree()
437+
/// runs. However, since SILCloner always handles single-entry regions,
438+
/// fixDomTree() could be part of SILCloner itself.
436439
class RegionCloner : public SILCloner<RegionCloner> {
437-
DominanceInfo &DomTree;
438440
SILBasicBlock *StartBB;
439441

440442
friend class SILInstructionVisitor<RegionCloner>;
441443
friend class SILCloner<RegionCloner>;
442444

443445
public:
444446
RegionCloner(SILBasicBlock *EntryBB, DominanceInfo &DT)
445-
: SILCloner<RegionCloner>(*EntryBB->getParent()), DomTree(DT),
446-
StartBB(EntryBB) {}
447+
: SILCloner<RegionCloner>(*EntryBB->getParent(), &DT), StartBB(EntryBB) {}
447448

448449
SILBasicBlock *cloneRegion(ArrayRef<SILBasicBlock *> exitBBs) {
449-
assert (DomTree.getNode(StartBB) != nullptr && "Can't cloned dead code");
450-
451-
// We need to split any edge from a non cond_br basic block leading to a
452-
// exit block. After cloning this edge will become critical if it came from
453-
// inside the cloned region. The SSAUpdater can't handle critical non
454-
// cond_br edges.
455-
//
456-
// FIXME: remove this in the next commit. The SILCloner will always do it.
457-
for (auto *BB : exitBBs) {
458-
SmallVector<SILBasicBlock *, 8> Preds(BB->getPredecessorBlocks());
459-
for (auto *Pred : Preds)
460-
if (!isa<CondBranchInst>(Pred->getTerminator()) &&
461-
!isa<BranchInst>(Pred->getTerminator()))
462-
splitEdgesFromTo(Pred, BB, &DomTree, nullptr);
463-
}
450+
assert(DomTree->getNode(StartBB) != nullptr && "Can't cloned dead code");
464451

465452
cloneReachableBlocks(StartBB, exitBBs);
466453

@@ -477,25 +464,25 @@ class RegionCloner : public SILCloner<RegionCloner> {
477464
void fixDomTree() {
478465
for (auto *BB : originalPreorderBlocks()) {
479466
auto *ClonedBB = getOpBasicBlock(BB);
480-
auto *OrigDomBB = DomTree.getNode(BB)->getIDom()->getBlock();
467+
auto *OrigDomBB = DomTree->getNode(BB)->getIDom()->getBlock();
481468
if (BB == StartBB) {
482469
// The cloned start node shares the same dominator as the original node.
483-
auto *ClonedNode = DomTree.addNewBlock(ClonedBB, OrigDomBB);
470+
auto *ClonedNode = DomTree->addNewBlock(ClonedBB, OrigDomBB);
484471
(void)ClonedNode;
485472
assert(ClonedNode);
486473
continue;
487474
}
488475
// Otherwise, map the dominator structure using the mapped block.
489-
DomTree.addNewBlock(ClonedBB, getOpBasicBlock(OrigDomBB));
476+
DomTree->addNewBlock(ClonedBB, getOpBasicBlock(OrigDomBB));
490477
}
491478
}
492479

493480
SILValue getMappedValue(SILValue V) {
494481
if (auto *BB = V->getParentBlock()) {
495-
if (!DomTree.dominates(StartBB, BB)) {
482+
if (!DomTree->dominates(StartBB, BB)) {
496483
// Must be a value that dominates the start basic block.
497-
assert(DomTree.dominates(BB, StartBB) &&
498-
"Must dominated the start of the cloned region");
484+
assert(DomTree->dominates(BB, StartBB)
485+
&& "Must dominated the start of the cloned region");
499486
return V;
500487
}
501488
}

lib/SILOptimizer/LoopTransforms/LoopRotate.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,10 +409,13 @@ bool swift::rotateLoop(SILLoop *loop, DominanceInfo *domInfo,
409409
header->moveAfter(latch);
410410

411411
// Merge the old latch with the old header if possible.
412-
mergeBasicBlockWithSuccessor(latch, domInfo, loopInfo);
412+
if (mergeBasicBlockWithSuccessor(latch, domInfo, loopInfo))
413+
newHeader = latch; // The old Header is gone. Latch is now the Header.
413414

414-
// Create a new preheader.
415-
splitIfCriticalEdge(preheader, newHeader, domInfo, loopInfo);
415+
// Cloning the header into the preheader created critical edges from the
416+
// preheader and original header to both the new header and loop exit.
417+
splitCriticalEdgesFrom(preheader, domInfo, loopInfo);
418+
splitCriticalEdgesFrom(newHeader, domInfo, loopInfo);
416419

417420
if (shouldVerify) {
418421
domInfo->verify();

lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ void LoopCloner::cloneLoop() {
7474
Loop->getExitBlocks(ExitBlocks);
7575

7676
// Clone the entire loop.
77-
cloneReachableBlocks(Loop->getHeader(), ExitBlocks);
77+
cloneReachableBlocks(Loop->getHeader(), ExitBlocks,
78+
/*insertAfter*/Loop->getLoopLatch());
7879
}
7980

8081
/// Determine the number of iterations the loop is at most executed. The loop
@@ -93,7 +94,7 @@ static Optional<uint64_t> getMaxLoopTripCount(SILLoop *Loop,
9394
if (!Loop->isLoopExiting(Latch))
9495
return None;
9596

96-
// Get the loop exit condition.
97+
// Get the loop exit condition.
9798
auto *CondBr = dyn_cast<CondBranchInst>(Latch->getTerminator());
9899
if (!CondBr)
99100
return None;

0 commit comments

Comments
 (0)