Skip to content

Commit a13c0f6

Browse files
committed
[InstSimplify] Fold x*C1/C2 <= x (PR48744)
We can fold x*C1/C2 <= x to true if C1 <= C2. This is valid even if the multiplication is not nuw: https://alive2.llvm.org/ce/z/vULors The multiplication or division can be replaced by shifts. We don't handle the case where both are shifts, as that should get folded away by InstCombine.
1 parent 4bfbfb9 commit a13c0f6

File tree

2 files changed

+29
-28
lines changed

2 files changed

+29
-28
lines changed

llvm/lib/Analysis/InstructionSimplify.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -2901,6 +2901,28 @@ static Value *simplifyICmpWithBinOpOnLHS(
29012901
return getTrue(ITy);
29022902
}
29032903

2904+
// (x*C1)/C2 <= x for C1 <= C2.
2905+
// This holds even if the multiplication overflows: Assume that x != 0 and
2906+
// arithmetic is modulo M. For overflow to occur we must have C1 >= M/x and
2907+
// thus C2 >= M/x. It follows that (x*C1)/C2 <= (M-1)/C2 <= ((M-1)*x)/M < x.
2908+
//
2909+
// Additionally, either the multiplication and division might be represented
2910+
// as shifts:
2911+
// (x*C1)>>C2 <= x for C1 < 2**C2.
2912+
// (x<<C1)/C2 <= x for 2**C1 < C2.
2913+
const APInt *C1, *C2;
2914+
if ((match(LBO, m_UDiv(m_Mul(m_Specific(RHS), m_APInt(C1)), m_APInt(C2))) &&
2915+
C1->ule(*C2)) ||
2916+
(match(LBO, m_LShr(m_Mul(m_Specific(RHS), m_APInt(C1)), m_APInt(C2))) &&
2917+
C1->ule(APInt(C2->getBitWidth(), 1) << *C2)) ||
2918+
(match(LBO, m_UDiv(m_Shl(m_Specific(RHS), m_APInt(C1)), m_APInt(C2))) &&
2919+
(APInt(C1->getBitWidth(), 1) << *C1).ule(*C2))) {
2920+
if (Pred == ICmpInst::ICMP_UGT)
2921+
return getFalse(ITy);
2922+
if (Pred == ICmpInst::ICMP_ULE)
2923+
return getTrue(ITy);
2924+
}
2925+
29042926
return nullptr;
29052927
}
29062928

llvm/test/Transforms/InstSimplify/icmp.ll

+7-28
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,7 @@ define i1 @poison2(i32 %x) {
3939

4040
define i1 @mul_div_cmp_smaller(i8 %x) {
4141
; CHECK-LABEL: @mul_div_cmp_smaller(
42-
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 3
43-
; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[MUL]], 4
44-
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
45-
; CHECK-NEXT: ret i1 [[CMP]]
42+
; CHECK-NEXT: ret i1 true
4643
;
4744
%mul = mul i8 %x, 3
4845
%div = udiv i8 %mul, 4
@@ -52,10 +49,7 @@ define i1 @mul_div_cmp_smaller(i8 %x) {
5249

5350
define i1 @mul_div_cmp_equal(i8 %x) {
5451
; CHECK-LABEL: @mul_div_cmp_equal(
55-
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 3
56-
; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[MUL]], 3
57-
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
58-
; CHECK-NEXT: ret i1 [[CMP]]
52+
; CHECK-NEXT: ret i1 true
5953
;
6054
%mul = mul i8 %x, 3
6155
%div = udiv i8 %mul, 3
@@ -78,10 +72,7 @@ define i1 @mul_div_cmp_greater(i8 %x) {
7872
}
7973
define i1 @mul_div_cmp_ugt(i8 %x) {
8074
; CHECK-LABEL: @mul_div_cmp_ugt(
81-
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 3
82-
; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[MUL]], 4
83-
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[DIV]], [[X]]
84-
; CHECK-NEXT: ret i1 [[CMP]]
75+
; CHECK-NEXT: ret i1 false
8576
;
8677
%mul = mul i8 %x, 3
8778
%div = udiv i8 %mul, 4
@@ -133,10 +124,7 @@ define i1 @mul_div_cmp_wrong_operand(i8 %x, i8 %y) {
133124

134125
define i1 @mul_lshr_cmp_smaller(i8 %x) {
135126
; CHECK-LABEL: @mul_lshr_cmp_smaller(
136-
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 3
137-
; CHECK-NEXT: [[DIV:%.*]] = lshr i8 [[MUL]], 2
138-
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
139-
; CHECK-NEXT: ret i1 [[CMP]]
127+
; CHECK-NEXT: ret i1 true
140128
;
141129
%mul = mul i8 %x, 3
142130
%div = lshr i8 %mul, 2
@@ -146,10 +134,7 @@ define i1 @mul_lshr_cmp_smaller(i8 %x) {
146134

147135
define i1 @mul_lshr_cmp_equal(i8 %x) {
148136
; CHECK-LABEL: @mul_lshr_cmp_equal(
149-
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 4
150-
; CHECK-NEXT: [[DIV:%.*]] = lshr i8 [[MUL]], 2
151-
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
152-
; CHECK-NEXT: ret i1 [[CMP]]
137+
; CHECK-NEXT: ret i1 true
153138
;
154139
%mul = mul i8 %x, 4
155140
%div = lshr i8 %mul, 2
@@ -172,10 +157,7 @@ define i1 @mul_lshr_cmp_greater(i8 %x) {
172157

173158
define i1 @shl_div_cmp_smaller(i8 %x) {
174159
; CHECK-LABEL: @shl_div_cmp_smaller(
175-
; CHECK-NEXT: [[MUL:%.*]] = shl i8 [[X:%.*]], 2
176-
; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[MUL]], 5
177-
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
178-
; CHECK-NEXT: ret i1 [[CMP]]
160+
; CHECK-NEXT: ret i1 true
179161
;
180162
%mul = shl i8 %x, 2
181163
%div = udiv i8 %mul, 5
@@ -185,10 +167,7 @@ define i1 @shl_div_cmp_smaller(i8 %x) {
185167

186168
define i1 @shl_div_cmp_equal(i8 %x) {
187169
; CHECK-LABEL: @shl_div_cmp_equal(
188-
; CHECK-NEXT: [[MUL:%.*]] = shl i8 [[X:%.*]], 2
189-
; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[MUL]], 4
190-
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
191-
; CHECK-NEXT: ret i1 [[CMP]]
170+
; CHECK-NEXT: ret i1 true
192171
;
193172
%mul = shl i8 %x, 2
194173
%div = udiv i8 %mul, 4

0 commit comments

Comments
 (0)