@@ -420,11 +420,13 @@ class BasicBlockCloner : public SILClonerWithScopes<BasicBlockCloner> {
420
420
" times during SESE cloning." );
421
421
}
422
422
423
- // / Clone the body of `loop` starting from `startBlock` and nest the cloned
424
- // / fragment into the parent loop. If `startBlock` is the same as the header
425
- // / of `loop`, we clone the entire loop including the back edge. Otherwise,
426
- // / we clone one iteration of the loop body without the back edge.
427
- SILLoop *cloneLoop (SILLoopInfo *LI, SILLoop *loop, SILBasicBlock *startBlock) {
423
+ // / Utility to unroll one iteration of the loop or to clone the entire loop.
424
+ // / - If `startBlock` is the same as the header of `loop`, we clone the
425
+ // / entire loop including the back edge.
426
+ // / - Otherwise, we unroll one iteration of the loop body starting from
427
+ // / `startBlock' to the latch.
428
+ // / The unrolled or cloned version is nested into the parent loop.
429
+ SILLoop *cloneOrUnrollLoop (SILLoopInfo *LI, SILLoop *loop, SILBasicBlock *startBlock) {
428
430
llvm::DenseMap<SILLoop*, SILLoop*> loopClones;
429
431
// This is for convenience as top-level loops have nullptr for parent loop.
430
432
loopClones[nullptr ] = nullptr ;
@@ -514,24 +516,48 @@ class BasicBlockCloner : public SILClonerWithScopes<BasicBlockCloner> {
514
516
515
517
// A helper class to transform a loop to have a single exit from the header.
516
518
class SingleExitLoopTransformer {
517
- public:
518
- SingleExitLoopTransformer (GraphFunctionDeviceInfo *deviceInfo,
519
- SILLoopInfo *LI, DominanceInfo *DI, SILLoop *loop,
520
- PostDominanceInfo *PDI)
521
- : deviceInfo(deviceInfo), DI(DI), PDI(PDI), LI(LI), loop(loop),
522
- header (loop->getHeader ()), preheader(loop->getLoopPreheader ()),
523
- latch(loop->getLoopLatch ()), currentFn(header->getParent ()),
524
- oldHeaderNumArgs(header->getNumArguments ()), hasUndefsAtPreheader(false ) {
525
- assert (preheader && " Canonicalization should have given us one preheader" );
526
- assert (latch && " Canonicalization should have given us one latch block" );
527
- initialize ();
519
+ public:
520
+ // Convert the given loop into a SESE form. Returns false if the loop was
521
+ // already in SESE form. Otherwise, returns true.
522
+ static bool doIt (GraphFunctionDeviceInfo *deviceInfo, SILLoopInfo *LI,
523
+ DominanceInfo *DI, SILLoop *loop, PostDominanceInfo *PDI) {
524
+ SingleExitLoopTransformer transformer (deviceInfo, LI, DI, loop, PDI);
525
+ bool loopChanged = transformer.transform ();
526
+ if (loopChanged) {
527
+ // Recalculate dominator information as it is stale now.
528
+ DI->recalculate (*transformer.currentFn );
529
+ PDI->recalculate (*transformer.currentFn );
530
+ }
531
+
532
+ #ifndef NDEBUG
533
+ {
534
+ // Verify that the loop is OK after all the transformations.
535
+ llvm::DenseSet<const SILLoop *> nestedLoops;
536
+ loop->verifyLoopNest (&nestedLoops);
537
+ }
538
+ #endif
539
+ return loopChanged;
540
+ }
541
+
542
+ private:
543
+ SingleExitLoopTransformer (GraphFunctionDeviceInfo *deviceInfo,
544
+ SILLoopInfo *LI, DominanceInfo *DI, SILLoop *loop,
545
+ PostDominanceInfo *PDI)
546
+ : deviceInfo(deviceInfo), DI(DI), PDI(PDI), LI(LI), loop(loop),
547
+ header (loop->getHeader ()), preheader(loop->getLoopPreheader ()),
548
+ latch(loop->getLoopLatch ()), currentFn(header->getParent ()),
549
+ oldHeaderNumArgs(header->getNumArguments ()),
550
+ hasUndefsAtPreheader(false ) {
551
+ assert (preheader &&
552
+ " Canonicalization should have given us one preheader" );
553
+ assert (latch && " Canonicalization should have given us one latch block" );
554
+ initialize ();
528
555
}
529
556
530
557
// / Transforms the loop to ensure it has a single exit from the header.
531
558
// / Returns true if the CFG was changed.
532
559
bool transform ();
533
560
534
- private:
535
561
// Helper functions
536
562
537
563
void initialize ();
@@ -711,6 +737,24 @@ void SingleExitLoopTransformer::ensureSingleExitBlock() {
711
737
<< SILPrintContext (llvm::dbgs ()).getID (nearestCommonPD)
712
738
<< " \n " );
713
739
740
+ // Compute the set of preheaders of loops that are unrelated to our loop w.r.t
741
+ // nesting. This will be used when needing to identify cases where a loop
742
+ // from outside is moved into the current loop. e.g.,
743
+ // while ... {
744
+ // if ... {
745
+ // for(...) {...} // This should be nested into the while loop.
746
+ // break;
747
+ // }
748
+ // }
749
+ // The unrelated loops are those that are not contained within each other.
750
+ SmallPtrSet<SILBasicBlock *, 32 > unrelatedPreheaders;
751
+ for (auto *otherLoop : *LI) {
752
+ if (!otherLoop->contains (loop) && !loop->contains (otherLoop)) {
753
+ unrelatedPreheaders.insert (otherLoop->getLoopPreheader ());
754
+ }
755
+ }
756
+
757
+
714
758
// Collect all the blocks from each exiting block up to nearest common PD.
715
759
SmallPtrSet<SILBasicBlock *, 32 > blocksToBeMoved;
716
760
for (SILBasicBlock *exitBlock : exitBlockList) {
@@ -735,6 +779,19 @@ void SingleExitLoopTransformer::ensureSingleExitBlock() {
735
779
continue ;
736
780
}
737
781
782
+ // Check if `succ` is a preheader of another loop.
783
+ SILLoop *succBlockLoop = nullptr ;
784
+ if (unrelatedPreheaders.count (succ) > 0 ) {
785
+ // We are about a move a loop from outside. Perform canonicalization
786
+ // of that loop first.
787
+ SILBasicBlock *unrelatedHeader = succ->getSingleSuccessorBlock ();
788
+ assert (unrelatedHeader &&
789
+ " There should be a single successor for a preheader." );
790
+ succBlockLoop = LI->getLoopFor (unrelatedHeader);
791
+ SingleExitLoopTransformer::doIt (deviceInfo, LI, DI, succBlockLoop,
792
+ PDI);
793
+ }
794
+
738
795
if (DI->properlyDominates (header, succ)) {
739
796
worklist.insert (succ);
740
797
continue ;
@@ -752,6 +809,24 @@ void SingleExitLoopTransformer::ensureSingleExitBlock() {
752
809
753
810
// Clone the block and rewire the edge.
754
811
SILBasicBlock *clonedSucc = cloner.initAndCloneBlock (succ);
812
+ // If `succ` is a preheader of an unrelated loop, we will have to clone
813
+ // the entire loop now so that we can also incrementally update LoopInfo.
814
+ if (succBlockLoop) {
815
+ SILLoop *clonedLoop = cloner.cloneOrUnrollLoop (
816
+ LI, succBlockLoop, succBlockLoop->getHeader ());
817
+ changeBranchTarget (clonedSucc->getTerminator (), 0 ,
818
+ clonedLoop->getHeader (), /* preserveArgs*/ true );
819
+ // Note that all the nodes of `clonedLoop` should be moved into the
820
+ // current loop. We do that here itself as an optimization and also
821
+ // because the dominator and post-dominator information for the new
822
+ // blocks in `clonedLoop` are stale and cannot be relied upon.
823
+ for (SILBasicBlock *bb : clonedLoop->getBlocks ()) {
824
+ blocksToBeMoved.insert (bb);
825
+ }
826
+ // Add the header to worklist for processing the exit edge.
827
+ // (Other successor edges are already processed above.)
828
+ worklist.insert (clonedLoop->getHeader ());
829
+ }
755
830
changeBranchTarget (current->getTerminator (), edgeIdx, clonedSucc,
756
831
/* preserveArgs*/ true );
757
832
worklist.insert (clonedSucc);
@@ -771,24 +846,45 @@ void SingleExitLoopTransformer::ensureSingleExitBlock() {
771
846
772
847
// Update loop info if this belongs to a parent loop.
773
848
SILLoop *outsideBlockLoop = LI->getLoopFor (outsideBlock);
774
- if (outsideBlockLoop != nullptr ) {
775
- // FIXME: We don't deal with cases where the nodes being moved in
776
- // belong to another loop yet. e.g.,
849
+ if (outsideBlockLoop == nullptr ) {
850
+ // outsideBlock is not part of any other loop. Simply add it to our loop.
851
+ loop->addBasicBlockToLoop (outsideBlock, LI->getBase ());
852
+ } else {
853
+ // We deal with the case where the nodes being moved in
854
+ // belong to another loop. e.g.,
777
855
// while ... {
778
856
// if ... {
779
857
// for(...) {...}
780
858
// break;
781
859
// }
782
860
// }
783
- // Check that `loop` is nested within `reachableLoop`.
784
- assert (outsideBlockLoop->contains (loop) &&
785
- " Nodes being moved belong to a non-nested loop." );
786
- // Move the node into our loop.
787
- outsideBlockLoop->removeBlockFromLoop (outsideBlock);
788
- LI->changeLoopFor (outsideBlock, nullptr );
861
+ if (outsideBlockLoop->contains (loop)) {
862
+ // If our `loop` is nested within `outsideBlockLoop`. Move the node
863
+ // from `outsideBlockLoop` into our `loop`.
864
+ outsideBlockLoop->removeBlockFromLoop (outsideBlock);
865
+ LI->changeLoopFor (outsideBlock, nullptr );
866
+ loop->addBasicBlockToLoop (outsideBlock, LI->getBase ());
867
+ } else {
868
+ // We should only nest `outsideBlockLoop` into our `loop` when we
869
+ // process the very first node of the `outsideBlockLoop`. Check that we
870
+ // have not already nested the `outsideBlockLoop` into our `loop`.
871
+ if (!loop->contains (outsideBlockLoop)) {
872
+ // Not yet nested, adjust the LoopInfo w.r.t nesting.
873
+ if (outsideBlockLoop->getParentLoop () == nullptr ) {
874
+ // Remove from top-level loops as we are nesting it in `loop`.
875
+ LI->removeLoop (llvm::find (*LI, outsideBlockLoop));
876
+ }
877
+ loop->addChildLoop (outsideBlockLoop);
878
+ }
879
+ // Add the block to this loop and all its parents.
880
+ auto *L = loop;
881
+ while (L) {
882
+ L->addBlockEntry (outsideBlock);
883
+ L = L->getParentLoop ();
884
+ }
885
+ }
789
886
// top-level loop is already correct.
790
887
}
791
- loop->addBasicBlockToLoop (outsideBlock, LI->getBase ());
792
888
}
793
889
if (cloner.hasCloned ()) {
794
890
// TODO(https://bugs.swift.org/browse/SR-8336): the transformations here are
@@ -1283,13 +1379,8 @@ void SESERegionBuilder::ensureSingleExitFromLoops() {
1283
1379
}
1284
1380
continue ;
1285
1381
}
1286
- SingleExitLoopTransformer transformer (&deviceInfo, &LI, &DI, loop, &PDI);
1287
- bool loopChanged = transformer.transform ();
1288
- if (loopChanged) {
1289
- // Recalculate dominator information as it is stale now.
1290
- DI.recalculate (*F);
1291
- PDI.recalculate (*F);
1292
- }
1382
+ bool loopChanged =
1383
+ SingleExitLoopTransformer::doIt (&deviceInfo, &LI, &DI, loop, &PDI);
1293
1384
changed |= loopChanged;
1294
1385
}
1295
1386
if (changed) {
@@ -1414,7 +1505,7 @@ void SingleExitLoopTransformer::unrollLoopBodyOnce() {
1414
1505
}
1415
1506
1416
1507
// Clone everything starting from the old header.
1417
- cloner.cloneLoop (LI, loop, header);
1508
+ cloner.cloneOrUnrollLoop (LI, loop, header);
1418
1509
1419
1510
// Get the clone for old header.
1420
1511
SILBasicBlock *clonedOldHeader = cloner.remapBasicBlock (header);
0 commit comments