From 962be5d16b6d17a78140102c63f3c1dccd98597f Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 5 Sep 2025 19:54:59 +0100 Subject: [PATCH 1/4] [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 &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 2d050bf2c01379bda258ae4f6e6eec5baf8e5841 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Mon, 8 Sep 2025 14:05:31 +0100 Subject: [PATCH 2/4] !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)) + %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)) + (-4 * ((zext i32 %start to i64) /u 4)) + %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)) + (-4 * ((zext i32 %start to i64) /u 4)) + %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)) + %A),+,5}<%loop> U: full-set S: full-set Exits: ((5 * ((zext i32 %start to i64) /u 2)) + %A) LoopDispositions: { %loop: Computable } ; CHECK-NEXT: %gep.48 = getelementptr <{ i32, i16 }>, ptr %A, i64 %iv From 19ae5af3685538ba0c7d12bea532de9f19d38d05 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Mon, 8 Sep 2025 22:07:27 +0100 Subject: [PATCH 3/4] !fixup use logBase2. --- llvm/lib/Analysis/ScalarEvolution.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index f9fbcb05798da..409d8d9b878bb 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -3220,11 +3220,12 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, // D is a multiple of C2, and C1 is a multiple of C1. const SCEV *D; const SCEVConstant *C2; - if (LHSC->getAPInt().isPowerOf2() && + APInt LHSV = LHSC->getAPInt(); + if (LHSV.isPowerOf2() && match(Ops[1], m_scev_UDiv(m_SCEV(D), m_SCEVConstant(C2))) && C2->getAPInt().isPowerOf2() && - getMinTrailingZeros(LHSC) >= getMinTrailingZeros(C2) && - getMinTrailingZeros(LHSC) <= getMinTrailingZeros(D)) { + LHSV.logBase2() >= C2->getAPInt().logBase2() && + LHSV.logBase2() <= getMinTrailingZeros(D)) { return getMulExpr(getUDivExpr(LHSC, C2), D); } } From 81b23c3094db3b19b5504abc9904dd2a4ed979be Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Tue, 9 Sep 2025 09:55:36 +0100 Subject: [PATCH 4/4] !fixup address comments, thanks! --- llvm/lib/Analysis/ScalarEvolution.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index 409d8d9b878bb..34e497d9ea3cb 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -3220,11 +3220,10 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, // D is a multiple of C2, and C1 is a multiple of C1. const SCEV *D; const SCEVConstant *C2; - APInt LHSV = LHSC->getAPInt(); + const APInt &LHSV = LHSC->getAPInt(); if (LHSV.isPowerOf2() && match(Ops[1], m_scev_UDiv(m_SCEV(D), m_SCEVConstant(C2))) && - C2->getAPInt().isPowerOf2() && - LHSV.logBase2() >= C2->getAPInt().logBase2() && + C2->getAPInt().isPowerOf2() && LHSV.uge(C2->getAPInt()) && LHSV.logBase2() <= getMinTrailingZeros(D)) { return getMulExpr(getUDivExpr(LHSC, C2), D); }