[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