[llvm] [SCEV] Bail out on wider AddRecs in SCEVWrapPrediacte::implies. (PR #191498)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 11 06:44:27 PDT 2026


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/191498

>From af0403bcd988b8db56147db34ee6ae7339f38a56 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 10 Apr 2026 16:20:52 +0100
Subject: [PATCH] [SCEV] Bail out on wider AddRecs in
 SCEVWrapPrediacte::implies.

NSSW/NUSW on a wider AddRec does not imply NSSW/NUSW on a narrower
AddRec.

Fixes https://github.com/llvm/llvm-project/issues/191382.
---
 llvm/lib/Analysis/ScalarEvolution.cpp                      | 6 ++++++
 .../Analysis/LoopAccessAnalysis/nssw-predicate-implied.ll  | 3 ++-
 llvm/test/Analysis/LoopAccessAnalysis/nusw-predicates.ll   | 7 ++++++-
 .../LoopVectorize/runtime-check-small-clamped-bounds.ll    | 6 ++++--
 4 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 2862acfedb91d..9f362deb7cca9 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -15335,6 +15335,12 @@ bool SCEVWrapPredicate::implies(const SCEVPredicate *N,
   if (Start->getType()->isPointerTy() && Start->getType() != OpStart->getType())
     return false;
 
+  // NUSW/NSSW on a wider-type AddRec does not imply the same on a
+  // narrower-type AddRec.
+  if (SE.getTypeSizeInBits(AR->getType()) >
+      SE.getTypeSizeInBits(Op->AR->getType()))
+    return false;
+
   const SCEV *Step = AR->getStepRecurrence(SE);
   const SCEV *OpStep = Op->AR->getStepRecurrence(SE);
   if (!SE.isKnownPositive(Step) || !SE.isKnownPositive(OpStep))
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/nssw-predicate-implied.ll b/llvm/test/Analysis/LoopAccessAnalysis/nssw-predicate-implied.ll
index 8299df310ce1f..168e9a867d217 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/nssw-predicate-implied.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/nssw-predicate-implied.ll
@@ -333,7 +333,7 @@ exit:
   ret void
 }
 
-; FIXME: NSSW on the wider i32 AddRec does not imply NSSW on a narrower i8 AddRec.
+; NSSW on the wider i32 AddRec does not imply NSSW on a narrower i8 AddRec.
 ; Test for https://github.com/llvm/llvm-project/issues/191382.
 define void @wider_i32_nssw_does_not_imply_narrower_i8_nssw(ptr %dst, ptr %src, i32 %N) {
 ; CHECK-LABEL: 'wider_i32_nssw_does_not_imply_narrower_i8_nssw'
@@ -358,6 +358,7 @@ define void @wider_i32_nssw_does_not_imply_narrower_i8_nssw(ptr %dst, ptr %src,
 ; CHECK-NEXT:      SCEV assumptions:
 ; CHECK-NEXT:      Equal predicate: (zext i1 (trunc i32 %N to i1) to i32) == 0
 ; CHECK-NEXT:      {0,+,2}<%loop> Added Flags: <nssw>
+; CHECK-NEXT:      {0,+,1}<%loop> Added Flags: <nssw>
 ; CHECK-EMPTY:
 ; CHECK-NEXT:      Expressions re-written:
 ; CHECK-NEXT:      [PSE] %gep.dst = getelementptr inbounds i32, ptr %dst, i64 %ext.iv.1:
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/nusw-predicates.ll b/llvm/test/Analysis/LoopAccessAnalysis/nusw-predicates.ll
index 9d932c9bb4809..87b25140949b9 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/nusw-predicates.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/nusw-predicates.ll
@@ -159,19 +159,24 @@ loop:
    ret void
  }
 
-; FIXME: NUSW on the wider i32 AddRec does not imply NUSW on a narrower i8 AddRec.
+; NUSW on the wider i32 AddRec does not imply NUSW on a narrower i8 AddRec.
 ; Test for https://github.com/llvm/llvm-project/issues/191382.
 define void @wider_i32_nusw_does_not_imply_narrower_i4_nusw(ptr %dst, i64 %n) {
 ; CHECK-LABEL: 'wider_i32_nusw_does_not_imply_narrower_i4_nusw'
 ; CHECK-NEXT:    loop:
 ; CHECK-NEXT:      Memory dependences are safe
 ; CHECK-NEXT:      Dependences:
+; CHECK-NEXT:        Forward:
+; CHECK-NEXT:            %l.dst = load i8, ptr %gep.dst, align 1 ->
+; CHECK-NEXT:            store i8 %xor, ptr %gep.dst, align 1
+; CHECK-EMPTY:
 ; CHECK-NEXT:      Run-time memory checks:
 ; CHECK-NEXT:      Grouped accesses:
 ; CHECK-EMPTY:
 ; CHECK-NEXT:      Non vectorizable stores to invariant address were not found in loop.
 ; CHECK-NEXT:      SCEV assumptions:
 ; CHECK-NEXT:      {1,+,1}<%loop> Added Flags: <nusw>
+; CHECK-NEXT:      {0,+,1}<%loop> Added Flags: <nusw>
 ; CHECK-EMPTY:
 ; CHECK-NEXT:      Expressions re-written:
 ; CHECK-NEXT:      [PSE] %gep.dst = getelementptr inbounds nuw i8, ptr %dst, i64 %iv.mod.zext:
diff --git a/llvm/test/Transforms/LoopVectorize/runtime-check-small-clamped-bounds.ll b/llvm/test/Transforms/LoopVectorize/runtime-check-small-clamped-bounds.ll
index c3bf402071ade..c14a2495c5c3f 100644
--- a/llvm/test/Transforms/LoopVectorize/runtime-check-small-clamped-bounds.ll
+++ b/llvm/test/Transforms/LoopVectorize/runtime-check-small-clamped-bounds.ll
@@ -407,7 +407,7 @@ exit:
   ret void
 }
 
-; FIXME: NUSW on the wider i32 AddRec does no imply NUSW on a narrower i8 AddRec.
+; NUSW on the wider i32 AddRec does no imply NUSW on a narrower i8 AddRec.
 ; Test for https://github.com/llvm/llvm-project/issues/191382.
 define void @wider_nusw_does_not_imply_narrower(ptr %dst, i64 %n) {
 ; CHECK-LABEL: @wider_nusw_does_not_imply_narrower(
@@ -424,7 +424,9 @@ define void @wider_nusw_does_not_imply_narrower(ptr %dst, i64 %n) {
 ; CHECK-NEXT:    [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 1
 ; CHECK-NEXT:    [[TMP4:%.*]] = icmp ugt i64 [[TMP0]], 4294967295
 ; CHECK-NEXT:    [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP4]]
-; CHECK-NEXT:    br i1 [[TMP8]], label [[SCALAR_PH]], label [[VECTOR_MEMCHECK:%.*]]
+; CHECK-NEXT:    [[TMP7:%.*]] = icmp ugt i64 [[TMP0]], 15
+; CHECK-NEXT:    [[TMP9:%.*]] = or i1 [[TMP8]], [[TMP7]]
+; CHECK-NEXT:    br i1 [[TMP9]], label [[SCALAR_PH]], label [[VECTOR_MEMCHECK:%.*]]
 ; CHECK:       vector.ph:
 ; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i32 [[TMP5]], 4
 ; CHECK-NEXT:    [[N_VEC:%.*]] = sub i32 [[TMP5]], [[N_MOD_VF]]



More information about the llvm-commits mailing list