[llvm] [SCEV] Prove LHS Pred min(Y0..Yn) via per-operand decomposition. (PR #208555)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 9 13:47:52 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

<details>
<summary>Changes</summary>

Extend isKnownViaMinMaxDecomposition to handle min-on-RHS case:

  LHS Pred min(Y0, ..., Yn)   if   LHS Pred Yi for all i

Alive2 proofs:
 * unsigned predicates https://alive2.llvm.org/ce/z/BRrcEA
 * signed predicates https://alive2.llvm.org/ce/z/DBgWQW

Depends on https://github.com/llvm/llvm-project/pull/208546 (included in
the PR)

---

Patch is 23.06 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/208555.diff


4 Files Affected:

- (modified) llvm/lib/Analysis/ScalarEvolution.cpp (+38) 
- (modified) llvm/test/Analysis/ScalarEvolution/minmax-decomposition-guards.ll (+24-24) 
- (modified) llvm/test/Transforms/LoopVectorize/early-exit-minmax-trip-count.ll (+30-5) 
- (modified) llvm/test/Transforms/LoopVectorize/single-early-exit-deref-assumptions.ll (+72-14) 


``````````diff
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 134be6ac097e0..d96ec905a5901 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -11494,8 +11494,46 @@ bool ScalarEvolution::isKnownViaInduction(CmpPredicate Pred, SCEVUse LHS,
          isLoopEntryGuardedByCond(MDL, Pred, SplitLHS.first, SplitRHS.first);
 }
 
+/// Try to prove \p LHS \p Pred \p RHS by decomposing a min/max expression on
+/// either side into its operands:
+///
+///   max(X0, ..., Xn) Pred RHS  if  Xi Pred RHS for all i, and
+///   LHS Pred min(Y0, ..., Yn)  if  LHS Pred Yi for all i.
+static bool isKnownViaMinMaxDecomposition(ScalarEvolution &SE,
+                                          CmpPredicate Pred, const SCEV *LHS,
+                                          const SCEV *RHS) {
+  if (!isa<SCEVMinMaxExpr>(LHS) && !isa<SCEVMinMaxExpr>(RHS))
+    return false;
+
+  // Normalize predicates to less-than(or equal).
+  if (ICmpInst::isGT(Pred) || ICmpInst::isGE(Pred)) {
+    std::swap(LHS, RHS);
+    Pred = ICmpInst::getSwappedCmpPredicate(Pred);
+  }
+
+  if (!ICmpInst::isLT(Pred) && !ICmpInst::isLE(Pred))
+    return false;
+
+  if (isa<SCEVSMaxExpr, SCEVUMaxExpr>(LHS))
+    if (all_of(cast<SCEVMinMaxExpr>(LHS)->operands(), [&](const SCEV *Op) {
+          return SE.isKnownPredicate(Pred, Op, RHS);
+        }))
+      return true;
+  if (isa<SCEVSMinExpr, SCEVUMinExpr>(RHS))
+    if (all_of(cast<SCEVMinMaxExpr>(RHS)->operands(), [&](const SCEV *Op) {
+          return SE.isKnownPredicate(Pred, LHS, Op);
+        }))
+      return true;
+  return false;
+}
+
 bool ScalarEvolution::isKnownPredicate(CmpPredicate Pred, SCEVUse LHS,
                                        SCEVUse RHS) {
+  // Try to prove the predicate by decomposing a min/max expression before
+  // canonicalizing the operands, which may hide the min/max structure.
+  if (isKnownViaMinMaxDecomposition(*this, Pred, LHS, RHS))
+    return true;
+
   // Canonicalize the inputs first.
   (void)SimplifyICmpOperands(Pred, LHS, RHS);
 
diff --git a/llvm/test/Analysis/ScalarEvolution/minmax-decomposition-guards.ll b/llvm/test/Analysis/ScalarEvolution/minmax-decomposition-guards.ll
index 35c7790347dc7..e33cbc4935472 100644
--- a/llvm/test/Analysis/ScalarEvolution/minmax-decomposition-guards.ll
+++ b/llvm/test/Analysis/ScalarEvolution/minmax-decomposition-guards.ll
@@ -7,9 +7,9 @@ declare void @use(i64)
 define void @umax_start(i64 %x0, i64 %x1, i64 %bound) {
 ; CHECK-LABEL: 'umax_start'
 ; CHECK-NEXT:  Determining loop execution counts for: @umax_start
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 umax %x1)) + (%x0 umax %x1 umax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 umax %x1)) + %bound)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 umax %x1)) + (%x0 umax %x1 umax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 umax %x1)) + %bound)
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -61,9 +61,9 @@ exit:
 define void @umax_start_3op(i64 %x0, i64 %x1, i64 %x2, i64 %bound) {
 ; CHECK-LABEL: 'umax_start_3op'
 ; CHECK-NEXT:  Determining loop execution counts for: @umax_start_3op
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 umax %x1 umax %x2)) + (%x0 umax %x1 umax %x2 umax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 umax %x1 umax %x2)) + %bound)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 umax %x1 umax %x2)) + (%x0 umax %x1 umax %x2 umax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 umax %x1 umax %x2)) + %bound)
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -92,9 +92,9 @@ exit:
 define void @umax_start_swapped_guards(i64 %x0, i64 %x1, i64 %bound) {
 ; CHECK-LABEL: 'umax_start_swapped_guards'
 ; CHECK-NEXT:  Determining loop execution counts for: @umax_start_swapped_guards
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 umax %x1)) + (%x0 umax %x1 umax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 umax %x1)) + %bound)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 umax %x1)) + (%x0 umax %x1 umax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 umax %x1)) + %bound)
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -120,9 +120,9 @@ exit:
 define void @smax_start(i64 %x0, i64 %x1, i64 %bound) {
 ; CHECK-LABEL: 'smax_start'
 ; CHECK-NEXT:  Determining loop execution counts for: @smax_start
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 smax %x1)) + (%x0 smax %x1 smax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 smax %x1)) + %bound)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 smax %x1)) + (%x0 smax %x1 smax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 smax %x1)) + %bound)
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -174,9 +174,9 @@ exit:
 define void @smax_start_3op(i64 %x0, i64 %x1, i64 %x2, i64 %bound) {
 ; CHECK-LABEL: 'smax_start_3op'
 ; CHECK-NEXT:  Determining loop execution counts for: @smax_start_3op
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 smax %x1 smax %x2)) + (%x0 smax %x1 smax %x2 smax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 smax %x1 smax %x2)) + %bound)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 smax %x1 smax %x2)) + (%x0 smax %x1 smax %x2 smax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 smax %x1 smax %x2)) + %bound)
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -206,9 +206,9 @@ exit:
 define void @smax_start_swapped_guards(i64 %x0, i64 %x1, i64 %bound) {
 ; CHECK-LABEL: 'smax_start_swapped_guards'
 ; CHECK-NEXT:  Determining loop execution counts for: @smax_start_swapped_guards
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 smax %x1)) + (%x0 smax %x1 smax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (%x0 smax %x1)) + %bound)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 smax %x1)) + (%x0 smax %x1 smax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (%x0 smax %x1)) + %bound)
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -234,9 +234,9 @@ exit:
 define void @umin_limit(i64 %x0, i64 %x1, i64 %bound) {
 ; CHECK-LABEL: 'umin_limit'
 ; CHECK-NEXT:  Determining loop execution counts for: @umin_limit
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + ((%x0 umin %x1) umax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + (%x0 umin %x1))
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + ((%x0 umin %x1) umax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + (%x0 umin %x1))
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -288,9 +288,9 @@ exit:
 define void @umin_limit_3op(i64 %x0, i64 %x1, i64 %x2, i64 %bound) {
 ; CHECK-LABEL: 'umin_limit_3op'
 ; CHECK-NEXT:  Determining loop execution counts for: @umin_limit_3op
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + ((%x0 umin %x1 umin %x2) umax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + (%x0 umin %x1 umin %x2))
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + ((%x0 umin %x1 umin %x2) umax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + (%x0 umin %x1 umin %x2))
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -319,9 +319,9 @@ exit:
 define void @umin_limit_swapped_guards(i64 %x0, i64 %x1, i64 %bound) {
 ; CHECK-LABEL: 'umin_limit_swapped_guards'
 ; CHECK-NEXT:  Determining loop execution counts for: @umin_limit_swapped_guards
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + ((%x0 umin %x1) umax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + (%x0 umin %x1))
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + ((%x0 umin %x1) umax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + (%x0 umin %x1))
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -347,9 +347,9 @@ exit:
 define void @smin_limit(i64 %x0, i64 %x1, i64 %bound) {
 ; CHECK-LABEL: 'smin_limit'
 ; CHECK-NEXT:  Determining loop execution counts for: @smin_limit
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + ((%x0 smin %x1) smax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + (%x0 smin %x1))
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + ((%x0 smin %x1) smax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + (%x0 smin %x1))
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -401,9 +401,9 @@ exit:
 define void @smin_limit_3op(i64 %x0, i64 %x1, i64 %x2, i64 %bound) {
 ; CHECK-LABEL: 'smin_limit_3op'
 ; CHECK-NEXT:  Determining loop execution counts for: @smin_limit_3op
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + ((%x0 smin %x1 smin %x2) smax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + (%x0 smin %x1 smin %x2))
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + ((%x0 smin %x1 smin %x2) smax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + (%x0 smin %x1 smin %x2))
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
@@ -431,9 +431,9 @@ exit:
 define void @smin_limit_swapped_guards(i64 %x0, i64 %x1, i64 %bound) {
 ; CHECK-LABEL: 'smin_limit_swapped_guards'
 ; CHECK-NEXT:  Determining loop execution counts for: @smin_limit_swapped_guards
-; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + ((%x0 smin %x1) smax %bound))
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * %bound) + (%x0 smin %x1))
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + ((%x0 smin %x1) smax %bound))
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * %bound) + (%x0 smin %x1))
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
diff --git a/llvm/test/Transforms/LoopVectorize/early-exit-minmax-trip-count.ll b/llvm/test/Transforms/LoopVectorize/early-exit-minmax-trip-count.ll
index 25a60cc14761a..a8e3219cc4e02 100644
--- a/llvm/test/Transforms/LoopVectorize/early-exit-minmax-trip-count.ll
+++ b/llvm/test/Transforms/LoopVectorize/early-exit-minmax-trip-count.ll
@@ -162,17 +162,42 @@ define i1 @deref_umin_swapped_guards(ptr %ptr, i64 %a, i64 %b, i64 %c) #0 {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[GUARD_POS]])
 ; CHECK-NEXT:    [[DEREF:%.*]] = call i64 @llvm.umin.i64(i64 [[A]], i64 [[B]])
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i64 [[DEREF]]) ]
+; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[C]], 4
+; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; CHECK:       [[VECTOR_PH]]:
+; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[C]], 4
+; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[C]], [[N_MOD_VF]]
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LATCH:.*]] ]
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY_INTERIM:.*]] ]
 ; CHECK-NEXT:    [[ELEMENT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[IV]]
-; CHECK-NEXT:    [[ELEMENT:%.*]] = load i8, ptr [[ELEMENT_GEP]], align 1
+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <4 x i8>, ptr [[ELEMENT_GEP]], align 1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <4 x i8> [[WIDE_LOAD]], zeroinitializer
+; CHECK-NEXT:    [[TMP2:%.*]] = freeze <4 x i1> [[TMP1]]
+; CHECK-NEXT:    [[TMP3:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP2]])
+; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[IV]], 4
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[TMP3]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM]]
+; CHECK:       [[VECTOR_BODY_INTERIM]]:
+; CHECK-NEXT:    br i1 [[TMP4]], label %[[MIDDLE_BLOCK:.*]], label %[[LOOP]], !llvm.loop [[LOOP4:![0-9]+]]
+; CHECK:       [[MIDDLE_BLOCK]]:
+; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[C]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[CMP_N]], label %[[EXIT_1:.*]], label %[[SCALAR_PH]]
+; CHECK:       [[VECTOR_EARLY_EXIT]]:
+; CHECK-NEXT:    br label %[[EXIT_0:.*]]
+; CHECK:       [[SCALAR_PH]]:
+; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
+; CHECK-NEXT:    br label %[[LOOP1:.*]]
+; CHECK:       [[LOOP1]]:
+; CHECK-NEXT:    [[IV1:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LATCH:.*]] ]
+; CHECK-NEXT:    [[ELEMENT_GEP1:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[IV1]]
+; CHECK-NEXT:    [[ELEMENT:%.*]] = load i8, ptr [[ELEMENT_GEP1]], align 1
 ; CHECK-NEXT:    [[FOUND_CHECK:%.*]] = icmp eq i8 [[ELEMENT]], 0
-; CHECK-NEXT:    br i1 [[FOUND_CHECK]], label %[[EXIT_0:.*]], label %[[LATCH]]
+; CHECK-NEXT:    br i1 [[FOUND_CHECK]], label %[[EXIT_0]], label %[[LATCH]]
 ; CHECK:       [[LATCH]]:
-; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 1
+; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV1]], 1
 ; CHECK-NEXT:    [[RANGE_CHECK:%.*]] = icmp ult i64 [[IV_NEXT]], [[C]]
-; CHECK-NEXT:    br i1 [[RANGE_CHECK]], label %[[LOOP]], label %[[EXIT_1:.*]]
+; CHECK-NEXT:    br i1 [[RANGE_CHECK]], label %[[LOOP1]], label %[[EXIT_1]], !llvm.loop [[LOOP5:![0-9]+]]
 ; CHECK:       [[EXIT_0]]:
 ; CHECK-NEXT:    ret i1 true
 ; CHECK:       [[EXIT_1]]:
diff --git a/llvm/test/Transforms/LoopVectorize/single-early-exit-deref-assumptions.ll b/llvm/test/Transforms/LoopVectorize/single-early-exit-deref-assumptions.ll
index 8be66cc4c8ef8..c0528909143f4 100644
--- a/llvm/test/Transforms/LoopVectorize/single-early-exit-deref-assumptions.ll
+++ b/llvm/test/Transforms/LoopVectorize/single-early-exit-deref-assumptions.ll
@@ -1336,21 +1336,50 @@ define i64 @early_exit_deref_assumption_extra_constant_assume(ptr noalias %p1, p
 ; CHECK-NEXT:    [[C:%.*]] = icmp ne i64 [[N]], 0
 ; CHECK-NEXT:    br i1 [[C]], label %[[SCALAR_PH:.*]], label %[[LOOP_END:.*]]
 ; CHECK:       [[SCALAR_PH]]:
+; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[N]], 4
+; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH1:.*]], label %[[VECTOR_PH:.*]]
+; CHECK:       [[VECTOR_PH]]:
+; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[N]], 4
+; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[N]], [[N_MOD_VF]]
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], %[[LOOP_INC:.*]] ], [ 0, %[[SCALAR_PH]] ]
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT3:%.*]], %[[VECTOR_BODY_INTERIM:.*]] ]
 ; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[INDEX]]
-; CHECK-NEXT:    [[LD1:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
-; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[INDEX]]
+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <4 x i8>, ptr [[ARRAYIDX]], align 1
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[INDEX]]
+; CHECK-NEXT:    [[WIDE_LOAD2:%.*]] = load <4 x i8>, ptr [[TMP1]], align 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne <4 x i8> [[WIDE_LOAD]], [[WIDE_LOAD2]]
+; CHECK-NEXT:    [[TMP3:%.*]] = freeze <4 x i1> [[TMP2]]
+; CHECK-NEXT:    [[TMP4:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP3]])
+; CHECK-NEXT:    [[INDEX_NEXT3]] = add nuw i64 [[INDEX]], 4
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[INDEX_NEXT3]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[TMP4]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM]]
+; CHECK:       [[VECTOR_BODY_INTERIM]]:
+; CHECK-NEXT:    br i1 [[TMP5]], label %[[MIDDLE_BLOCK:.*]], label %[[LOOP]], !llvm.loop [[LOOP18:![0-9]+]]
+; CHECK:       [[MIDDLE_BLOCK]]:
+; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[CMP_N]], label %[[LOOP_END_LOOPEXIT:.*]], label %[[SCALAR_PH1]]
+; CHECK:       [[VECTOR_EARLY_EXIT]]:
+; CHECK-NEXT:    [[TMP6:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v4i1(<4 x i1> [[TMP2]], i1 false)
+; CHECK-NEXT:    [[TMP7:%.*]] = add i64 [[INDEX]], [[TMP6]]
+; CHECK-NEXT:    br label %[[LOOP_END_LOOPEXIT]]
+; CHECK:       [[SCALAR_PH1]]:
+; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[SCALAR_PH]] ]
+; CHECK-NEXT:    br label %[[LOOP1:.*]]
+; CHECK:       [[LOOP1]]:
+; CHECK-NEXT:    [[INDEX1:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], %[[LOOP_INC:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH1]] ]
+; CHECK-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[INDEX1]]
+; CHECK-NEXT:    [[LD1:%.*]] = load i8, ptr [[ARRAYIDX2]], align 1
+; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[INDEX1]]
 ; CHECK-NEXT:    [[LD2:%.*]] = load i8, ptr [[ARRAYIDX1]], align 1
 ; CHECK-NEXT:    [[CMP3:%.*]] = icmp eq i8 [[LD1]], [[LD2]]
-; CHECK-NEXT:    br i1 [[CMP3]], label %[[LOOP_INC]], label %[[LOOP_END_LOOPEXIT:.*]]
+; CHECK-NEXT:    br i1 [[CMP3]], label %[[LOOP_INC]], label %[[LOOP_END_LOOPEXIT]]
 ; CHECK:       [[LOOP_INC]]:
-; CHECK-NEXT:    [[INDEX_NEXT]] = add i64 [[INDEX]], 1
+; CHECK-NEXT:    [[INDEX_NEXT]] = add i64 [[INDEX1]], 1
 ; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i64 [[INDEX_NEXT]], [[N]]
-; CHECK-NEXT:    br i1 [[EXITCOND]], label %[[LOOP]], label %[[LOOP_END_LOOPEXIT]]
+; CHECK-NEXT:    br i1 [[EXITCOND]], label %[[LOOP1]], label %[[LOOP_END_LOOPEXIT]], !llvm.loop [[LOOP19:![0-9]+]]
 ; CHECK:       [[LOOP_END_LOOPEXIT]]:
-; CHECK-NEXT:    [[RETVAL_PH:%.*]] = phi i64 [ -1, %[[LOOP_INC]] ], [ [[INDEX]], %[[LOOP]] ]
+; CHECK-NEXT:    [[RETVAL_PH:%.*]] = phi i64 [ -1, %[[LOOP_INC]] ], [ [[INDEX1]], %[[LOOP1]] ], [ -1, %[[MIDDLE_BLOCK]] ], [ [[TMP7]], %[[VECTOR_EARLY_EXIT]] ]
 ; CHECK-NEXT:    br label %[[LOOP_END]]
 ; CHECK:       [[LOOP_END]]:
 ; CHECK-NEXT:    [[RETVAL:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[RETVAL_PH]], %[[LOOP_END_LOOPEXIT]] ]
@@ -1393,21 +1422,50 @@ define i64 @early_exit_deref_assumption_extra_variable_assume(ptr noalias %p1, p
 ; CHECK-NEXT:    [[C:%.*]] = icmp ne i64 [[N]], 0
 ; CHECK-NEXT:    br i1 [[C]], label %[[SCALAR_PH:.*]], label %[[LOOP_END:.*]]
 ; CHECK:       [[SCALAR_PH]]:
+; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[N]], 4
+; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH1:.*]], label %[[VECTOR_PH:.*]]
+; CHECK:       [[VECTOR_PH]]:
+; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[N]], 4
+; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[N]], [[N_MOD_VF]]
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], %[[LOOP_INC:.*]] ], [ 0, %[[SCALAR_PH]] ]
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT3:%.*]], %[[VECTOR_BODY_INTERIM:.*]] ]
 ; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[INDEX]]
-; CHECK-NEXT:    [[LD1:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
-; CHECK-NEXT:    ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/208555


More information about the llvm-commits mailing list