[llvm] [SCEV] Generalize (C * A /u C) -> A fold to (C1 * A /u C2) -> C1/C2 * A. (PR #157159)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 8 08:13:42 PDT 2025
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/157159
>From 28df048bb5fcb1f47c68a158fcd9cc9f788f03d5 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 5 Sep 2025 19:54:59 +0100
Subject: [PATCH 1/2] [SCEV] Generalize (C * A /u C) -> A fold to (C1 * A /u
C2) -> C1/C2 * A.
Generalize fold added in 74ec38fad0a to support multiplying and dividing
by different constants, given they are both powers-of-2 and C1 is a
multiple of C2, checked via their trailing zeros.
https://alive2.llvm.org/ce/z/eqJ2xj
---
llvm/lib/Analysis/ScalarEvolution.cpp | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index bd57d1192eb94..f9fbcb05798da 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -3216,13 +3216,16 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl<const SCEV *> &Ops,
};
}
- // Try to fold (C * D /u C) -> D, if C is a power-of-2 and D is a multiple
- // of C.
+ // Try to fold (C1 * D /u C2) -> C1/C2 * D, if C1 and C2 are powers-of-2,
+ // D is a multiple of C2, and C1 is a multiple of C1.
const SCEV *D;
- if (match(Ops[1], m_scev_UDiv(m_SCEV(D), m_scev_Specific(LHSC))) &&
- LHSC->getAPInt().isPowerOf2() &&
- LHSC->getAPInt().logBase2() <= getMinTrailingZeros(D)) {
- return D;
+ const SCEVConstant *C2;
+ if (LHSC->getAPInt().isPowerOf2() &&
+ match(Ops[1], m_scev_UDiv(m_SCEV(D), m_SCEVConstant(C2))) &&
+ C2->getAPInt().isPowerOf2() &&
+ getMinTrailingZeros(LHSC) >= getMinTrailingZeros(C2) &&
+ getMinTrailingZeros(LHSC) <= getMinTrailingZeros(D)) {
+ return getMulExpr(getUDivExpr(LHSC, C2), D);
}
}
}
>From a06fe6f79ba21d6ea2a652338df52e3e574c9f8a Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 8 Sep 2025 14:05:31 +0100
Subject: [PATCH 2/2] !fixup update test
---
llvm/test/Analysis/ScalarEvolution/mul-udiv-folds.ll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/Analysis/ScalarEvolution/mul-udiv-folds.ll b/llvm/test/Analysis/ScalarEvolution/mul-udiv-folds.ll
index b5d976ba3acda..dfaf0c95bc2f8 100644
--- a/llvm/test/Analysis/ScalarEvolution/mul-udiv-folds.ll
+++ b/llvm/test/Analysis/ScalarEvolution/mul-udiv-folds.ll
@@ -23,7 +23,7 @@ define void @udiv4_and_udiv2(i1 %c, ptr %A) {
; CHECK-NEXT: %gep.16 = getelementptr i16, ptr %A, i64 %iv
; CHECK-NEXT: --> {((2 * ((zext i32 %start to i64) /u 4))<nuw><nsw> + %A),+,2}<%loop> U: full-set S: full-set Exits: ((zext i32 %start to i64) + %A) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %gep.32 = getelementptr i32, ptr %A, i64 %iv
-; CHECK-NEXT: --> {((zext i32 %start to i64) + %A),+,4}<%loop> U: full-set S: full-set Exits: ((zext i32 %start to i64) + (4 * ((zext i32 %start to i64) /u 2))<nuw><nsw> + (-4 * ((zext i32 %start to i64) /u 4))<nsw> + %A) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {((zext i32 %start to i64) + %A),+,4}<%loop> U: full-set S: full-set Exits: ((3 * (zext i32 %start to i64))<nuw><nsw> + (-4 * ((zext i32 %start to i64) /u 4))<nsw> + %A) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %gep.40 = getelementptr <{ i32, i8 }>, ptr %A, i64 %iv
; CHECK-NEXT: --> {((5 * ((zext i32 %start to i64) /u 4))<nuw><nsw> + %A),+,5}<%loop> U: full-set S: full-set Exits: ((5 * ((zext i32 %start to i64) /u 2))<nuw><nsw> + %A) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %gep.48 = getelementptr <{ i32, i16 }>, ptr %A, i64 %iv
More information about the llvm-commits
mailing list