Skip to content

Commit e80f489

Browse files
[SCEV] BECount to zero if ((-C + (C smax %x)) /u %x), C > 0 holds
The SCEV expression `((-C + (C smax %x)) /u %x)` can be folded to zero for any positive constant C. Proof: https://alive2.llvm.org/ce/z/_dLm8C.
1 parent 3b19e48 commit e80f489

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3547,6 +3547,22 @@ const SCEV *ScalarEvolution::getUDivExpr(const SCEV *LHS,
35473547
}
35483548
}
35493549

3550+
// ((-C + (C smax %x)) /u %x) evaluates to zero, for any positive constant C.
3551+
if (const auto *AE = dyn_cast<SCEVAddExpr>(LHS);
3552+
AE && AE->getNumOperands() == 2) {
3553+
if (const auto *VC = dyn_cast<SCEVConstant>(AE->getOperand(0))) {
3554+
const APInt &NegC = VC->getAPInt();
3555+
if (NegC.isNegative() && !NegC.isMinSignedValue()) {
3556+
const auto *MME = dyn_cast<SCEVSMaxExpr>(AE->getOperand(1));
3557+
if (MME && MME->getNumOperands() == 2 &&
3558+
isa<SCEVConstant>(MME->getOperand(0)) &&
3559+
cast<SCEVConstant>(MME->getOperand(0))->getAPInt() == -NegC &&
3560+
MME->getOperand(1) == RHS)
3561+
return getZero(LHS->getType());
3562+
}
3563+
}
3564+
}
3565+
35503566
// The Insertion Point (IP) might be invalid by now (due to UniqueSCEVs
35513567
// changes). Make sure we get a new one.
35523568
IP = nullptr;
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
2+
; RUN: opt -disable-output -passes="print<scalar-evolution>" < %s 2>&1 | FileCheck %s
3+
4+
define i32 @test_expr_with_constant_1(i32 %x) {
5+
; CHECK-LABEL: 'test_expr_with_constant_1'
6+
; CHECK-NEXT: Classifying expressions for: @test_expr_with_constant_1
7+
; CHECK-NEXT: %smax = tail call i32 @llvm.smax.i32(i32 %x, i32 1)
8+
; CHECK-NEXT: --> (1 smax %x) U: [1,-2147483648) S: [1,-2147483648)
9+
; CHECK-NEXT: %add = add nsw i32 %smax, -1
10+
; CHECK-NEXT: --> (-1 + (1 smax %x))<nsw> U: [0,2147483647) S: [0,2147483647)
11+
; CHECK-NEXT: %udiv = udiv i32 %add, %x
12+
; CHECK-NEXT: --> 0 U: [0,1) S: [0,1)
13+
; CHECK-NEXT: Determining loop execution counts for: @test_expr_with_constant_1
14+
;
15+
entry:
16+
%smax = tail call i32 @llvm.smax.i32(i32 %x, i32 1)
17+
%add = add nsw i32 %smax, -1
18+
%udiv = udiv i32 %add, %x
19+
ret i32 %udiv
20+
}
21+
22+
; Non-1 constant: (-2 + (2 smax %x)) /u %x
23+
define i32 @test_expr_with_constant_2(i32 %x) {
24+
; CHECK-LABEL: 'test_expr_with_constant_2'
25+
; CHECK-NEXT: Classifying expressions for: @test_expr_with_constant_2
26+
; CHECK-NEXT: %smax = tail call i32 @llvm.smax.i32(i32 %x, i32 2)
27+
; CHECK-NEXT: --> (2 smax %x) U: [2,-2147483648) S: [2,-2147483648)
28+
; CHECK-NEXT: %add = add nsw i32 %smax, -2
29+
; CHECK-NEXT: --> (-2 + (2 smax %x))<nsw> U: [0,2147483646) S: [0,2147483646)
30+
; CHECK-NEXT: %udiv = udiv i32 %add, %x
31+
; CHECK-NEXT: --> 0 U: [0,1) S: [0,1)
32+
; CHECK-NEXT: Determining loop execution counts for: @test_expr_with_constant_2
33+
;
34+
entry:
35+
%smax = tail call i32 @llvm.smax.i32(i32 %x, i32 2)
36+
%add = add nsw i32 %smax, -2
37+
%udiv = udiv i32 %add, %x
38+
ret i32 %udiv
39+
}
40+
41+
; Negative test, constants mismatch: (-3 + (2 smax %x)) /u %x
42+
define i32 @test_expr_mismatch_constants(i32 %x) {
43+
; CHECK-LABEL: 'test_expr_mismatch_constants'
44+
; CHECK-NEXT: Classifying expressions for: @test_expr_mismatch_constants
45+
; CHECK-NEXT: %smax = tail call i32 @llvm.smax.i32(i32 %x, i32 2)
46+
; CHECK-NEXT: --> (2 smax %x) U: [2,-2147483648) S: [2,-2147483648)
47+
; CHECK-NEXT: %add = add nsw i32 %smax, -3
48+
; CHECK-NEXT: --> (-3 + (2 smax %x))<nsw> U: [-1,2147483645) S: [-1,2147483645)
49+
; CHECK-NEXT: %udiv = udiv i32 %add, %x
50+
; CHECK-NEXT: --> ((-3 + (2 smax %x))<nsw> /u %x) U: full-set S: full-set
51+
; CHECK-NEXT: Determining loop execution counts for: @test_expr_mismatch_constants
52+
;
53+
entry:
54+
%smax = tail call i32 @llvm.smax.i32(i32 %x, i32 2)
55+
%add = add nsw i32 %smax, -3
56+
%udiv = udiv i32 %add, %x
57+
ret i32 %udiv
58+
}
59+
60+
; Negative constant: (3 + (-3 smax %x)) /u %x
61+
define i32 @test_expr_negative_constant(i32 %x) {
62+
; CHECK-LABEL: 'test_expr_negative_constant'
63+
; CHECK-NEXT: Classifying expressions for: @test_expr_negative_constant
64+
; CHECK-NEXT: %smax = tail call i32 @llvm.smax.i32(i32 %x, i32 -3)
65+
; CHECK-NEXT: --> (-3 smax %x) U: [-3,-2147483648) S: [-3,-2147483648)
66+
; CHECK-NEXT: %add = add nsw i32 %smax, 3
67+
; CHECK-NEXT: --> (3 + (-3 smax %x)) U: [0,-2147483645) S: [0,-2147483645)
68+
; CHECK-NEXT: %udiv = udiv i32 %add, %x
69+
; CHECK-NEXT: --> ((3 + (-3 smax %x)) /u %x) U: [0,-2147483645) S: [0,-2147483645)
70+
; CHECK-NEXT: Determining loop execution counts for: @test_expr_negative_constant
71+
;
72+
entry:
73+
%smax = tail call i32 @llvm.smax.i32(i32 %x, i32 -3)
74+
%add = add nsw i32 %smax, 3
75+
%udiv = udiv i32 %add, %x
76+
ret i32 %udiv
77+
}
78+
79+
; Negative signed minimum value.
80+
define i8 @text_expr_with_constant_signed_min(i8 %x) {
81+
; CHECK-LABEL: 'text_expr_with_constant_signed_min'
82+
; CHECK-NEXT: Classifying expressions for: @text_expr_with_constant_signed_min
83+
; CHECK-NEXT: %smax = tail call i8 @llvm.smax.i8(i8 %x, i8 -128)
84+
; CHECK-NEXT: --> %x U: full-set S: full-set
85+
; CHECK-NEXT: %add = add nsw i8 %smax, -128
86+
; CHECK-NEXT: --> (-128 + %x) U: full-set S: full-set
87+
; CHECK-NEXT: %udiv = udiv i8 %add, %x
88+
; CHECK-NEXT: --> ((-128 + %x) /u %x) U: full-set S: full-set
89+
; CHECK-NEXT: Determining loop execution counts for: @text_expr_with_constant_signed_min
90+
;
91+
entry:
92+
%smax = tail call i8 @llvm.smax.i8(i8 %x, i8 128)
93+
%add = add nsw i8 %smax, -128
94+
%udiv = udiv i8 %add, %x
95+
ret i8 %udiv
96+
}

0 commit comments

Comments
 (0)