Issue 89365
Summary verify-scev fails with "Trip Count for Loop ... Changed!"
Labels new issue
Assignees
Reporter bjope
    Given this input
```
define void @foo() {
entry:
  br label %for.outer

for.outer.again:
  %phi3.lcssa = phi i16 [ %phi3, %for.cond3 ]
  br label %for.outer

for.outer:
  %.pre = phi i16 [ 0, %entry ], [ %phi3.lcssa, %for.outer.again ]
  %step.outer = add i16 %.pre, 2
 %cmp0 = icmp ult i16 %step.outer, 17
  br i1 %cmp0, label %for.cond1, label %end

for.cond1:
  %phi1 = phi i16 [ %step.1, %for.body1 ], [ %step.outer, %for.outer ]
  %step.1 = add i16 %phi1, 1
  %cmp1 = icmp ne i16 %step.1, 8
  br i1 %cmp1, label %for.body1, label %for.cond2.preheader

for.body1:
  br label %for.cond1

for.cond2.preheader:
  %phi1.lcssa = phi i16 [ %phi1, %for.cond1 ]
  %cmpnew = icmp uge i16 %phi1.lcssa, 8
  br i1 %cmpnew, label %for.cond2, label %end

for.cond2:
  %phi2 = phi i16 [ %step.2, %for.body2 ], [ %phi1.lcssa, %for.cond2.preheader ]
  %step.2 = add i16 %phi2, -1
  %cmp2 = icmp ugt i16 %phi2, 8
  br i1 %cmp2, label %for.body2, label %for.cond3.preheader

for.body2:
  br label %for.cond2

for.cond3.preheader:
  %step.2.lcssa = phi i16 [ %step.2, %for.cond2 ]
  br label %for.cond3

for.cond3:
  %phi3 = phi i16 [ %step.3, %for.body3 ], [ %step.2.lcssa, %for.cond3.preheader ]
 %step.3 = add i16 %phi3, 1
  %cmp3 = icmp ne i16 %phi3, 20
  br i1 %cmp3, label %for.body3, label %for.outer.again

for.body3:
  br label %for.cond3

end:
  ret void
}

```
when running `opt -passes="print<scalar-evolution>,no-op-loop,print<scalar-evolution>,verify<scalar-evolution>" -o /dev/null` the first print says:
```
Classifying expressions for: @foo
  %phi3.lcssa = phi i16 [ %phi3, %for.cond3 ]
  -->  {{{(1 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2>,+,1}<nw><%for.cond3> U: full-set S: full-set  -->  20 U: [20,21) S: [20,21)                Exits: 20 LoopDispositions: { %for.outer: Variant, %for.cond1: Variant, %for.cond2: Variant, %for.cond3: Computable }
  %.pre = phi i16 [ 0, %entry ], [ %phi3.lcssa, %for.outer.again ]
  -->  %.pre U: full-set S: full-set            Exits: <<Unknown>>              LoopDispositions: { %for.outer: Variant, %for.cond1: Invariant, %for.cond2: Invariant, %for.cond3: Invariant }
  %step.outer = add i16 %.pre, 2
  -->  (2 + %.pre) U: full-set S: full-set              Exits: <<Unknown>> LoopDispositions: { %for.outer: Variant, %for.cond1: Invariant, %for.cond2: Invariant, %for.cond3: Invariant }
  %phi1 = phi i16 [ %step.1, %for.body1 ], [ %step.outer, %for.outer ]
  -->  {(2 + %.pre),+,1}<%for.cond1> U: full-set S: full-set            Exits: 7                LoopDispositions: { %for.cond1: Computable, %for.outer: Variant }
  %step.1 = add i16 %phi1, 1
  -->  {(3 + %.pre),+,1}<%for.cond1> U: full-set S: full-set Exits: 8                LoopDispositions: { %for.cond1: Computable, %for.outer: Variant }
  %phi1.lcssa = phi i16 [ %phi1, %for.cond1 ]
 -->  {(2 + %.pre),+,1}<%for.cond1> U: full-set S: full-set  -->  7 U: [7,8) S: [7,8)          Exits: 7                LoopDispositions: { %for.outer: Variant, %for.cond1: Computable, %for.cond2: Invariant, %for.cond3: Invariant }
  %phi2 = phi i16 [ %step.2, %for.body2 ], [ %phi1.lcssa, %for.cond2.preheader ]
  -->  {{(2 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2> U: full-set S: full-set  --> {7,+,-1}<nw><%for.cond2> U: [7,8) S: [7,8)            Exits: 7 LoopDispositions: { %for.cond2: Computable, %for.outer: Variant }
 %step.2 = add i16 %phi2, -1
  -->  {{(1 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2> U: full-set S: full-set  --> {6,+,-1}<nw><%for.cond2> U: [6,7) S: [6,7)            Exits: 6 LoopDispositions: { %for.cond2: Computable, %for.outer: Variant }
 %step.2.lcssa = phi i16 [ %step.2, %for.cond2 ]
  -->  {{(1 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2> U: full-set S: full-set  -->  6 U: [6,7) S: [6,7)           Exits: 6                LoopDispositions: { %for.outer: Variant, %for.cond1: Variant, %for.cond2: Computable, %for.cond3: Invariant }
  %phi3 = phi i16 [ %step.3, %for.body3 ], [ %step.2.lcssa, %for.cond3.preheader ]
  -->  {{{(1 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2>,+,1}<nw><%for.cond3> U: full-set S: full-set  -->  {6,+,1}<nw><%for.cond3> U: [6,21) S: [6,21) Exits: 20               LoopDispositions: { %for.cond3: Computable, %for.outer: Variant }
  %step.3 = add i16 %phi3, 1
  -->  {{{(2 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2>,+,1}<nw><%for.cond3> U: full-set S: full-set  -->  {7,+,1}<nw><%for.cond3> U: [7,22) S: [7,22) Exits: 21               LoopDispositions: { %for.cond3: Computable, %for.outer: Variant }
Determining loop execution counts for: @foo
Loop %for.cond1: backedge-taken count is (5 + (-1 * %.pre))
Loop %for.cond1: constant max backedge-taken count is i16 -1
Loop %for.cond1: symbolic max backedge-taken count is (5 + (-1 * %.pre))
Loop %for.cond1: Trip multiple is 1
Loop %for.cond2: backedge-taken count is i16 0
Loop %for.cond2: constant max backedge-taken count is i16 0
Loop %for.cond2: symbolic max backedge-taken count is i16 0
Loop %for.cond2: Trip multiple is 1
Loop %for.cond3: backedge-taken count is i16 14
Loop %for.cond3: constant max backedge-taken count is i16 14
Loop %for.cond3: symbolic max backedge-taken count is i16 14
Loop %for.cond3: Trip multiple is 15
Loop %for.outer: <multiple exits> Unpredictable backedge-taken count.
  exit count for for.outer: ***COULDNOTCOMPUTE***
  exit count for for.cond2.preheader: i1 false
Loop %for.outer: constant max backedge-taken count is i1 false
Loop %for.outer: symbolic max backedge-taken count is i1 false
  symbolic max exit count for for.outer: ***COULDNOTCOMPUTE***
  symbolic max exit count for for.cond2.preheader: i1 false

```
and then the second one says:
```
Classifying expressions for: @foo
  %phi3.lcssa = phi i16 [ %phi3, %for.cond3 ]
 -->  {{{(1 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2>,+,1}<nw><%for.cond3> U: full-set S: full-set  -->  19 U: [19,20) S: [19,20)                Exits: 19 LoopDispositions: { %for.outer: Variant, %for.cond1: Variant, %for.cond2: Variant, %for.cond3: Computable }
  %.pre = phi i16 [ 0, %entry ], [ %phi3.lcssa, %for.outer.again ]
  -->  %.pre U: full-set S: full-set            Exits: <<Unknown>>              LoopDispositions: { %for.outer: Variant, %for.cond1: Invariant, %for.cond2: Invariant, %for.cond3: Invariant }
  %step.outer = add i16 %.pre, 2
  -->  (2 + %.pre) U: full-set S: full-set              Exits: <<Unknown>> LoopDispositions: { %for.outer: Variant, %for.cond1: Invariant, %for.cond2: Invariant, %for.cond3: Invariant }
  %phi1 = phi i16 [ %step.1, %for.body1 ], [ %step.outer, %for.cond1.preheader ]
  -->  {(2 + %.pre),+,1}<%for.cond1> U: full-set S: full-set            Exits: 7 LoopDispositions: { %for.cond1: Computable, %for.outer: Variant }
 %step.1 = add i16 %phi1, 1
  -->  {(3 + %.pre),+,1}<%for.cond1> U: full-set S: full-set            Exits: 8                LoopDispositions: { %for.cond1: Computable, %for.outer: Variant }
  %phi1.lcssa = phi i16 [ %phi1, %for.cond1 ]
  -->  {(2 + %.pre),+,1}<%for.cond1> U: full-set S: full-set  -->  7 U: [7,8) S: [7,8)          Exits: 7 LoopDispositions: { %for.outer: Variant, %for.cond1: Computable, %for.cond2: Invariant, %for.cond3: Invariant }
  %phi2 = phi i16 [ %step.2, %for.body2 ], [ %phi1.lcssa, %for.cond2.preheader1 ]
  -->  {{(2 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2> U: full-set S: full-set  --> {7,+,-1}<nw><%for.cond2> U: [7,8) S: [7,8)            Exits: 7 LoopDispositions: { %for.cond2: Computable, %for.outer: Variant }
 %step.2 = add i16 %phi2, -1
  -->  {{(1 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2> U: full-set S: full-set  --> {6,+,-1}<nw><%for.cond2> U: [6,7) S: [6,7)            Exits: 6 LoopDispositions: { %for.cond2: Computable, %for.outer: Variant }
 %step.2.lcssa = phi i16 [ %step.2, %for.cond2 ]
  -->  {{(1 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2> U: full-set S: full-set  -->  6 U: [6,7) S: [6,7)           Exits: 6                LoopDispositions: { %for.outer: Variant, %for.cond1: Variant, %for.cond2: Computable, %for.cond3: Invariant }
  %phi3 = phi i16 [ %step.3, %for.body3 ], [ %step.2.lcssa, %for.cond3.preheader ]
  -->  {{{(1 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2>,+,1}<nw><%for.cond3> U: full-set S: full-set  -->  {6,+,1}<nw><%for.cond3> U: [6,20) S: [6,20) Exits: 19               LoopDispositions: { %for.cond3: Computable, %for.outer: Variant }
  %step.3 = add i16 %phi3, 1
  -->  {{{(2 + %.pre),+,1}<%for.cond1>,+,-1}<nw><%for.cond2>,+,1}<nw><%for.cond3> U: full-set S: full-set  -->  {7,+,1}<nw><%for.cond3> U: [7,21) S: [7,21) Exits: 20               LoopDispositions: { %for.cond3: Computable, %for.outer: Variant }
Determining loop execution counts for: @foo
Loop %for.cond1: backedge-taken count is (5 + (-1 * %.pre))
Loop %for.cond1: constant max backedge-taken count is i16 -1
Loop %for.cond1: symbolic max backedge-taken count is (5 + (-1 * %.pre))
Loop %for.cond1: Trip multiple is 1
Loop %for.cond2: backedge-taken count is i16 0
Loop %for.cond2: constant max backedge-taken count is i16 0
Loop %for.cond2: symbolic max backedge-taken count is i16 0
Loop %for.cond2: Trip multiple is 1
Loop %for.cond3: backedge-taken count is i16 13
Loop %for.cond3: constant max backedge-taken count is i16 13
Loop %for.cond3: symbolic max backedge-taken count is i16 13
Loop %for.cond3: Trip multiple is 14
Loop %for.outer: <multiple exits> Unpredictable backedge-taken count.
  exit count for for.outer: ***COULDNOTCOMPUTE***
  exit count for for.cond2.preheader: i1 false
Loop %for.outer: constant max backedge-taken count is i1 false
Loop %for.outer: symbolic max backedge-taken count is i1 false
  symbolic max exit count for for.outer: ***COULDNOTCOMPUTE***
  symbolic max exit count for for.cond2.preheader: i1 false

```
So we can for example see that Exsits has changed for `%phi3` and  `%step.3`, and the max backedge-taken counts for %for.cond3 goes from 14 to 13.

Then the verification complains:
```
Trip Count for Loop at depth 2 containing: %for.cond3<header><exiting>,%for.body3<latch>
 Changed!
Old: 13
New: 14
Delta: -1
```

Some things that I've noticed:
1) no-op-loop will result in running LoopSimplify, which will add a pre-header for the for.cond1 loop. This should not really change anything from the perspective of SCEV, but I figure we do forget some SCEV values/dispositions in the process.

2) If modifying LoopSimplify like this
```
@@ -881,6 +929,17 @@ PreservedAnalyses LoopSimplifyPass::run(Function &F,
     MSSAU = std::make_unique<MemorySSAUpdater>(MSSA);
   }
 
+ SE->print(dbgs());
+  SE->forgetAllLoops();
+  SE->print(dbgs());
+ SE->verify();
 
   // Note that we don't preserve LCSSA in the new PM, if you need it run LCSSA
   // after simplifying the loops. MemorySSA is preserved if it exists.
  for (auto *L : *LI)
    Changed |=
 simplifyLoop(L, DT, LI, SE, AC, MSSAU.get(), /*PreserveLCSSA*/ false);
```
we can see that doing forgetAllLoops() and then re-calculating SCEV gives the same behavior. So this is not really related to LoopSimplify or the pass manager. But it seems a bit weird that the SCEV result changes after doing forgetAllLoops!?!?

3) When doing the second `print<scalar-evolution>` the function ScalarEvolution::howManyGreaterThans is involved. But it isn't involved the first time.

4) ( @fhahn : Bi-secting pointed at this starting to happen after commit 7019624ee124 "[SCEV] Strengthen nowrap flags via ranges for ARs on construction.". But maybe that is a co-incidence. )
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to