[llvm] 503541f - [SCEV] Recognize binary `and` as bit-wise `umin`

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 10 06:46:59 PST 2022


Author: Roman Lebedev
Date: 2022-02-10T17:42:54+03:00
New Revision: 503541fa93533920acd29ed86d46deae48546ce6

URL: https://github.com/llvm/llvm-project/commit/503541fa93533920acd29ed86d46deae48546ce6
DIFF: https://github.com/llvm/llvm-project/commit/503541fa93533920acd29ed86d46deae48546ce6.diff

LOG: [SCEV] Recognize binary `and` as bit-wise `umin`

https://alive2.llvm.org/ce/z/aKAr94

We could transparently handle wider bitwidths,
by effectively casting iN to <N x i1> and performing the `umin`
bit/element -wise, the expression will be rather large,
so let's not do that for now.

Added: 
    

Modified: 
    llvm/lib/Analysis/ScalarEvolution.cpp
    llvm/test/Analysis/ScalarEvolution/exact-exit-count-more-precise.ll
    llvm/test/Analysis/ScalarEvolution/logical-operations.ll
    llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
    llvm/test/Analysis/ScalarEvolution/pr48225.ll
    llvm/test/Analysis/ScalarEvolution/umin-umax-folds.ll
    llvm/test/Analysis/ScalarEvolution/widenable-condition.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 36fa16267c5c..961d6a868f28 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -7180,6 +7180,9 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) {
               MulCount);
         }
       }
+      // Binary `and` is a bit-wise `umin`.
+      if (BO->LHS->getType()->isIntegerTy(1))
+        return getUMinExpr(getSCEV(BO->LHS), getSCEV(BO->RHS));
       break;
 
     case Instruction::Or:

diff  --git a/llvm/test/Analysis/ScalarEvolution/exact-exit-count-more-precise.ll b/llvm/test/Analysis/ScalarEvolution/exact-exit-count-more-precise.ll
index f33de3c7ec0f..a916f175b4ad 100644
--- a/llvm/test/Analysis/ScalarEvolution/exact-exit-count-more-precise.ll
+++ b/llvm/test/Analysis/ScalarEvolution/exact-exit-count-more-precise.ll
@@ -11,7 +11,7 @@ define void @test_and(i16 %in) {
 ; CHECK-NEXT:    %_tmp6.i = add nsw i16 %_tmp25.i, 1
 ; CHECK-NEXT:    --> {(1 + %in),+,1}<nsw><%bb1.i> U: full-set S: full-set Exits: 2 LoopDispositions: { %bb1.i: Computable, %bb2: Variant }
 ; CHECK-NEXT:    %or.cond = and i1 %_tmp10.i, %exitcond.i
-; CHECK-NEXT:    --> %or.cond U: full-set S: full-set Exits: true LoopDispositions: { %bb1.i: Variant, %bb2: Variant }
+; CHECK-NEXT:    --> (%_tmp10.i umin %exitcond.i) U: full-set S: full-set Exits: true LoopDispositions: { %bb1.i: Variant, %bb2: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @test_and
 ; CHECK-NEXT:  Loop %bb1.i: backedge-taken count is (1 + (-1 * %in))
 ; CHECK-NEXT:  Loop %bb1.i: max backedge-taken count is -1

diff  --git a/llvm/test/Analysis/ScalarEvolution/logical-operations.ll b/llvm/test/Analysis/ScalarEvolution/logical-operations.ll
index 1b7c554d995e..cc3ae1eccc06 100644
--- a/llvm/test/Analysis/ScalarEvolution/logical-operations.ll
+++ b/llvm/test/Analysis/ScalarEvolution/logical-operations.ll
@@ -47,7 +47,7 @@ define i1 @binary_and.i1(i1 %x, i1 %y) {
 ; CHECK-LABEL: 'binary_and.i1'
 ; CHECK-NEXT:  Classifying expressions for: @binary_and.i1
 ; CHECK-NEXT:    %r = and i1 %x, %y
-; CHECK-NEXT:    --> %r U: full-set S: full-set
+; CHECK-NEXT:    --> (%x umin %y) U: full-set S: full-set
 ; CHECK-NEXT:  Determining loop execution counts for: @binary_and.i1
 ;
   %r = and i1 %x, %y
@@ -69,11 +69,11 @@ define i1 @binary_and.4ops.i1(i1 %x, i1 %y, i1 %z, i1 %a) {
 ; CHECK-LABEL: 'binary_and.4ops.i1'
 ; CHECK-NEXT:  Classifying expressions for: @binary_and.4ops.i1
 ; CHECK-NEXT:    %t0 = and i1 %x, %y
-; CHECK-NEXT:    --> %t0 U: full-set S: full-set
+; CHECK-NEXT:    --> (%x umin %y) U: full-set S: full-set
 ; CHECK-NEXT:    %t1 = and i1 %z, %a
-; CHECK-NEXT:    --> %t1 U: full-set S: full-set
+; CHECK-NEXT:    --> (%z umin %a) U: full-set S: full-set
 ; CHECK-NEXT:    %r = and i1 %t0, %t1
-; CHECK-NEXT:    --> %r U: full-set S: full-set
+; CHECK-NEXT:    --> (%x umin %y umin %z umin %a) U: full-set S: full-set
 ; CHECK-NEXT:  Determining loop execution counts for: @binary_and.4ops.i1
 ;
   %t0 = and i1 %x, %y

diff  --git a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
index 54c5e79ef0b1..bf72608d1a73 100644
--- a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
+++ b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
@@ -486,7 +486,7 @@ define void @test_guard_if_and_enter(i32* nocapture readonly %data, i64 %count)
 ; CHECK-LABEL: 'test_guard_if_and_enter'
 ; CHECK-NEXT:  Classifying expressions for: @test_guard_if_and_enter
 ; CHECK-NEXT:    %cmp.and = and i1 %cmp.ult, %cmp.ne
-; CHECK-NEXT:    --> %cmp.and U: full-set S: full-set
+; CHECK-NEXT:    --> (%cmp.ult umin %cmp.ne) U: full-set S: full-set
 ; CHECK-NEXT:    %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ]
 ; CHECK-NEXT:    --> {0,+,1}<nuw><%loop> U: [0,4) S: [0,4) Exits: (-1 + %count) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %idx = getelementptr inbounds i32, i32* %data, i64 %iv
@@ -522,7 +522,7 @@ define void @test_guard_if_and_skip(i32* nocapture readonly %data, i64 %count) {
 ; CHECK-LABEL: 'test_guard_if_and_skip'
 ; CHECK-NEXT:  Classifying expressions for: @test_guard_if_and_skip
 ; CHECK-NEXT:    %cmp.and = and i1 %cmp.ult, %cmp.ne
-; CHECK-NEXT:    --> %cmp.and U: full-set S: full-set
+; CHECK-NEXT:    --> (%cmp.ult umin %cmp.ne) U: full-set S: full-set
 ; CHECK-NEXT:    %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ]
 ; CHECK-NEXT:    --> {0,+,1}<nuw><%loop> U: full-set S: full-set Exits: (-1 + %count) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %idx = getelementptr inbounds i32, i32* %data, i64 %iv
@@ -558,9 +558,9 @@ define void @test_guard_if_and_and(i32* nocapture readonly %data, i64 %count, i1
 ; CHECK-LABEL: 'test_guard_if_and_and'
 ; CHECK-NEXT:  Classifying expressions for: @test_guard_if_and_and
 ; CHECK-NEXT:    %cmp.and1 = and i1 %c, %cmp.ne
-; CHECK-NEXT:    --> %cmp.and1 U: full-set S: full-set
+; CHECK-NEXT:    --> (%c umin %cmp.ne) U: full-set S: full-set
 ; CHECK-NEXT:    %cmp.and = and i1 %cmp.ult, %cmp.and1
-; CHECK-NEXT:    --> %cmp.and U: full-set S: full-set
+; CHECK-NEXT:    --> (%c umin %cmp.ult umin %cmp.ne) U: full-set S: full-set
 ; CHECK-NEXT:    %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ]
 ; CHECK-NEXT:    --> {0,+,1}<nuw><%loop> U: [0,4) S: [0,4) Exits: (-1 + %count) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %idx = getelementptr inbounds i32, i32* %data, i64 %iv
@@ -599,7 +599,7 @@ define void @test_guard_if_and_or(i32* nocapture readonly %data, i64 %count, i1
 ; CHECK-NEXT:    %cmp.or = or i1 %c, %cmp.ne
 ; CHECK-NEXT:    --> (%c umax %cmp.ne) U: full-set S: full-set
 ; CHECK-NEXT:    %cmp.and = and i1 %cmp.ult, %cmp.or
-; CHECK-NEXT:    --> %cmp.and U: full-set S: full-set
+; CHECK-NEXT:    --> ((%c umax %cmp.ne) umin %cmp.ult) U: full-set S: full-set
 ; CHECK-NEXT:    %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ]
 ; CHECK-NEXT:    --> {0,+,1}<nuw><%loop> U: full-set S: full-set Exits: (-1 + %count) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %idx = getelementptr inbounds i32, i32* %data, i64 %iv
@@ -747,9 +747,9 @@ define void @test_guard_if_or_and(i32* nocapture readonly %data, i64 %count, i1
 ; CHECK-LABEL: 'test_guard_if_or_and'
 ; CHECK-NEXT:  Classifying expressions for: @test_guard_if_or_and
 ; CHECK-NEXT:    %cmp.and = and i1 %c, %cmp.eq
-; CHECK-NEXT:    --> %cmp.and U: full-set S: full-set
+; CHECK-NEXT:    --> (%c umin %cmp.eq) U: full-set S: full-set
 ; CHECK-NEXT:    %cmp.or = or i1 %cmp.uge, %cmp.and
-; CHECK-NEXT:    --> (%cmp.and umax %cmp.uge) U: full-set S: full-set
+; CHECK-NEXT:    --> ((%c umin %cmp.eq) umax %cmp.uge) U: full-set S: full-set
 ; CHECK-NEXT:    %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ]
 ; CHECK-NEXT:    --> {0,+,1}<nuw><%loop> U: full-set S: full-set Exits: (-1 + %count) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %idx = getelementptr inbounds i32, i32* %data, i64 %iv
@@ -1110,7 +1110,7 @@ define void @test_guard_slt_sgt_1(i32* nocapture %a, i64 %N) {
 ; CHECK-LABEL: 'test_guard_slt_sgt_1'
 ; CHECK-NEXT:  Classifying expressions for: @test_guard_slt_sgt_1
 ; CHECK-NEXT:    %and = and i1 %c.0, %c.1
-; CHECK-NEXT:    --> %and U: full-set S: full-set
+; CHECK-NEXT:    --> (%c.0 umin %c.1) U: full-set S: full-set
 ; CHECK-NEXT:    %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK-NEXT:    --> {0,+,1}<nuw><nsw><%loop> U: [0,11) S: [0,11) Exits: (-1 + %N) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %idx = getelementptr inbounds i32, i32* %a, i64 %iv
@@ -1146,7 +1146,7 @@ define void @test_guard_slt_sgt_2(i32* nocapture %a, i64 %i) {
 ; CHECK-LABEL: 'test_guard_slt_sgt_2'
 ; CHECK-NEXT:  Classifying expressions for: @test_guard_slt_sgt_2
 ; CHECK-NEXT:    %and = and i1 %c.0, %c.1
-; CHECK-NEXT:    --> %and U: full-set S: full-set
+; CHECK-NEXT:    --> (%c.0 umin %c.1) U: full-set S: full-set
 ; CHECK-NEXT:    %iv = phi i64 [ %iv.next, %loop ], [ %i, %entry ]
 ; CHECK-NEXT:    --> {%i,+,1}<nuw><nsw><%loop> U: full-set S: full-set Exits: 17 LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %idx = getelementptr inbounds i32, i32* %a, i64 %iv
@@ -1182,7 +1182,7 @@ define void @test_guard_sle_sge_1(i32* nocapture %a, i64 %N) {
 ; CHECK-LABEL: 'test_guard_sle_sge_1'
 ; CHECK-NEXT:  Classifying expressions for: @test_guard_sle_sge_1
 ; CHECK-NEXT:    %and = and i1 %c.0, %c.1
-; CHECK-NEXT:    --> %and U: full-set S: full-set
+; CHECK-NEXT:    --> (%c.0 umin %c.1) U: full-set S: full-set
 ; CHECK-NEXT:    %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK-NEXT:    --> {0,+,1}<nuw><nsw><%loop> U: [0,12) S: [0,12) Exits: (-1 + %N) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %idx = getelementptr inbounds i32, i32* %a, i64 %iv
@@ -1218,7 +1218,7 @@ define void @test_guard_sle_sge_2(i32* nocapture %a, i64 %i) {
 ; CHECK-LABEL: 'test_guard_sle_sge_2'
 ; CHECK-NEXT:  Classifying expressions for: @test_guard_sle_sge_2
 ; CHECK-NEXT:    %and = and i1 %c.0, %c.1
-; CHECK-NEXT:    --> %and U: full-set S: full-set
+; CHECK-NEXT:    --> (%c.0 umin %c.1) U: full-set S: full-set
 ; CHECK-NEXT:    %iv = phi i64 [ %iv.next, %loop ], [ %i, %entry ]
 ; CHECK-NEXT:    --> {%i,+,1}<nuw><nsw><%loop> U: full-set S: full-set Exits: 17 LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %idx = getelementptr inbounds i32, i32* %a, i64 %iv

diff  --git a/llvm/test/Analysis/ScalarEvolution/pr48225.ll b/llvm/test/Analysis/ScalarEvolution/pr48225.ll
index 38e0967b4cae..ee17d557727b 100644
--- a/llvm/test/Analysis/ScalarEvolution/pr48225.ll
+++ b/llvm/test/Analysis/ScalarEvolution/pr48225.ll
@@ -17,7 +17,7 @@ define void @test_and(i1 %boolcond) {
 ; CHECK-NEXT:    %iv = phi i32 [ 0, %entry ], [ %inc, %backedge ]
 ; CHECK-NEXT:    --> {0,+,1}<nuw><nsw><%loop> U: [0,3) S: [0,3) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %or.cond = and i1 %cond.false.on.first.iter, %cond.false.on.second.iter
-; CHECK-NEXT:    --> %or.cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond.false.on.first.iter umin %cond.false.on.second.iter) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:    %inc = add nuw nsw i32 %iv, 1
 ; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%loop> U: [1,4) S: [1,4) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @test_and

diff  --git a/llvm/test/Analysis/ScalarEvolution/umin-umax-folds.ll b/llvm/test/Analysis/ScalarEvolution/umin-umax-folds.ll
index 2ec0a45be0a0..219a71e9453e 100644
--- a/llvm/test/Analysis/ScalarEvolution/umin-umax-folds.ll
+++ b/llvm/test/Analysis/ScalarEvolution/umin-umax-folds.ll
@@ -13,7 +13,7 @@ define void @umin_sext_x_zext_x(i32 %len) {
 ; CHECK-NEXT:    %iv.next = add i64 %iv, 1
 ; CHECK-NEXT:    --> {1,+,1}<%loop> U: [1,4294967297) S: [1,4294967297) Exits: (1 + (zext i32 %len to i64))<nuw><nsw> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %and = and i1 %cmp1, %cmp2
-; CHECK-NEXT:    --> %and U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cmp1 umin %cmp2) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @umin_sext_x_zext_x
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is (zext i32 %len to i64)
 ; CHECK-NEXT:  Loop %loop: max backedge-taken count is 4294967295

diff  --git a/llvm/test/Analysis/ScalarEvolution/widenable-condition.ll b/llvm/test/Analysis/ScalarEvolution/widenable-condition.ll
index 218c73640168..ee5cdcd6754f 100644
--- a/llvm/test/Analysis/ScalarEvolution/widenable-condition.ll
+++ b/llvm/test/Analysis/ScalarEvolution/widenable-condition.ll
@@ -20,7 +20,7 @@ define i32 @wc_max() {
 ; CHECK-NEXT:    %widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    --> %widenable_cond3 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:    %exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
-; CHECK-NEXT:    --> %exiplicit_guard_cond4 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
+; CHECK-NEXT:    --> (%cond_1 umin %widenable_cond3) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
 ; CHECK-NEXT:  Determining loop execution counts for: @wc_max
 ; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
 ; CHECK-NEXT:  Loop %loop: max backedge-taken count is 1999


        


More information about the llvm-commits mailing list