[llvm] r318819 - [SCEV] Strengthen variance condition in calculateLoopDisposition

Max Kazantsev via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 21 22:21:39 PST 2017


Author: mkazantsev
Date: Tue Nov 21 22:21:39 2017
New Revision: 318819

URL: http://llvm.org/viewvc/llvm-project?rev=318819&view=rev
Log:
[SCEV] Strengthen variance condition in calculateLoopDisposition

Given loops `L1` and `L2` with AddRecs `AR1` and `AR2` varying in them respectively.
When identifying loop disposition of `AR2` w.r.t. `L1`, we only say that it is varying if
`L1` contains `L2`. But there is also a possible situation where `L1` and `L2` are
consecutive sibling loops within the parent loop. In this case, `AR2` is also varying
w.r.t. `L1`, but we don't correctly identify it.

It can lead, for exaple, to attempt of incorrect folding. Consider:
  AR1 = {a,+,b}<L1>
  AR2 = {c,+,d}<L2>
  EXAR2 = sext(AR1)
  MUL = mul AR1, EXAR2
If we incorrectly assume that `EXAR2` is invariant w.r.t. `L1`, we can end up trying to
construct something like: `{a * {c,+,d}<L2>,+,b * {c,+,d}<L2>}<L1>`, which is incorrect
because `AR2` is not available on entrance of `L1`.

Both situations "`L1` contains `L2`" and "`L1` preceeds sibling loop `L2`" can be handled
with one check: "header of `L1` dominates header of `L2`". This patch replaces the old
insufficient check with this one.

Differential Revision: https://reviews.llvm.org/D39453

Modified:
    llvm/trunk/lib/Analysis/ScalarEvolution.cpp
    llvm/trunk/test/Analysis/ScalarEvolution/different-loops-recs.ll

Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=318819&r1=318818&r2=318819&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original)
+++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Tue Nov 21 22:21:39 2017
@@ -10927,9 +10927,11 @@ ScalarEvolution::computeLoopDisposition(
     if (!L)
       return LoopVariant;
 
-    // This recurrence is variant w.r.t. L if L contains AR's loop.
-    if (L->contains(AR->getLoop()))
+    // Everything that is not defined at loop entry is variant.
+    if (DT.dominates(L->getHeader(), AR->getLoop()->getHeader()))
       return LoopVariant;
+    assert(!L->contains(AR->getLoop()) && "Containing loop's header does not"
+           " dominate the contained loop's header?");
 
     // This recurrence is invariant w.r.t. L if AR's loop contains L.
     if (AR->getLoop()->contains(L))

Modified: llvm/trunk/test/Analysis/ScalarEvolution/different-loops-recs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScalarEvolution/different-loops-recs.ll?rev=318819&r1=318818&r2=318819&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/ScalarEvolution/different-loops-recs.ll (original)
+++ llvm/trunk/test/Analysis/ScalarEvolution/different-loops-recs.ll Tue Nov 21 22:21:39 2017
@@ -510,3 +510,122 @@ exit:
   %tmp10 = add i32 %iv.1.2, 3
   ret void
 }
+
+define i64 @test_09(i32 %param) {
+
+; CHECK-LABEL: Classifying expressions for: @test_09
+; CHECK:       %iv1 = phi i64 [ %iv1.next, %guarded ], [ 0, %outer.loop ]
+; CHECK-NEXT:    -->  {0,+,1}<nuw><nsw><%loop1>
+; CHECK:       %iv1.trunc = trunc i64 %iv1 to i32
+; CHECK-NEXT:    -->  {0,+,1}<%loop1>
+; CHECK:       %iv1.next = add nuw nsw i64 %iv1, 1
+; CHECK-NEXT:    -->  {1,+,1}<nuw><nsw><%loop1>
+; CHECK:       %iv2 = phi i32 [ %iv2.next, %loop2 ], [ %param, %loop2.preheader ]
+; CHECK-NEXT:    -->  {%param,+,1}<%loop2>
+; CHECK:       %iv2.next = add i32 %iv2, 1
+; CHECK-NEXT:    -->  {(1 + %param),+,1}<%loop2>
+; CHECK:       %iv2.ext = sext i32 %iv2.next to i64
+; CHECK-NEXT:    -->  (sext i32 {(1 + %param),+,1}<%loop2> to i64)
+; CHECK:       %ret = mul i64 %iv1, %iv2.ext
+; CHECK-NEXT:    -->  ((sext i32 {(1 + %param),+,1}<%loop2> to i64) * {0,+,1}<nuw><nsw><%loop1>)
+
+entry:
+  br label %outer.loop
+
+outer.loop:                                 ; preds = %loop2.exit, %entry
+  br label %loop1
+
+loop1:                                           ; preds = %guarded, %outer.loop
+  %iv1 = phi i64 [ %iv1.next, %guarded ], [ 0, %outer.loop ]
+  %iv1.trunc = trunc i64 %iv1 to i32
+  %cond1 = icmp ult i64 %iv1, 100
+  br i1 %cond1, label %guarded, label %deopt
+
+guarded:                                          ; preds = %loop1
+  %iv1.next = add nuw nsw i64 %iv1, 1
+  %tmp16 = icmp slt i32 %iv1.trunc, 2
+  br i1 %tmp16, label %loop1, label %loop2.preheader
+
+deopt:                                            ; preds = %loop1
+  unreachable
+
+loop2.preheader:                                 ; preds = %guarded
+  br label %loop2
+
+loop2:                                           ; preds = %loop2, %loop2.preheader
+  %iv2 = phi i32 [ %iv2.next, %loop2 ], [ %param, %loop2.preheader ]
+  %iv2.next = add i32 %iv2, 1
+  %cond2 = icmp slt i32 %iv2, %iv1.trunc
+  br i1 %cond2, label %loop2, label %exit
+
+exit:                                          ; preds = %loop2.exit
+  %iv2.ext = sext i32 %iv2.next to i64
+  %ret = mul i64 %iv1, %iv2.ext
+  ret i64 %ret
+}
+
+define i64 @test_10(i32 %param) {
+
+; CHECK-LABEL: Classifying expressions for: @test_10
+; CHECK:       %uncle = phi i64 [ %uncle.outer.next, %uncle.loop.backedge ], [ 0, %outer.loop ]
+; CHECK-NEXT:  -->  {0,+,1}<%uncle.loop>
+; CHECK:       %iv1 = phi i64 [ %iv1.next, %guarded ], [ 0, %uncle.loop ]
+; CHECK-NEXT:  -->  {0,+,1}<nuw><nsw><%loop1>
+; CHECK:       %iv1.trunc = trunc i64 %iv1 to i32
+; CHECK-NEXT:  -->  {0,+,1}<%loop1>
+; CHECK:       %iv1.next = add nuw nsw i64 %iv1, 1
+; CHECK-NEXT:  -->  {1,+,1}<nuw><nsw><%loop1>
+; CHECK:       %uncle.outer.next = add i64 %uncle, 1
+; CHECK-NEXT:  -->  {1,+,1}<%uncle.loop>
+; CHECK:       %iv2 = phi i32 [ %iv2.next, %loop2 ], [ %param, %loop2.preheader ]
+; CHECK-NEXT:  -->  {%param,+,1}<%loop2>
+; CHECK:       %iv2.next = add i32 %iv2, 1
+; CHECK-NEXT:  -->  {(1 + %param),+,1}<%loop2>
+; CHECK:       %iv2.ext = sext i32 %iv2.next to i64
+; CHECK-NEXT:  -->  (sext i32 {(1 + %param),+,1}<%loop2> to i64)
+; CHECK:       %ret = mul i64 %iv1, %iv2.ext
+; CHECK-NEXT:  -->  ((sext i32 {(1 + %param),+,1}<%loop2> to i64) * {0,+,1}<nuw><nsw><%loop1>)
+
+entry:
+  br label %outer.loop
+
+outer.loop:                                       ; preds = %entry
+  br label %uncle.loop
+
+uncle.loop:                                       ; preds = %uncle.loop.backedge, %outer.loop
+  %uncle = phi i64 [ %uncle.outer.next, %uncle.loop.backedge ], [ 0, %outer.loop ]
+  br label %loop1
+
+loop1:                                            ; preds = %guarded, %uncle.loop
+  %iv1 = phi i64 [ %iv1.next, %guarded ], [ 0, %uncle.loop ]
+  %iv1.trunc = trunc i64 %iv1 to i32
+  %cond1 = icmp ult i64 %iv1, 100
+  br i1 %cond1, label %guarded, label %deopt
+
+guarded:                                          ; preds = %loop1
+  %iv1.next = add nuw nsw i64 %iv1, 1
+  %tmp16 = icmp slt i32 %iv1.trunc, 2
+  br i1 %tmp16, label %loop1, label %uncle.loop.backedge
+
+uncle.loop.backedge:                              ; preds = %guarded
+  %uncle.outer.next = add i64 %uncle, 1
+  %cond.uncle = icmp ult i64 %uncle, 120
+  br i1 %cond.uncle, label %loop2.preheader, label %uncle.loop
+
+deopt:                                            ; preds = %loop1
+  unreachable
+
+loop2.preheader:                                  ; preds = %uncle.loop.backedge
+  br label %loop2
+
+loop2:                                            ; preds = %loop2, %loop2.preheader
+  %iv2 = phi i32 [ %iv2.next, %loop2 ], [ %param, %loop2.preheader ]
+  %iv2.next = add i32 %iv2, 1
+  %cond2 = icmp slt i32 %iv2, %iv1.trunc
+  br i1 %cond2, label %loop2, label %exit
+
+exit:                                             ; preds = %loop2
+  %iv2.ext = sext i32 %iv2.next to i64
+  %ret = mul i64 %iv1, %iv2.ext
+  ret i64 %ret
+}




More information about the llvm-commits mailing list