diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp --- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp +++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp @@ -475,10 +475,10 @@ // Return the top-most loop containing ExitBB and having ExitBB as exiting block // or the loop containing ExitBB, if there is no parent loop containing ExitBB // as exiting block. -static const Loop *getTopMostExitingLoop(const BasicBlock *ExitBB, - const LoopInfo &LI) { - const Loop *TopMost = LI.getLoopFor(ExitBB); - const Loop *Current = TopMost; +static Loop *getTopMostExitingLoop(const BasicBlock *ExitBB, + const LoopInfo &LI) { + Loop *TopMost = LI.getLoopFor(ExitBB); + Loop *Current = TopMost; while (Current) { if (Current->isLoopExiting(ExitBB)) TopMost = Current; @@ -792,14 +792,14 @@ if (DefaultExitBB) { // Check the loop containing this exit. - Loop *ExitL = LI.getLoopFor(DefaultExitBB); + Loop *ExitL = getTopMostExitingLoop(DefaultExitBB, LI); if (!ExitL || ExitL->contains(OuterL)) OuterL = ExitL; } for (unsigned Index : ExitCaseIndices) { auto CaseI = SI.case_begin() + Index; // Compute the outer loop from this exit. - Loop *ExitL = LI.getLoopFor(CaseI->getCaseSuccessor()); + Loop *ExitL = getTopMostExitingLoop(CaseI->getCaseSuccessor(), LI); if (!ExitL || ExitL->contains(OuterL)) OuterL = ExitL; } @@ -2207,7 +2207,9 @@ SmallVector ExitBlocks; L.getUniqueExitBlocks(ExitBlocks); for (auto *ExitBB : ExitBlocks) { - Loop *NewOuterExitL = LI.getLoopFor(ExitBB); + // ExitBB can be an exit block for several levels in the loop nest. Make + // sure we find the top most. + Loop *NewOuterExitL = getTopMostExitingLoop(ExitBB, LI); if (!NewOuterExitL) { // We exited the entire nest with this block, so we're done. OuterExitL = nullptr; diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/update-scev-3.ll b/llvm/test/Transforms/SimpleLoopUnswitch/update-scev-3.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SimpleLoopUnswitch/update-scev-3.ll @@ -0,0 +1,186 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +; RUN: opt < %s -passes='print,simple-loop-unswitch' -verify-scev -S | FileCheck %s + +; This is a reproducer for https://github.com/llvm/llvm-project/issues/61080 +; +; Note that the print in the beginning of the pipeline is +; needed for reproducing the original problem, as we need something that +; calculate SCEV before the loop unswitch, to verify that we invalidate SCEV +; correctly while doing the unswitch. +; +; Verify that we no longer hit that assert. Also perform checks to show the IR +; transformation that is going on in this test. + + +define i32 @foo(i1 %not) { +; CHECK-LABEL: define i32 @foo +; CHECK-SAME: (i1 [[NOT:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[FALSE:%.*]] = and i1 true, false +; CHECK-NEXT: br i1 [[NOT]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] +; CHECK: entry.split.us: +; CHECK-NEXT: br i1 [[FALSE]], label [[ENTRY_SPLIT_US_SPLIT_US:%.*]], label [[ENTRY_SPLIT_US_SPLIT:%.*]] +; CHECK: entry.split.us.split.us: +; CHECK-NEXT: br label [[FOR_COND_US_US:%.*]] +; CHECK: for.cond.us.us: +; CHECK-NEXT: br label [[FOR_COND_SPLIT_US_US_US:%.*]] +; CHECK: for.cond.split.us.us.us: +; CHECK-NEXT: br label [[FOR_COND_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US:%.*]] +; CHECK: for.cond.split.us.split.us.split.us.split.us: +; CHECK-NEXT: br label [[FOR_COND_SPLIT_US_SPLIT_US_SPLIT_US:%.*]] +; CHECK: entry.split.us.split: +; CHECK-NEXT: br label [[FOR_COND_US:%.*]] +; CHECK: for.cond.us: +; CHECK-NEXT: br label [[FOR_COND_SPLIT_US_US:%.*]] +; CHECK: for.inc11.us: +; CHECK-NEXT: br label [[FOR_COND_US]] +; CHECK: for.cond.split.us.us: +; CHECK-NEXT: br label [[FOR_COND_SPLIT_US_SPLIT_US11:%.*]] +; CHECK: for.cond5.preheader.us.us9: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT_US_US_US10:%.*]] +; CHECK: for.inc8.us.us: +; CHECK-NEXT: br i1 false, label [[FOR_INC8_FOR_COND5_PREHEADER_CRIT_EDGE_US_US:%.*]], label [[FOR_INC11_SPLIT_US_US:%.*]] +; CHECK: for.inc8.for.cond5.preheader_crit_edge.us.us: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_US_US9:%.*]] +; CHECK: for.end.us.us: +; CHECK-NEXT: br i1 false, label [[FOR_INC8_US_US:%.*]], label [[CLEANUP15_SPLIT_US_SPLIT_US:%.*]] +; CHECK: for.cond5.preheader.split.us.us.us10: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT_US_SPLIT_US7_US:%.*]] +; CHECK: for.body7.us.us4.us: +; CHECK-NEXT: br label [[HANDLER_POINTER_OVERFLOW_US_US5_US:%.*]] +; CHECK: handler.pointer_overflow.us.us5.us: +; CHECK-NEXT: br label [[CONT_US_US6_US:%.*]] +; CHECK: cont.us.us6.us: +; CHECK-NEXT: br label [[FOR_END_SPLIT_US_US_US:%.*]] +; CHECK: for.end.split.us.us.us: +; CHECK-NEXT: br label [[FOR_END_US_US:%.*]] +; CHECK: for.cond5.preheader.split.us.split.us7.us: +; CHECK-NEXT: br label [[FOR_BODY7_US_US4_US:%.*]] +; CHECK: for.inc11.split.us.us: +; CHECK-NEXT: br label [[FOR_INC11_US:%.*]] +; CHECK: for.cond.split.us.split.us11: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_US_US9]] +; CHECK: for.cond.split.us.split.us.split.us: +; CHECK-NEXT: br label [[FOR_COND_SPLIT_US_SPLIT_US:%.*]] +; CHECK: cleanup15.split.us.split.us: +; CHECK-NEXT: br label [[CLEANUP15_SPLIT_US:%.*]] +; CHECK: entry.split: +; CHECK-NEXT: br i1 [[FALSE]], label [[ENTRY_SPLIT_SPLIT_US:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]] +; CHECK: entry.split.split.us: +; CHECK-NEXT: br label [[FOR_COND_US12:%.*]] +; CHECK: for.cond.us12: +; CHECK-NEXT: br label [[FOR_COND_SPLIT_US:%.*]] +; CHECK: for.cond.split.us: +; CHECK-NEXT: br label [[FOR_COND_SPLIT_SPLIT_US_SPLIT_US:%.*]] +; CHECK: for.cond.split.split.us.split.us: +; CHECK-NEXT: br label [[FOR_COND_SPLIT_SPLIT_US:%.*]] +; CHECK: entry.split.split: +; CHECK-NEXT: br label [[FOR_COND:%.*]] +; CHECK: for.cond: +; CHECK-NEXT: br label [[FOR_COND_SPLIT:%.*]] +; CHECK: for.cond.split.us.split.us: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_US_US:%.*]] +; CHECK: for.cond5.preheader.us.us: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT_US_US_US:%.*]] +; CHECK: for.cond5.preheader.split.us.us.us: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT_US_SPLIT_US_SPLIT_US_SPLIT_US:%.*]] +; CHECK: for.cond5.preheader.split.us.split.us.split.us.split.us: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT_US_SPLIT_US_SPLIT_US:%.*]] +; CHECK: cleanup15.split.us: +; CHECK-NEXT: br label [[CLEANUP15:%.*]] +; CHECK: for.cond5.preheader.split.us.split.us.split.us: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT_US_SPLIT_US:%.*]] +; CHECK: for.cond.split: +; CHECK-NEXT: br label [[FOR_COND_SPLIT_SPLIT:%.*]] +; CHECK: for.cond.split.split.us: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_US8:%.*]] +; CHECK: for.cond5.preheader.us8: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT_US:%.*]] +; CHECK: for.cond5.preheader.split.us: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT_SPLIT_US_SPLIT_US:%.*]] +; CHECK: for.cond5.preheader.split.split.us.split.us: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT_SPLIT_US:%.*]] +; CHECK: for.cond.split.split: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER:%.*]] +; CHECK: for.cond5.preheader: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT:%.*]] +; CHECK: for.cond5.preheader.split.us.split.us: +; CHECK-NEXT: br label [[FOR_BODY7_US_US:%.*]] +; CHECK: for.body7.us.us: +; CHECK-NEXT: br label [[HANDLER_POINTER_OVERFLOW_US_US:%.*]] +; CHECK: handler.pointer_overflow.us.us: +; CHECK-NEXT: br label [[CONT_US_US:%.*]] +; CHECK: cont.us.us: +; CHECK-NEXT: br label [[CONT_FOR_BODY7_CRIT_EDGE_US_US:%.*]] +; CHECK: cont.for.body7_crit_edge.us.us: +; CHECK-NEXT: br label [[FOR_BODY7_US_US]] +; CHECK: for.cond5.preheader.split: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER_SPLIT_SPLIT:%.*]] +; CHECK: for.cond5.preheader.split.split.us: +; CHECK-NEXT: br label [[FOR_BODY7_US1:%.*]] +; CHECK: for.body7.us1: +; CHECK-NEXT: br label [[CONT_US2:%.*]] +; CHECK: cont.us2: +; CHECK-NEXT: br label [[CONT_FOR_BODY7_CRIT_EDGE_US3:%.*]] +; CHECK: cont.for.body7_crit_edge.us3: +; CHECK-NEXT: br label [[FOR_BODY7_US1]] +; CHECK: for.cond5.preheader.split.split: +; CHECK-NEXT: br label [[FOR_BODY7:%.*]] +; CHECK: for.body7: +; CHECK-NEXT: br label [[CONT:%.*]] +; CHECK: cont: +; CHECK-NEXT: br label [[FOR_END_SPLIT:%.*]] +; CHECK: for.end.split: +; CHECK-NEXT: br label [[FOR_END:%.*]] +; CHECK: for.end: +; CHECK-NEXT: br i1 false, label [[FOR_INC8:%.*]], label [[CLEANUP15_SPLIT:%.*]] +; CHECK: for.inc8: +; CHECK-NEXT: br i1 false, label [[FOR_INC8_FOR_COND5_PREHEADER_CRIT_EDGE:%.*]], label [[FOR_INC11_SPLIT:%.*]] +; CHECK: for.inc8.for.cond5.preheader_crit_edge: +; CHECK-NEXT: br label [[FOR_COND5_PREHEADER]] +; CHECK: for.inc11.split: +; CHECK-NEXT: br label [[FOR_INC11:%.*]] +; CHECK: for.inc11: +; CHECK-NEXT: br label [[FOR_COND]] +; CHECK: cleanup15.split: +; CHECK-NEXT: br label [[CLEANUP15]] +; CHECK: cleanup15: +; CHECK-NEXT: ret i32 0 +; +entry: + %false = and i1 1, 0 + br label %for.cond + +for.cond: ; preds = %for.inc11, %entry + br label %for.cond5.preheader + +for.cond5.preheader: ; preds = %for.inc8.for.cond5.preheader_crit_edge, %for.cond + br label %for.body7 + +for.body7: ; preds = %cont.for.body7_crit_edge, %for.cond5.preheader + br i1 %not, label %handler.pointer_overflow, label %cont + +handler.pointer_overflow: ; preds = %for.body7 + br label %cont + +cont: ; preds = %handler.pointer_overflow, %for.body7 + br i1 %false, label %cont.for.body7_crit_edge, label %for.end + +cont.for.body7_crit_edge: ; preds = %cont + br label %for.body7 + +for.end: ; preds = %cont + br i1 %false, label %for.inc8, label %cleanup15 + +for.inc8: ; preds = %for.end + br i1 %false, label %for.inc8.for.cond5.preheader_crit_edge, label %for.inc11 + +for.inc8.for.cond5.preheader_crit_edge: ; preds = %for.inc8 + br label %for.cond5.preheader + +for.inc11: ; preds = %for.inc8 + br label %for.cond + +cleanup15: ; preds = %for.end + ret i32 0 +}