Skip to content

Commit d13aae7

Browse files
committed
[InstCombine] fold unsigned predicates to signed on srem result
This allows optimization of more signed floor implementations when the divisor is a known power of two to an arithmetic shift. Proof for the implemented optimizations: https://alive2.llvm.org/ce/z/j6C-Nz Proof for the test cases: https://alive2.llvm.org/ce/z/M_PBjw
1 parent f9ddc44 commit d13aae7

File tree

3 files changed

+50
-28
lines changed

3 files changed

+50
-28
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2674,10 +2674,41 @@ Instruction *InstCombinerImpl::foldICmpShrConstant(ICmpInst &Cmp,
26742674
Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp,
26752675
BinaryOperator *SRem,
26762676
const APInt &C) {
2677+
const ICmpInst::Predicate Pred = Cmp.getPredicate();
2678+
if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT) {
2679+
// Canonicalize unsigned predicates to signed:
2680+
// (X s% DivisorC) u> C -> (X s% DivisorC) s< 0
2681+
// iff (C s< 0 ? ~C : C) u>= abs(DivisorC)-1
2682+
// (X s% DivisorC) u< C+1 -> (X s% DivisorC) s> -1
2683+
// iff (C+1 s< 0 ? ~C : C) u>= abs(DivisorC)-1
2684+
2685+
const APInt *DivisorC;
2686+
if (!match(SRem->getOperand(1), m_APInt(DivisorC)))
2687+
return nullptr;
2688+
2689+
APInt NormalizedC = C;
2690+
if (Pred == ICmpInst::ICMP_ULT) {
2691+
assert(!NormalizedC.isZero() &&
2692+
"ult X, 0 should have been simplified already.");
2693+
--NormalizedC;
2694+
}
2695+
if (C.isNegative())
2696+
NormalizedC.flipAllBits();
2697+
assert(!DivisorC->isZero() &&
2698+
"srem X, 0 should have been simplified already.");
2699+
if (!NormalizedC.uge(DivisorC->abs() - 1))
2700+
return nullptr;
2701+
2702+
Type *Ty = SRem->getType();
2703+
if (Pred == ICmpInst::ICMP_UGT)
2704+
return new ICmpInst(ICmpInst::ICMP_SLT, SRem,
2705+
ConstantInt::getNullValue(Ty));
2706+
return new ICmpInst(ICmpInst::ICMP_SGT, SRem,
2707+
ConstantInt::getAllOnesValue(Ty));
2708+
}
26772709
// Match an 'is positive' or 'is negative' comparison of remainder by a
26782710
// constant power-of-2 value:
26792711
// (X % pow2C) sgt/slt 0
2680-
const ICmpInst::Predicate Pred = Cmp.getPredicate();
26812712
if (Pred != ICmpInst::ICMP_SGT && Pred != ICmpInst::ICMP_SLT &&
26822713
Pred != ICmpInst::ICMP_EQ && Pred != ICmpInst::ICMP_NE)
26832714
return nullptr;

llvm/test/Transforms/InstCombine/add.ll

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3020,11 +3020,7 @@ define i32 @floor_sdiv_wrong_op(i32 %x, i32 %y) {
30203020

30213021
define i32 @floor_sdiv_using_srem_by_8(i32 %x) {
30223022
; CHECK-LABEL: @floor_sdiv_using_srem_by_8(
3023-
; CHECK-NEXT: [[D:%.*]] = sdiv i32 [[X:%.*]], 8
3024-
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 8
3025-
; CHECK-NEXT: [[I:%.*]] = icmp ugt i32 [[R]], -2147483648
3026-
; CHECK-NEXT: [[S:%.*]] = sext i1 [[I]] to i32
3027-
; CHECK-NEXT: [[F:%.*]] = add nsw i32 [[D]], [[S]]
3023+
; CHECK-NEXT: [[F:%.*]] = ashr i32 [[X:%.*]], 3
30283024
; CHECK-NEXT: ret i32 [[F]]
30293025
;
30303026
%d = sdiv i32 %x, 8
@@ -3037,11 +3033,7 @@ define i32 @floor_sdiv_using_srem_by_8(i32 %x) {
30373033

30383034
define i32 @floor_sdiv_using_srem_by_2(i32 %x) {
30393035
; CHECK-LABEL: @floor_sdiv_using_srem_by_2(
3040-
; CHECK-NEXT: [[D:%.*]] = sdiv i32 [[X:%.*]], 2
3041-
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 2
3042-
; CHECK-NEXT: [[I:%.*]] = icmp ugt i32 [[R]], -2147483648
3043-
; CHECK-NEXT: [[S:%.*]] = sext i1 [[I]] to i32
3044-
; CHECK-NEXT: [[F:%.*]] = add nsw i32 [[D]], [[S]]
3036+
; CHECK-NEXT: [[F:%.*]] = ashr i32 [[X:%.*]], 1
30453037
; CHECK-NEXT: ret i32 [[F]]
30463038
;
30473039
%d = sdiv i32 %x, 2

llvm/test/Transforms/InstCombine/icmp-srem.ll

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
define i1 @icmp_ugt_sremsmin_smin(i32 %x) {
55
; CHECK-LABEL: define i1 @icmp_ugt_sremsmin_smin(
66
; CHECK-SAME: i32 [[X:%.*]]) {
7-
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], -2147483648
8-
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[R]], -2147483648
7+
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[X]], -2147483648
98
; CHECK-NEXT: ret i1 [[C]]
109
;
1110
%r = srem i32 %x, -2147483648
@@ -64,7 +63,7 @@ define i1 @icmp_ult_sremsmin_sminp1(i32 %x) {
6463
; CHECK-LABEL: define i1 @icmp_ult_sremsmin_sminp1(
6564
; CHECK-SAME: i32 [[X:%.*]]) {
6665
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], -2147483648
67-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[R]], -2147483647
66+
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[R]], -1
6867
; CHECK-NEXT: ret i1 [[C]]
6968
;
7069
%r = srem i32 %x, -2147483648
@@ -100,7 +99,7 @@ define i1 @icmp_ugt_srem5_smin(i32 %x) {
10099
; CHECK-LABEL: define i1 @icmp_ugt_srem5_smin(
101100
; CHECK-SAME: i32 [[X:%.*]]) {
102101
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 5
103-
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[R]], -2147483648
102+
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], 0
104103
; CHECK-NEXT: ret i1 [[C]]
105104
;
106105
%r = srem i32 %x, 5
@@ -112,7 +111,7 @@ define i1 @icmp_ugt_srem5_m5(i32 %x) {
112111
; CHECK-LABEL: define i1 @icmp_ugt_srem5_m5(
113112
; CHECK-SAME: i32 [[X:%.*]]) {
114113
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 5
115-
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[R]], -5
114+
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], 0
116115
; CHECK-NEXT: ret i1 [[C]]
117116
;
118117
%r = srem i32 %x, 5
@@ -148,7 +147,7 @@ define i1 @icmp_ugt_srem5_4(i32 %x) {
148147
; CHECK-LABEL: define i1 @icmp_ugt_srem5_4(
149148
; CHECK-SAME: i32 [[X:%.*]]) {
150149
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 5
151-
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[R]], 4
150+
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], 0
152151
; CHECK-NEXT: ret i1 [[C]]
153152
;
154153
%r = srem i32 %x, 5
@@ -160,7 +159,7 @@ define i1 @icmp_ugt_srem5_smaxm1(i32 %x) {
160159
; CHECK-LABEL: define i1 @icmp_ugt_srem5_smaxm1(
161160
; CHECK-SAME: i32 [[X:%.*]]) {
162161
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 5
163-
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[R]], 2147483646
162+
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], 0
164163
; CHECK-NEXT: ret i1 [[C]]
165164
;
166165
%r = srem i32 %x, 5
@@ -172,7 +171,7 @@ define i1 @icmp_ult_srem5_sminp1(i32 %x) {
172171
; CHECK-LABEL: define i1 @icmp_ult_srem5_sminp1(
173172
; CHECK-SAME: i32 [[X:%.*]]) {
174173
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 5
175-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[R]], -2147483647
174+
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[R]], -1
176175
; CHECK-NEXT: ret i1 [[C]]
177176
;
178177
%r = srem i32 %x, 5
@@ -184,7 +183,7 @@ define i1 @icmp_ult_srem5_m4(i32 %x) {
184183
; CHECK-LABEL: define i1 @icmp_ult_srem5_m4(
185184
; CHECK-SAME: i32 [[X:%.*]]) {
186185
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 5
187-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[R]], -4
186+
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[R]], -1
188187
; CHECK-NEXT: ret i1 [[C]]
189188
;
190189
%r = srem i32 %x, 5
@@ -220,7 +219,7 @@ define i1 @icmp_ult_srem5_5(i32 %x) {
220219
; CHECK-LABEL: define i1 @icmp_ult_srem5_5(
221220
; CHECK-SAME: i32 [[X:%.*]]) {
222221
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 5
223-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[R]], 5
222+
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[R]], -1
224223
; CHECK-NEXT: ret i1 [[C]]
225224
;
226225
%r = srem i32 %x, 5
@@ -232,7 +231,7 @@ define i1 @icmp_ult_srem5_smax(i32 %x) {
232231
; CHECK-LABEL: define i1 @icmp_ult_srem5_smax(
233232
; CHECK-SAME: i32 [[X:%.*]]) {
234233
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 5
235-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[R]], 2147483647
234+
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[R]], -1
236235
; CHECK-NEXT: ret i1 [[C]]
237236
;
238237
%r = srem i32 %x, 5
@@ -244,7 +243,7 @@ define i1 @icmp_ugt_sremsmax_smin(i32 %x) {
244243
; CHECK-LABEL: define i1 @icmp_ugt_sremsmax_smin(
245244
; CHECK-SAME: i32 [[X:%.*]]) {
246245
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 2147483647
247-
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[R]], -2147483648
246+
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], 0
248247
; CHECK-NEXT: ret i1 [[C]]
249248
;
250249
%r = srem i32 %x, 2147483647
@@ -256,7 +255,7 @@ define i1 @icmp_ugt_sremsmax_sminp1(i32 %x) {
256255
; CHECK-LABEL: define i1 @icmp_ugt_sremsmax_sminp1(
257256
; CHECK-SAME: i32 [[X:%.*]]) {
258257
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 2147483647
259-
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[R]], -2147483647
258+
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], 0
260259
; CHECK-NEXT: ret i1 [[C]]
261260
;
262261
%r = srem i32 %x, 2147483647
@@ -292,7 +291,7 @@ define i1 @icmp_ugt_sremsmax_smaxm1(i32 %x) {
292291
; CHECK-LABEL: define i1 @icmp_ugt_sremsmax_smaxm1(
293292
; CHECK-SAME: i32 [[X:%.*]]) {
294293
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 2147483647
295-
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[R]], 2147483646
294+
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[R]], 0
296295
; CHECK-NEXT: ret i1 [[C]]
297296
;
298297
%r = srem i32 %x, 2147483647
@@ -328,7 +327,7 @@ define i1 @icmp_ult_sremsmax_sminp1(i32 %x) {
328327
; CHECK-LABEL: define i1 @icmp_ult_sremsmax_sminp1(
329328
; CHECK-SAME: i32 [[X:%.*]]) {
330329
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 2147483647
331-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[R]], -2147483647
330+
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[R]], -1
332331
; CHECK-NEXT: ret i1 [[C]]
333332
;
334333
%r = srem i32 %x, 2147483647
@@ -340,7 +339,7 @@ define i1 @icmp_ult_sremsmax_sminp2(i32 %x) {
340339
; CHECK-LABEL: define i1 @icmp_ult_sremsmax_sminp2(
341340
; CHECK-SAME: i32 [[X:%.*]]) {
342341
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 2147483647
343-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[R]], -2147483646
342+
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[R]], -1
344343
; CHECK-NEXT: ret i1 [[C]]
345344
;
346345
%r = srem i32 %x, 2147483647
@@ -376,7 +375,7 @@ define i1 @icmp_ult_sremsmax_smax(i32 %x) {
376375
; CHECK-LABEL: define i1 @icmp_ult_sremsmax_smax(
377376
; CHECK-SAME: i32 [[X:%.*]]) {
378377
; CHECK-NEXT: [[R:%.*]] = srem i32 [[X]], 2147483647
379-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[R]], 2147483647
378+
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[R]], -1
380379
; CHECK-NEXT: ret i1 [[C]]
381380
;
382381
%r = srem i32 %x, 2147483647

0 commit comments

Comments
 (0)