[llvm] [VPlan] Support URem in getSCEVExprForVPValue. (PR #199794)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Thu May 28 12:51:09 PDT 2026
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/199794
>From 4bb1fe22da332470c1c139b1daa07e771c9b4108 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 23 May 2026 14:01:51 +0100
Subject: [PATCH 1/2] [VPlan] Support URem in getSCEVExprForVPValue.
Extend vputils::getSCEVExprForVPValue to construct SCEV expressions for
URem recipes.
Enables SCEV-based no-alias reasoning for stores derived from urem GEPs.
---
llvm/lib/Transforms/Vectorize/VPlanUtils.cpp | 5 ++++
...predicated-loads-with-predicated-stores.ll | 30 +++++--------------
2 files changed, 12 insertions(+), 23 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
index 9750cba584f82..548c54416460d 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
@@ -216,6 +216,11 @@ const SCEV *vputils::getSCEVExprForVPValue(const VPValue *V,
return CreateSCEV({LHSVal, RHSVal}, [&](ArrayRef<SCEVUse> Ops) {
return SE.getUDivExpr(Ops[0], Ops[1]);
});
+ if (match(V,
+ m_Binary<Instruction::URem>(m_VPValue(LHSVal), m_VPValue(RHSVal))))
+ return CreateSCEV({LHSVal, RHSVal}, [&](ArrayRef<SCEVUse> Ops) {
+ return SE.getURemExpr(Ops[0], Ops[1]);
+ });
// Handle AND with constant mask: x & (2^n - 1) can be represented as x % 2^n.
const APInt *Mask;
if (match(V, m_c_BinaryAnd(m_VPValue(LHSVal), m_APInt(Mask))) &&
diff --git a/llvm/test/Transforms/LoopVectorize/hoist-predicated-loads-with-predicated-stores.ll b/llvm/test/Transforms/LoopVectorize/hoist-predicated-loads-with-predicated-stores.ll
index f930e5017e663..ff5824473bb16 100644
--- a/llvm/test/Transforms/LoopVectorize/hoist-predicated-loads-with-predicated-stores.ll
+++ b/llvm/test/Transforms/LoopVectorize/hoist-predicated-loads-with-predicated-stores.ll
@@ -966,32 +966,19 @@ define void @sink_multiple_store_groups_noalias_via_scev_urem(ptr %dst, ptr %src
; CHECK-NEXT: [[TMP13:%.*]] = insertelement <2 x double> poison, double [[TMP11]], i32 0
; CHECK-NEXT: [[TMP14:%.*]] = insertelement <2 x double> [[TMP13]], double [[TMP12]], i32 1
; CHECK-NEXT: [[TMP15:%.*]] = urem <2 x i64> [[VEC_IND]], splat (i64 128)
-; CHECK-NEXT: [[TMP16:%.*]] = xor <2 x i1> [[TMP10]], splat (i1 true)
-; CHECK-NEXT: [[TMP18:%.*]] = fadd <2 x double> [[TMP14]], splat (double 8.000000e+00)
-; CHECK-NEXT: [[TMP29:%.*]] = extractelement <2 x i1> [[TMP16]], i64 0
-; CHECK-NEXT: br i1 [[TMP29]], label %[[PRED_STORE_IF1:.*]], label %[[PRED_STORE_CONTINUE1:.*]]
-; CHECK: [[PRED_STORE_IF1]]:
; CHECK-NEXT: [[TMP17:%.*]] = extractelement <2 x i64> [[TMP15]], i64 0
-; CHECK-NEXT: [[TMP20:%.*]] = getelementptr double, ptr [[DST]], i64 [[TMP17]]
-; CHECK-NEXT: [[TMP21:%.*]] = extractelement <2 x double> [[TMP18]], i64 0
-; CHECK-NEXT: store double [[TMP21]], ptr [[TMP20]], align 8, !alias.scope [[META95]]
-; CHECK-NEXT: br label %[[PRED_STORE_CONTINUE1]]
-; CHECK: [[PRED_STORE_CONTINUE1]]:
-; CHECK-NEXT: [[TMP22:%.*]] = extractelement <2 x i1> [[TMP16]], i64 1
-; CHECK-NEXT: br i1 [[TMP22]], label %[[PRED_STORE_IF3:.*]], label %[[PRED_STORE_CONTINUE4:.*]]
-; CHECK: [[PRED_STORE_IF3]]:
; CHECK-NEXT: [[TMP23:%.*]] = extractelement <2 x i64> [[TMP15]], i64 1
-; CHECK-NEXT: [[TMP30:%.*]] = getelementptr double, ptr [[DST]], i64 [[TMP23]]
+; CHECK-NEXT: [[TMP20:%.*]] = fadd <2 x double> [[TMP14]], splat (double 8.000000e+00)
+; CHECK-NEXT: [[TMP19:%.*]] = getelementptr double, ptr [[DST]], i64 [[TMP17]]
+; CHECK-NEXT: [[TMP32:%.*]] = getelementptr double, ptr [[DST]], i64 [[TMP23]]
+; CHECK-NEXT: [[TMP18:%.*]] = select <2 x i1> [[TMP10]], <2 x double> [[TMP14]], <2 x double> [[TMP20]]
+; CHECK-NEXT: [[TMP22:%.*]] = extractelement <2 x double> [[TMP18]], i64 0
+; CHECK-NEXT: store double [[TMP22]], ptr [[TMP19]], align 8, !alias.scope [[META95]]
; CHECK-NEXT: [[TMP34:%.*]] = extractelement <2 x double> [[TMP18]], i64 1
-; CHECK-NEXT: store double [[TMP34]], ptr [[TMP30]], align 8, !alias.scope [[META95]]
-; CHECK-NEXT: br label %[[PRED_STORE_CONTINUE4]]
-; CHECK: [[PRED_STORE_CONTINUE4]]:
+; CHECK-NEXT: store double [[TMP34]], ptr [[TMP32]], align 8, !alias.scope [[META95]]
; CHECK-NEXT: [[TMP24:%.*]] = extractelement <2 x i1> [[TMP10]], i64 0
; CHECK-NEXT: br i1 [[TMP24]], label %[[PRED_STORE_IF:.*]], label %[[PRED_STORE_CONTINUE:.*]]
; CHECK: [[PRED_STORE_IF]]:
-; CHECK-NEXT: [[TMP27:%.*]] = extractelement <2 x i64> [[TMP15]], i64 0
-; CHECK-NEXT: [[TMP19:%.*]] = getelementptr double, ptr [[DST]], i64 [[TMP27]]
-; CHECK-NEXT: store double [[TMP11]], ptr [[TMP19]], align 8, !alias.scope [[META95]]
; CHECK-NEXT: [[TMP25:%.*]] = getelementptr i8, ptr [[TMP19]], i64 16
; CHECK-NEXT: store double 1.000000e+01, ptr [[TMP25]], align 8, !alias.scope [[META95]]
; CHECK-NEXT: br label %[[PRED_STORE_CONTINUE]]
@@ -999,9 +986,6 @@ define void @sink_multiple_store_groups_noalias_via_scev_urem(ptr %dst, ptr %src
; CHECK-NEXT: [[TMP26:%.*]] = extractelement <2 x i1> [[TMP10]], i64 1
; CHECK-NEXT: br i1 [[TMP26]], label %[[PRED_STORE_IF2:.*]], label %[[PRED_STORE_CONTINUE3]]
; CHECK: [[PRED_STORE_IF2]]:
-; CHECK-NEXT: [[TMP31:%.*]] = extractelement <2 x i64> [[TMP15]], i64 1
-; CHECK-NEXT: [[TMP32:%.*]] = getelementptr double, ptr [[DST]], i64 [[TMP31]]
-; CHECK-NEXT: store double [[TMP12]], ptr [[TMP32]], align 8, !alias.scope [[META95]]
; CHECK-NEXT: [[TMP33:%.*]] = getelementptr i8, ptr [[TMP32]], i64 16
; CHECK-NEXT: store double 1.000000e+01, ptr [[TMP33]], align 8, !alias.scope [[META95]]
; CHECK-NEXT: br label %[[PRED_STORE_CONTINUE3]]
>From 6f82024e4f8a1269b348133ef9670014f540e82e Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 28 May 2026 20:45:57 +0100
Subject: [PATCH 2/2] !fixup use pattern matching, thanks
---
llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h | 6 ++++++
llvm/lib/Transforms/Vectorize/VPlanUtils.cpp | 6 ++----
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
index 5f7419aec25d5..395aae7c1ef5c 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
@@ -630,6 +630,12 @@ m_UDiv(const Op0_t &Op0, const Op1_t &Op1) {
return m_Binary<Instruction::UDiv, Op0_t, Op1_t>(Op0, Op1);
}
+template <typename Op0_t, typename Op1_t>
+inline AllRecipe_match<Instruction::URem, Op0_t, Op1_t>
+m_URem(const Op0_t &Op0, const Op1_t &Op1) {
+ return m_Binary<Instruction::URem, Op0_t, Op1_t>(Op0, Op1);
+}
+
/// Match a binary AND operation.
template <typename Op0_t, typename Op1_t>
inline AllRecipe_commutative_match<Instruction::And, Op0_t, Op1_t>
diff --git a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
index f2d1e9302b880..3863c329beeb1 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanUtils.cpp
@@ -216,13 +216,11 @@ const SCEV *vputils::getSCEVExprForVPValue(const VPValue *V,
return CreateSCEV({LHSVal, RHSVal}, [&](ArrayRef<SCEVUse> Ops) {
return SE.getMulExpr(Ops[0], Ops[1], SCEV::FlagAnyWrap, 0);
});
- if (match(V,
- m_Binary<Instruction::UDiv>(m_VPValue(LHSVal), m_VPValue(RHSVal))))
+ if (match(V, m_UDiv(m_VPValue(LHSVal), m_VPValue(RHSVal))))
return CreateSCEV({LHSVal, RHSVal}, [&](ArrayRef<SCEVUse> Ops) {
return SE.getUDivExpr(Ops[0], Ops[1]);
});
- if (match(V,
- m_Binary<Instruction::URem>(m_VPValue(LHSVal), m_VPValue(RHSVal))))
+ if (match(V, m_URem(m_VPValue(LHSVal), m_VPValue(RHSVal))))
return CreateSCEV({LHSVal, RHSVal}, [&](ArrayRef<SCEVUse> Ops) {
return SE.getURemExpr(Ops[0], Ops[1]);
});
More information about the llvm-commits
mailing list