Skip to content

Commit a1afe66

Browse files
authored
[SCEV] Generalize (C * A /u C) -> A fold to (C1 * A /u C2) -> C1/C2 * A. (#157159)
Generalize fold added in 74ec38f (#156730) to support multiplying and dividing by different constants, given they are both powers-of-2 and C1 is a multiple of C2, checked via logBase2. https://alive2.llvm.org/ce/z/eqJ2xj PR: #157159
1 parent e741b71 commit a1afe66

File tree

2 files changed

+10
-7
lines changed

2 files changed

+10
-7
lines changed

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3216,13 +3216,16 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl<const SCEV *> &Ops,
32163216
};
32173217
}
32183218

3219-
// Try to fold (C * D /u C) -> D, if C is a power-of-2 and D is a multiple
3220-
// of C.
3219+
// Try to fold (C1 * D /u C2) -> C1/C2 * D, if C1 and C2 are powers-of-2,
3220+
// D is a multiple of C2, and C1 is a multiple of C1.
32213221
const SCEV *D;
3222-
if (match(Ops[1], m_scev_UDiv(m_SCEV(D), m_scev_Specific(LHSC))) &&
3223-
LHSC->getAPInt().isPowerOf2() &&
3224-
LHSC->getAPInt().logBase2() <= getMinTrailingZeros(D)) {
3225-
return D;
3222+
const SCEVConstant *C2;
3223+
const APInt &LHSV = LHSC->getAPInt();
3224+
if (LHSV.isPowerOf2() &&
3225+
match(Ops[1], m_scev_UDiv(m_SCEV(D), m_SCEVConstant(C2))) &&
3226+
C2->getAPInt().isPowerOf2() && LHSV.uge(C2->getAPInt()) &&
3227+
LHSV.logBase2() <= getMinTrailingZeros(D)) {
3228+
return getMulExpr(getUDivExpr(LHSC, C2), D);
32263229
}
32273230
}
32283231
}

llvm/test/Analysis/ScalarEvolution/mul-udiv-folds.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ define void @udiv4_and_udiv2(i1 %c, ptr %A) {
2323
; CHECK-NEXT: %gep.16 = getelementptr i16, ptr %A, i64 %iv
2424
; 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 }
2525
; CHECK-NEXT: %gep.32 = getelementptr i32, ptr %A, i64 %iv
26-
; 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 }
26+
; 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 }
2727
; CHECK-NEXT: %gep.40 = getelementptr <{ i32, i8 }>, ptr %A, i64 %iv
2828
; 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 }
2929
; CHECK-NEXT: %gep.48 = getelementptr <{ i32, i16 }>, ptr %A, i64 %iv

0 commit comments

Comments
 (0)