Skip to content

Commit ab83673

Browse files
committed
[InstCombine] Fold (a (s/u)% b) (s/u)(le/ge/lt/gt) (b (-/+) 1)
1 parent d7dcc05 commit ab83673

File tree

3 files changed

+75
-28
lines changed

3 files changed

+75
-28
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2519,6 +2519,30 @@ Instruction *InstCombinerImpl::foldICmpShrConstant(ICmpInst &Cmp,
25192519
Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp,
25202520
BinaryOperator *SRem,
25212521
const APInt &C) {
2522+
{
2523+
const APInt *C1;
2524+
ICmpInst::Predicate Pred = Cmp.getPredicate();
2525+
if ((match(SRem->getOperand(1), m_NonNegative(C1))) &&
2526+
((Pred == ICmpInst::ICMP_SLT && C == *C1 - 1) ||
2527+
(Pred == ICmpInst::ICMP_SGT && C == *C1 - 2) ||
2528+
(Pred == ICmpInst::ICMP_SGT && C == -*C1 + 1) ||
2529+
(Pred == ICmpInst::ICMP_SLT && C == -*C1 + 2))) {
2530+
// icmp slt (X s% C), (C - 1) --> icmp ne (X s% C), (C - 1), if C >= 0
2531+
// icmp sgt (X s% C), (C - 2) --> icmp eq (X s% C), (C - 1), if C >= 0
2532+
// icmp sgt (X s% C), (-C + 1) --> icmp ne (X s% C), (-C + 1), if C >= 0
2533+
// icmp slt (X s% C), (-C + 2) --> icmp eq (X s% C), (-C + 1), if C >= 0
2534+
return new ICmpInst(
2535+
((Pred == ICmpInst::ICMP_SLT && C == *C1 - 1) ||
2536+
(Pred == ICmpInst::ICMP_SGT && C == -*C1 + 1))
2537+
? ICmpInst::ICMP_NE
2538+
: ICmpInst::ICMP_EQ,
2539+
SRem,
2540+
ConstantInt::get(SRem->getType(), C == -*C1 + 1 || C == -*C1 + 2
2541+
? -*C1 + 1
2542+
: *C1 - 1));
2543+
}
2544+
}
2545+
25222546
// Match an 'is positive' or 'is negative' comparison of remainder by a
25232547
// constant power-of-2 value:
25242548
// (X % pow2C) sgt/slt 0
@@ -2566,6 +2590,23 @@ Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp,
25662590
return new ICmpInst(ICmpInst::ICMP_UGT, And, ConstantInt::get(Ty, SignMask));
25672591
}
25682592

2593+
Instruction *InstCombinerImpl::foldICmpURemConstant(ICmpInst &Cmp,
2594+
BinaryOperator *URem,
2595+
const APInt &C) {
2596+
const APInt *C1;
2597+
ICmpInst::Predicate Pred = Cmp.getPredicate();
2598+
if (match(URem->getOperand(1), m_APInt(C1)) &&
2599+
((Pred == ICmpInst::ICMP_ULT && C == *C1 - 1) ||
2600+
(Pred == ICmpInst::ICMP_UGT && C == *C1 - 2 && C.ugt(1)))) {
2601+
// icmp ult (X u% C), (C - 1) --> icmp ne (X u% C), (C - 1)
2602+
// icmp ugt (X u% C), (C - 2) --> icmp eq (X u% C), (C - 1), if C >u 1
2603+
return new ICmpInst(Pred == ICmpInst::ICMP_UGT ? ICmpInst::ICMP_EQ
2604+
: ICmpInst::ICMP_NE,
2605+
URem, ConstantInt::get(URem->getType(), *C1 - 1));
2606+
}
2607+
return nullptr;
2608+
}
2609+
25692610
/// Fold icmp (udiv X, Y), C.
25702611
Instruction *InstCombinerImpl::foldICmpUDivConstant(ICmpInst &Cmp,
25712612
BinaryOperator *UDiv,
@@ -3703,6 +3744,10 @@ Instruction *InstCombinerImpl::foldICmpBinOpWithConstant(ICmpInst &Cmp,
37033744
if (Instruction *I = foldICmpSRemConstant(Cmp, BO, C))
37043745
return I;
37053746
break;
3747+
case Instruction::URem:
3748+
if (Instruction *I = foldICmpURemConstant(Cmp, BO, C))
3749+
return I;
3750+
break;
37063751
case Instruction::UDiv:
37073752
if (Instruction *I = foldICmpUDivConstant(Cmp, BO, C))
37083753
return I;

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
663663
const APInt &C);
664664
Instruction *foldICmpSRemConstant(ICmpInst &Cmp, BinaryOperator *UDiv,
665665
const APInt &C);
666+
Instruction *foldICmpURemConstant(ICmpInst &Cmp, BinaryOperator *UDiv,
667+
const APInt &C);
666668
Instruction *foldICmpUDivConstant(ICmpInst &Cmp, BinaryOperator *UDiv,
667669
const APInt &C);
668670
Instruction *foldICmpDivConstant(ICmpInst &Cmp, BinaryOperator *Div,

llvm/test/Transforms/InstCombine/icmp.ll

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ declare void @use_i64(i64)
1414
define i1 @srem_sgt_test1(i64 %x) {
1515
; CHECK-LABEL: @srem_sgt_test1(
1616
; CHECK-NEXT: [[Y:%.*]] = srem i64 [[X:%.*]], 34360750831
17-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[Y]], 34360750829
17+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y]], 34360750830
1818
; CHECK-NEXT: ret i1 [[CMP]]
1919
;
2020
%y = srem i64 %x, 34360750831
@@ -25,7 +25,7 @@ define i1 @srem_sgt_test1(i64 %x) {
2525
define i1 @srem_slt_test1(i64 %x) {
2626
; CHECK-LABEL: @srem_slt_test1(
2727
; CHECK-NEXT: [[Y:%.*]] = srem i64 [[X:%.*]], 34360750831
28-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[Y]], 34360750830
28+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[Y]], 34360750830
2929
; CHECK-NEXT: ret i1 [[CMP]]
3030
;
3131
%y = srem i64 %x, 34360750831
@@ -36,7 +36,7 @@ define i1 @srem_slt_test1(i64 %x) {
3636
define i1 @srem_sgt_test2(i32 %x) {
3737
; CHECK-LABEL: @srem_sgt_test2(
3838
; CHECK-NEXT: [[Y:%.*]] = srem i32 [[X:%.*]], 1074977277
39-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[Y]], 1074977275
39+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[Y]], 1074977276
4040
; CHECK-NEXT: ret i1 [[CMP]]
4141
;
4242
%y = srem i32 %x, 1074977277
@@ -47,7 +47,7 @@ define i1 @srem_sgt_test2(i32 %x) {
4747
define i1 @srem_slt_test2(i32 %x) {
4848
; CHECK-LABEL: @srem_slt_test2(
4949
; CHECK-NEXT: [[Y:%.*]] = srem i32 [[X:%.*]], 1074977277
50-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[Y]], 1074977276
50+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[Y]], 1074977276
5151
; CHECK-NEXT: ret i1 [[CMP]]
5252
;
5353
%y = srem i32 %x, 1074977277
@@ -58,7 +58,7 @@ define i1 @srem_slt_test2(i32 %x) {
5858
define i1 @srem_sgt_test3(i16 %x) {
5959
; CHECK-LABEL: @srem_sgt_test3(
6060
; CHECK-NEXT: [[Y:%.*]] = srem i16 [[X:%.*]], 2259
61-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i16 [[Y]], 2257
61+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[Y]], 2258
6262
; CHECK-NEXT: ret i1 [[CMP]]
6363
;
6464
%y = srem i16 %x, 2259
@@ -69,7 +69,7 @@ define i1 @srem_sgt_test3(i16 %x) {
6969
define i1 @srem_slt_test3(i16 %x) {
7070
; CHECK-LABEL: @srem_slt_test3(
7171
; CHECK-NEXT: [[Y:%.*]] = srem i16 [[X:%.*]], 2259
72-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[Y]], 2258
72+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i16 [[Y]], 2258
7373
; CHECK-NEXT: ret i1 [[CMP]]
7474
;
7575
%y = srem i16 %x, 2259
@@ -80,7 +80,7 @@ define i1 @srem_slt_test3(i16 %x) {
8080
define i1 @srem_sgt_test4(i8 %x) {
8181
; CHECK-LABEL: @srem_sgt_test4(
8282
; CHECK-NEXT: [[Y:%.*]] = srem i8 [[X:%.*]], 50
83-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[Y]], 48
83+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[Y]], 49
8484
; CHECK-NEXT: ret i1 [[CMP]]
8585
;
8686
%y = srem i8 %x, 50
@@ -91,7 +91,7 @@ define i1 @srem_sgt_test4(i8 %x) {
9191
define i1 @srem_slt_test4(i8 %x) {
9292
; CHECK-LABEL: @srem_slt_test4(
9393
; CHECK-NEXT: [[Y:%.*]] = srem i8 [[X:%.*]], 50
94-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[Y]], 49
94+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[Y]], 49
9595
; CHECK-NEXT: ret i1 [[CMP]]
9696
;
9797
%y = srem i8 %x, 50
@@ -101,8 +101,8 @@ define i1 @srem_slt_test4(i8 %x) {
101101

102102
define i1 @test_srem_slt_constant(i32 %a) {
103103
; CHECK-LABEL: @test_srem_slt_constant(
104-
; CHECK-NEXT: [[Y:%.*]] = srem i32 [[A:%.*]], 512
105-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[Y]], 511
104+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], -2147483137
105+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP1]], 511
106106
; CHECK-NEXT: ret i1 [[CMP]]
107107
;
108108
%y = srem i32 %a, 512
@@ -112,8 +112,8 @@ define i1 @test_srem_slt_constant(i32 %a) {
112112

113113
define i1 @test_srem_sgt_constant(i32 %a) {
114114
; CHECK-LABEL: @test_srem_sgt_constant(
115-
; CHECK-NEXT: [[Y:%.*]] = srem i32 [[A:%.*]], 512
116-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[Y]], 510
115+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], -2147483137
116+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 511
117117
; CHECK-NEXT: ret i1 [[CMP]]
118118
;
119119
%y = srem i32 %a, 512
@@ -123,8 +123,8 @@ define i1 @test_srem_sgt_constant(i32 %a) {
123123

124124
define <2 x i1> @test_srem_slt_constant_splat(<2 x i32> %a) {
125125
; CHECK-LABEL: @test_srem_slt_constant_splat(
126-
; CHECK-NEXT: [[Y:%.*]] = srem <2 x i32> [[A:%.*]], <i32 512, i32 512>
127-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i32> [[Y]], <i32 511, i32 511>
126+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 -2147483137, i32 -2147483137>
127+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[TMP1]], <i32 511, i32 511>
128128
; CHECK-NEXT: ret <2 x i1> [[CMP]]
129129
;
130130
%y = srem <2 x i32> %a, <i32 512, i32 512>
@@ -134,8 +134,8 @@ define <2 x i1> @test_srem_slt_constant_splat(<2 x i32> %a) {
134134

135135
define <2 x i1> @test_srem_sgt_constant_splat(<2 x i32> %a) {
136136
; CHECK-LABEL: @test_srem_sgt_constant_splat(
137-
; CHECK-NEXT: [[Y:%.*]] = srem <2 x i32> [[A:%.*]], <i32 512, i32 512>
138-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i32> [[Y]], <i32 510, i32 510>
137+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 -2147483137, i32 -2147483137>
138+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 511, i32 511>
139139
; CHECK-NEXT: ret <2 x i1> [[CMP]]
140140
;
141141
%y = srem <2 x i32> %a, <i32 512, i32 512>
@@ -147,7 +147,7 @@ define <2 x i1> @test_srem_sgt_constant_splat(<2 x i32> %a) {
147147
define i1 @srem_sgt_test(i16 %x) {
148148
; CHECK-LABEL: @srem_sgt_test(
149149
; CHECK-NEXT: [[Y:%.*]] = srem i16 [[X:%.*]], 2259
150-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i16 [[Y]], -2258
150+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i16 [[Y]], -2258
151151
; CHECK-NEXT: ret i1 [[CMP]]
152152
;
153153
%y = srem i16 %x, -2259
@@ -158,7 +158,7 @@ define i1 @srem_sgt_test(i16 %x) {
158158
define i1 @srem_sle_test(i16 %x) {
159159
; CHECK-LABEL: @srem_sle_test(
160160
; CHECK-NEXT: [[Y:%.*]] = srem i16 [[X:%.*]], 2259
161-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[Y]], -2257
161+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[Y]], -2258
162162
; CHECK-NEXT: ret i1 [[CMP]]
163163
;
164164
%y = srem i16 %x, -2259
@@ -169,7 +169,7 @@ define i1 @srem_sle_test(i16 %x) {
169169
define <2 x i1> @test_srem_sgt_constant_splat_neg(<2 x i32> %a) {
170170
; CHECK-LABEL: @test_srem_sgt_constant_splat_neg(
171171
; CHECK-NEXT: [[Y:%.*]] = srem <2 x i32> [[A:%.*]], <i32 512, i32 512>
172-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i32> [[Y]], <i32 -511, i32 -511>
172+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[Y]], <i32 -511, i32 -511>
173173
; CHECK-NEXT: ret <2 x i1> [[CMP]]
174174
;
175175
%y = srem <2 x i32> %a, <i32 -512, i32 -512>
@@ -180,7 +180,7 @@ define <2 x i1> @test_srem_sgt_constant_splat_neg(<2 x i32> %a) {
180180
define <2 x i1> @test_srem_slt_constant_splat_neg(<2 x i32> %a) {
181181
; CHECK-LABEL: @test_srem_slt_constant_splat_neg(
182182
; CHECK-NEXT: [[Y:%.*]] = srem <2 x i32> [[A:%.*]], <i32 512, i32 512>
183-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i32> [[Y]], <i32 -510, i32 -510>
183+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[Y]], <i32 -511, i32 -511>
184184
; CHECK-NEXT: ret <2 x i1> [[CMP]]
185185
;
186186
%y = srem <2 x i32> %a, <i32 -512, i32 -512>
@@ -192,7 +192,7 @@ define <2 x i1> @test_srem_slt_constant_splat_neg(<2 x i32> %a) {
192192
define i1 @test_urem_slt(i32 %x) {
193193
; CHECK-LABEL: @test_urem_slt(
194194
; CHECK-NEXT: [[Y:%.*]] = urem i32 [[X:%.*]], 12235
195-
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[Y]], 12234
195+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[Y]], 12234
196196
; CHECK-NEXT: ret i1 [[CMP]]
197197
;
198198
%y = urem i32 %x, 12235
@@ -203,7 +203,7 @@ define i1 @test_urem_slt(i32 %x) {
203203
define i1 @test_urem_sge(i32 %x) {
204204
; CHECK-LABEL: @test_urem_sge(
205205
; CHECK-NEXT: [[Y:%.*]] = urem i32 [[X:%.*]], 13546
206-
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[Y]], 13544
206+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[Y]], 13545
207207
; CHECK-NEXT: ret i1 [[CMP]]
208208
;
209209
%y = urem i32 %x, 13546
@@ -214,7 +214,7 @@ define i1 @test_urem_sge(i32 %x) {
214214
define i1 @test_urem_uge(i32 %x) {
215215
; CHECK-LABEL: @test_urem_uge(
216216
; CHECK-NEXT: [[Y:%.*]] = urem i32 [[X:%.*]], 18642
217-
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[Y]], 18640
217+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[Y]], 18641
218218
; CHECK-NEXT: ret i1 [[CMP]]
219219
;
220220
%y = urem i32 %x, 18642
@@ -225,7 +225,7 @@ define i1 @test_urem_uge(i32 %x) {
225225
define i1 @test_urem_ult(i32 %x) {
226226
; CHECK-LABEL: @test_urem_ult(
227227
; CHECK-NEXT: [[Y:%.*]] = urem i32 [[X:%.*]], 15344
228-
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[Y]], 15343
228+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[Y]], 15343
229229
; CHECK-NEXT: ret i1 [[CMP]]
230230
;
231231
%y = urem i32 %x, 15344
@@ -235,8 +235,8 @@ define i1 @test_urem_ult(i32 %x) {
235235

236236
define <2 x i1> @test_urem_slt_constant_splat(<2 x i32> %a) {
237237
; CHECK-LABEL: @test_urem_slt_constant_splat(
238-
; CHECK-NEXT: [[Y:%.*]] = srem <2 x i32> [[A:%.*]], <i32 512, i32 512>
239-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i32> [[Y]], <i32 511, i32 511>
238+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 -2147483137, i32 -2147483137>
239+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[TMP1]], <i32 511, i32 511>
240240
; CHECK-NEXT: ret <2 x i1> [[CMP]]
241241
;
242242
%y = srem <2 x i32> %a, <i32 512, i32 512>
@@ -246,8 +246,8 @@ define <2 x i1> @test_urem_slt_constant_splat(<2 x i32> %a) {
246246

247247
define <2 x i1> @test_urem_sgt_constant_splat(<2 x i32> %a) {
248248
; CHECK-LABEL: @test_urem_sgt_constant_splat(
249-
; CHECK-NEXT: [[Y:%.*]] = srem <2 x i32> [[A:%.*]], <i32 512, i32 512>
250-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i32> [[Y]], <i32 510, i32 510>
249+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[A:%.*]], <i32 -2147483137, i32 -2147483137>
250+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 511, i32 511>
251251
; CHECK-NEXT: ret <2 x i1> [[CMP]]
252252
;
253253
%y = srem <2 x i32> %a, <i32 512, i32 512>

0 commit comments

Comments
 (0)