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 @@ -796,6 +796,13 @@ 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()); + if (!ExitL || ExitL->contains(OuterL)) + OuterL = ExitL; + } if (SE) { if (OuterL) @@ -821,10 +828,6 @@ // and don't disrupt the earlier indices. for (unsigned Index : reverse(ExitCaseIndices)) { auto CaseI = SI.case_begin() + Index; - // Compute the outer loop from this exit. - Loop *ExitL = LI.getLoopFor(CaseI->getCaseSuccessor()); - if (!ExitL || ExitL->contains(OuterL)) - OuterL = ExitL; // Save the value of this case. auto W = SIW.getSuccessorWeight(CaseI->getSuccessorIndex()); ExitCases.emplace_back(CaseI->getCaseValue(), CaseI->getCaseSuccessor(), W); diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/update-scev-2.ll b/llvm/test/Transforms/SimpleLoopUnswitch/update-scev-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SimpleLoopUnswitch/update-scev-2.ll @@ -0,0 +1,87 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +; RUN: opt < %s -passes='print,simple-loop-unswitch,print' -disable-output 2>&1 | FileCheck -check-prefix CHECK-SCEV %s +; RUN: opt < %s -passes='function(loop-deletion,simple-loop-unswitch),verify' -S | FileCheck -check-prefix CHECK-IR %s + +; These tests used to crash in debug builds: +; +; opt: ../lib/Analysis/ScalarEvolution.cpp:8569: const llvm::SCEV* llvm::ScalarEvolution::BackedgeTakenInfo::getExact(const llvm::Loop*, llvm::ScalarEvolution*, llvm::SmallVector*) const: Assertion `SE->DT.dominates(ENT.ExitingBlock, Latch) && "We should only have known counts for exiting blocks that dominate " "latch!"' failed. +; Stack dump: +; 0. Program arguments: /bin/opt -passes=function(loop-deletion,simple-loop-unswitch),verify -o - test.ll -S +; #0 0x00000000035912c8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/bin/opt+0x35912c8) +; #1 0x000000000358ebcc SignalHandler(int) Signals.cpp:0:0 +; #2 0x00007f546e44d630 __restore_rt sigaction.c:0:0 +; #3 0x00007f546bdaa387 raise (/lib64/libc.so.6+0x36387) +; #4 0x00007f546bdaba78 abort (/lib64/libc.so.6+0x37a78) +; #5 0x00007f546bda31a6 __assert_fail_base (/lib64/libc.so.6+0x2f1a6) +; #6 0x00007f546bda3252 (/lib64/libc.so.6+0x2f252) +; #7 0x000000000256b842 llvm::ScalarEvolution::BackedgeTakenInfo::getExact(...) const (.part.0) ScalarEvolution.cpp:0:0 +; #8 0x0000000002594d6e llvm::ScalarEvolution::verify() const (/bin/opt+0x2594d6e) +; +; Verify that we no longer hit that assert, while we expect to have forgotten SCEV for the outer loop. +; Also added checks to show and verify the IR transformation. + + +; Before the unswitch: +; +; CHECK-SCEV: Classifying expressions for: @f4 +; CHECK-SCEV-NEXT: %j.0 = phi i16 [ 0, %entry ], [ %0, %sw.bb2 ] +; CHECK-SCEV-NEXT: --> {0,+,1}<%lbl1> U: [0,3) S: [0,3) Exits: 2 LoopDispositions: { %lbl1: Computable, %lbl2: Invariant } +; CHECK-SCEV-NEXT: %0 = add i16 %j.0, 1 +; CHECK-SCEV-NEXT: --> {1,+,1}<%lbl1> U: [1,4) S: [1,4) Exits: 3 LoopDispositions: { %lbl1: Computable, %lbl2: Invariant } +; CHECK-SCEV-DAG: Loop %lbl2: Unpredictable backedge-taken count. +; CHECK-SCEV-DAG: Loop %lbl1: backedge-taken count is 2 +; +; After the unswitch: +; +; CHECK-SCEV: Classifying expressions for: @f4 +; CHECK-SCEV-NEXT: %j.0 = phi i16 [ 0, %entry ], [ %0, %sw.bb2 ] +; CHECK-SCEV-NEXT: --> {0,+,1}<%lbl1> U: [0,-32768) S: [0,-32768) Exits: <> LoopDispositions: { %lbl1: Computable } +; CHECK-SCEV-NEXT: %0 = add i16 %j.0, 1 +; CHECK-SCEV-NEXT: --> {1,+,1}<%lbl1> U: [1,-32768) S: [1,-32768) Exits: <> LoopDispositions: { %lbl1: Computable } +; CHECK-SCEV-DAG: Loop %lbl1: Unpredictable backedge-taken count. +; CHECK-SCEV-DAG: Loop %lbl2: Unpredictable backedge-taken count. + + +define i16 @f4() { +; CHECK-IR-LABEL: define i16 @f4() { +; CHECK-IR-NEXT: entry: +; CHECK-IR-NEXT: br label [[LBL1:%.*]] +; CHECK-IR: lbl1: +; CHECK-IR-NEXT: [[J_0:%.*]] = phi i16 [ 0, [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[SW_BB2:%.*]] ] +; CHECK-IR-NEXT: switch i16 [[J_0]], label [[LBL1_SPLIT:%.*]] [ +; CHECK-IR-NEXT: i16 0, label [[SW_BB2]] +; CHECK-IR-NEXT: i16 1, label [[SW_BB2]] +; CHECK-IR-NEXT: i16 2, label [[LBL3:%.*]] +; CHECK-IR-NEXT: ] +; CHECK-IR: lbl1.split: +; CHECK-IR-NEXT: br label [[LBL2:%.*]] +; CHECK-IR: lbl2: +; CHECK-IR-NEXT: br label [[LBL2]] +; CHECK-IR: sw.bb2: +; CHECK-IR-NEXT: [[TMP0]] = add i16 [[J_0]], 1 +; CHECK-IR-NEXT: br label [[LBL1]] +; CHECK-IR: lbl3: +; CHECK-IR-NEXT: ret i16 0 +; +entry: + br label %lbl1 + +lbl1: ; preds = %sw.bb2, %entry + %j.0 = phi i16 [ 0, %entry ], [ %0, %sw.bb2 ] + br label %lbl2 + +lbl2: ; preds = %lbl2, %lbl1 + switch i16 %j.0, label %lbl2 [ + i16 0, label %sw.bb2 + i16 1, label %sw.bb2 + i16 2, label %lbl3 + ] + +sw.bb2: ; preds = %lbl2, %lbl2 + %0 = add i16 %j.0, 1 + br label %lbl1 + +lbl3: ; preds = %lbl2 + ret i16 0 +} +