@@ -725,6 +725,24 @@ void SingleExitLoopTransformer::ensureSingleExitBlock() {
725
725
<< SILPrintContext (llvm::dbgs ()).getID (nearestCommonPD)
726
726
<< " \n " );
727
727
728
+ // Compute the set of preheaders of loops that are unrelated to our loop w.r.t
729
+ // nesting. This will be used when needing to identify cases where a loop
730
+ // from outside is moved into the current loop. e.g.,
731
+ // while ... {
732
+ // if ... {
733
+ // for(...) {...} // This should be nested into the while loop.
734
+ // break;
735
+ // }
736
+ // }
737
+ SmallPtrSet<SILBasicBlock *, 32 > unrelatedPreheaders;
738
+ for (auto *otherLoop : *LI) {
739
+ // If loop and otherLoop are not nested into either, remember the preheader.
740
+ if (!otherLoop->contains (loop) && !loop->contains (otherLoop)) {
741
+ unrelatedPreheaders.insert (otherLoop->getLoopPreheader ());
742
+ }
743
+ }
744
+
745
+
728
746
// Collect all the blocks from each exiting block up to nearest common PD.
729
747
SmallPtrSet<SILBasicBlock *, 32 > blocksToBeMoved;
730
748
for (SILBasicBlock *exitBlock : exitBlockList) {
@@ -749,38 +767,17 @@ void SingleExitLoopTransformer::ensureSingleExitBlock() {
749
767
continue ;
750
768
}
751
769
752
- // Check if this is a preheader of another loop.
770
+ // Check if `succ` is a preheader of another loop.
753
771
SILLoop *succBlockLoop = nullptr ;
754
- if (SILBasicBlock* succBlockLoopHeader = succ->getSingleSuccessorBlock ()) {
755
- succBlockLoop = LI->getLoopFor (succBlockLoopHeader);
756
- if (succBlockLoop &&
757
- LI->getLoopFor (succ) != succBlockLoop &&
758
- succBlockLoop->getHeader () == succBlockLoopHeader &&
759
- !succBlockLoop->contains (loop) &&
760
- !loop->contains (succBlockLoop)) {
761
- // `succ` is a pre-header of a loop that does not contain this loop
762
- // or contained within this loop. Before moving this loop into our
763
- // loop, we should first perform the canonicalization on that loop
764
- // first.
765
- SingleExitLoopTransformer::doIt (deviceInfo, LI, DI, succBlockLoop, PDI);
766
- // // Remove from the top-level loops before making it a child.
767
- // if (succBlockLoop->getParentLoop() == nullptr) {
768
- // LI->removeLoop(llvm::find(*LI, succBlockLoop));
769
- // }
770
- // loop->addChildLoop(succBlockLoop);
771
- // // Add the block to this loop and all its parents.
772
- // for (SILBasicBlock* bb : succBlockLoop->getBlocks()) {
773
- // auto *L = loop;
774
- // while (L) {
775
- // L->addBlockEntry(bb);
776
- // L = L->getParentLoop();
777
- // }
778
- // }
779
- // Reinitialize succ as it might have been changed by the transformer.
780
- // succ = succBlockLoop->getHeader();
781
- } else {
782
- succBlockLoop = nullptr ;
783
- }
772
+ if (unrelatedPreheaders.count (succ) > 0 ) {
773
+ // We are about a move a loop from outside. Perform canonicalization
774
+ // of that loop first.
775
+ SILBasicBlock *unrelatedHeader = succ->getSingleSuccessorBlock ();
776
+ assert (unrelatedHeader &&
777
+ " There should be a single successor for a preheader." );
778
+ succBlockLoop = LI->getLoopFor (unrelatedHeader);
779
+ SingleExitLoopTransformer::doIt (deviceInfo, LI, DI, succBlockLoop,
780
+ PDI);
784
781
}
785
782
786
783
if (DI->properlyDominates (header, succ)) {
@@ -800,16 +797,23 @@ void SingleExitLoopTransformer::ensureSingleExitBlock() {
800
797
801
798
// Clone the block and rewire the edge.
802
799
SILBasicBlock *clonedSucc = cloner.initAndCloneBlock (succ);
800
+ // If `succ` is a preheader of an unrelated loop, we will have to clone
801
+ // the entire loop now so that we can also incrementally update LoopInfo.
803
802
if (succBlockLoop) {
804
- // We will have to clone the entire loop now.
805
803
SILLoop *clonedLoop =
806
804
cloner.cloneLoop (LI, succBlockLoop, succBlockLoop->getHeader ());
807
- // clonedLoop->setParentLoop(loop->getParentLoop());
808
- if (clonedLoop->getParentLoop () == nullptr ) {
809
- LI->addTopLevelLoop (clonedLoop);
805
+ changeBranchTarget (clonedSucc->getTerminator (), 0 ,
806
+ clonedLoop->getHeader (), /* preserveArgs*/ true );
807
+ // Note that all the nodes of `clonedLoop` should be moved into the
808
+ // current loop. We do that here itself as an optimization and also
809
+ // because the dominator and post-dominator information for the new
810
+ // blocks in `clonedLoop` are stale and cannot be relied upon.
811
+ for (SILBasicBlock *bb : clonedLoop->getBlocks ()) {
812
+ blocksToBeMoved.insert (bb);
810
813
}
811
- changeBranchTarget (clonedSucc->getTerminator (), 0 , clonedLoop->getHeader (), /* preserveArgs*/ true );
812
- // succBlockLoop->addBasicBlockToLoop(clonedSucc, LI->getBase());
814
+ // Add the header to worklist for processing the exit edge.
815
+ // (Other successor edges are already processed above.)
816
+ worklist.insert (clonedLoop->getHeader ());
813
817
}
814
818
changeBranchTarget (current->getTerminator (), edgeIdx, clonedSucc,
815
819
/* preserveArgs*/ true );
@@ -833,26 +837,24 @@ void SingleExitLoopTransformer::ensureSingleExitBlock() {
833
837
if (outsideBlockLoop == nullptr ) {
834
838
loop->addBasicBlockToLoop (outsideBlock, LI->getBase ());
835
839
} else {
836
- // FIXME: We don't deal with cases where the nodes being moved in
837
- // belong to another loop yet . e.g.,
840
+ // We deal with the case where the nodes being moved in
841
+ // belong to another loop. e.g.,
838
842
// while ... {
839
843
// if ... {
840
844
// for(...) {...}
841
845
// break;
842
846
// }
843
847
// }
844
- // Check that `loop` is nested within `reachableLoop`.
845
- // assert(outsideBlockLoop->contains(loop) &&
846
- // "Nodes being moved belong to a non-nested loop.");
847
848
if (outsideBlockLoop->contains (loop)) {
848
- // `loop` is nested within `outsideBlockLoop`.
849
- // Move the node into our loop.
849
+ // `loop` is nested within `outsideBlockLoop`. Move the node from
850
+ // `outsideBlockLoop` into our ` loop` .
850
851
outsideBlockLoop->removeBlockFromLoop (outsideBlock);
851
852
LI->changeLoopFor (outsideBlock, nullptr );
852
853
loop->addBasicBlockToLoop (outsideBlock, LI->getBase ());
853
854
} else {
854
855
if (!loop->contains (outsideBlockLoop)) {
855
856
if (outsideBlockLoop->getParentLoop () == nullptr ) {
857
+ // Remove from top-level loops as we are nesting it in `loop`.
856
858
LI->removeLoop (llvm::find (*LI, outsideBlockLoop));
857
859
}
858
860
loop->addChildLoop (outsideBlockLoop);
0 commit comments