Skip to content

Commit 641d160

Browse files
authored
[InstCombine] Fold umax(smax)/smin(umin) with non-negative constants (#82929)
This patch extends `reassociateMinMaxWithConstants` to fold the following patterns: ``` umax (smax X, nneg C0), nneg C1 --> smax X, (umax C0, C1) smin (umin X, nneg C0), nneg C1 --> umin X, (smin/umin C0, C1) ``` Alive2: https://alive2.llvm.org/ce/z/wfEj-e Address the comment #82472 (review).
1 parent 6f9b0a7 commit 641d160

File tree

3 files changed

+150
-17
lines changed

3 files changed

+150
-17
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,22 +1220,33 @@ static Instruction *foldClampRangeOfTwo(IntrinsicInst *II,
12201220
/// If this min/max has a constant operand and an operand that is a matching
12211221
/// min/max with a constant operand, constant-fold the 2 constant operands.
12221222
static Value *reassociateMinMaxWithConstants(IntrinsicInst *II,
1223-
IRBuilderBase &Builder) {
1223+
IRBuilderBase &Builder,
1224+
const SimplifyQuery &SQ) {
12241225
Intrinsic::ID MinMaxID = II->getIntrinsicID();
1225-
auto *LHS = dyn_cast<IntrinsicInst>(II->getArgOperand(0));
1226-
if (!LHS || LHS->getIntrinsicID() != MinMaxID)
1226+
auto *LHS = dyn_cast<MinMaxIntrinsic>(II->getArgOperand(0));
1227+
if (!LHS)
12271228
return nullptr;
12281229

12291230
Constant *C0, *C1;
12301231
if (!match(LHS->getArgOperand(1), m_ImmConstant(C0)) ||
12311232
!match(II->getArgOperand(1), m_ImmConstant(C1)))
12321233
return nullptr;
12331234

1234-
// max (max X, C0), C1 --> max X, (max C0, C1) --> max X, NewC
1235+
// max (max X, C0), C1 --> max X, (max C0, C1)
1236+
// min (min X, C0), C1 --> min X, (min C0, C1)
1237+
// umax (smax X, nneg C0), nneg C1 --> smax X, (umax C0, C1)
1238+
// smin (umin X, nneg C0), nneg C1 --> umin X, (smin C0, C1)
1239+
Intrinsic::ID InnerMinMaxID = LHS->getIntrinsicID();
1240+
if (InnerMinMaxID != MinMaxID &&
1241+
!(((MinMaxID == Intrinsic::umax && InnerMinMaxID == Intrinsic::smax) ||
1242+
(MinMaxID == Intrinsic::smin && InnerMinMaxID == Intrinsic::umin)) &&
1243+
isKnownNonNegative(C0, SQ) && isKnownNonNegative(C1, SQ)))
1244+
return nullptr;
1245+
12351246
ICmpInst::Predicate Pred = MinMaxIntrinsic::getPredicate(MinMaxID);
12361247
Value *CondC = Builder.CreateICmp(Pred, C0, C1);
12371248
Value *NewC = Builder.CreateSelect(CondC, C0, C1);
1238-
return Builder.CreateIntrinsic(MinMaxID, II->getType(),
1249+
return Builder.CreateIntrinsic(InnerMinMaxID, II->getType(),
12391250
{LHS->getArgOperand(0), NewC});
12401251
}
12411252

@@ -1786,7 +1797,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
17861797
if (Instruction *SAdd = matchSAddSubSat(*II))
17871798
return SAdd;
17881799

1789-
if (Value *NewMinMax = reassociateMinMaxWithConstants(II, Builder))
1800+
if (Value *NewMinMax = reassociateMinMaxWithConstants(II, Builder, SQ))
17901801
return replaceInstUsesWith(*II, NewMinMax);
17911802

17921803
if (Instruction *R = reassociateMinMaxWithConstantInOperand(II, Builder))

llvm/test/Transforms/InstCombine/minmax-fold.ll

Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,7 @@ define i32 @test73(i32 %x) {
316316
; SMAX(SMAX(X, 36), 75) -> SMAX(X, 75)
317317
define i32 @test74(i32 %x) {
318318
; CHECK-LABEL: @test74(
319-
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 36)
320-
; CHECK-NEXT: [[RETVAL:%.*]] = call i32 @llvm.umax.i32(i32 [[COND]], i32 75)
319+
; CHECK-NEXT: [[RETVAL:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 75)
321320
; CHECK-NEXT: ret i32 [[RETVAL]]
322321
;
323322
%cmp = icmp slt i32 %x, 36
@@ -1419,3 +1418,127 @@ entry:
14191418
%r = select i1 %cmp2, i32 %s1, i32 %k1
14201419
ret i32 %r
14211420
}
1421+
1422+
define i32 @test_umax_smax1(i32 %x) {
1423+
; CHECK-LABEL: @test_umax_smax1(
1424+
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 1)
1425+
; CHECK-NEXT: ret i32 [[UMAX]]
1426+
;
1427+
%smax = call i32 @llvm.smax.i32(i32 %x, i32 0)
1428+
%umax = call i32 @llvm.umax.i32(i32 %smax, i32 1)
1429+
ret i32 %umax
1430+
}
1431+
1432+
define i32 @test_umax_smax2(i32 %x) {
1433+
; CHECK-LABEL: @test_umax_smax2(
1434+
; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 20)
1435+
; CHECK-NEXT: ret i32 [[SMAX]]
1436+
;
1437+
%smax = call i32 @llvm.smax.i32(i32 %x, i32 20)
1438+
%umax = call i32 @llvm.umax.i32(i32 %smax, i32 10)
1439+
ret i32 %umax
1440+
}
1441+
1442+
define <2 x i32> @test_umax_smax_vec(<2 x i32> %x) {
1443+
; CHECK-LABEL: @test_umax_smax_vec(
1444+
; CHECK-NEXT: [[UMAX:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 1, i32 20>)
1445+
; CHECK-NEXT: ret <2 x i32> [[UMAX]]
1446+
;
1447+
%smax = call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 0, i32 20>)
1448+
%umax = call <2 x i32> @llvm.umax.v2i32(<2 x i32> %smax, <2 x i32> <i32 1, i32 10>)
1449+
ret <2 x i32> %umax
1450+
}
1451+
1452+
define i32 @test_smin_umin1(i32 %x) {
1453+
; CHECK-LABEL: @test_smin_umin1(
1454+
; CHECK-NEXT: [[SMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 10)
1455+
; CHECK-NEXT: ret i32 [[SMIN]]
1456+
;
1457+
%smin = call i32 @llvm.umin.i32(i32 %x, i32 10)
1458+
%umin = call i32 @llvm.smin.i32(i32 %smin, i32 20)
1459+
ret i32 %umin
1460+
}
1461+
1462+
define i32 @test_smin_umin2(i32 %x) {
1463+
; CHECK-LABEL: @test_smin_umin2(
1464+
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 10)
1465+
; CHECK-NEXT: ret i32 [[UMIN]]
1466+
;
1467+
%smin = call i32 @llvm.umin.i32(i32 %x, i32 20)
1468+
%umin = call i32 @llvm.smin.i32(i32 %smin, i32 10)
1469+
ret i32 %umin
1470+
}
1471+
1472+
define <2 x i32> @test_smin_umin_vec(<2 x i32> %x) {
1473+
; CHECK-LABEL: @test_smin_umin_vec(
1474+
; CHECK-NEXT: [[UMIN:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 10, i32 10>)
1475+
; CHECK-NEXT: ret <2 x i32> [[UMIN]]
1476+
;
1477+
%smin = call <2 x i32> @llvm.umin.v2i32(<2 x i32> %x, <2 x i32> <i32 10, i32 20>)
1478+
%umin = call <2 x i32> @llvm.smin.v2i32(<2 x i32> %smin, <2 x i32> <i32 20, i32 10>)
1479+
ret <2 x i32> %umin
1480+
}
1481+
1482+
; Negative tests
1483+
1484+
define i32 @test_umax_smax3(i32 %x) {
1485+
; CHECK-LABEL: @test_umax_smax3(
1486+
; CHECK-NEXT: ret i32 -1
1487+
;
1488+
%smax = call i32 @llvm.smax.i32(i32 %x, i32 0)
1489+
%umax = call i32 @llvm.umax.i32(i32 %smax, i32 -1)
1490+
ret i32 %umax
1491+
}
1492+
1493+
define i32 @test_umax_smax4(i32 %x) {
1494+
; CHECK-LABEL: @test_umax_smax4(
1495+
; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 -20)
1496+
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SMAX]], i32 10)
1497+
; CHECK-NEXT: ret i32 [[UMAX]]
1498+
;
1499+
%smax = call i32 @llvm.smax.i32(i32 %x, i32 -20)
1500+
%umax = call i32 @llvm.umax.i32(i32 %smax, i32 10)
1501+
ret i32 %umax
1502+
}
1503+
1504+
define i32 @test_smin_umin3(i32 %x) {
1505+
; CHECK-LABEL: @test_smin_umin3(
1506+
; CHECK-NEXT: ret i32 -20
1507+
;
1508+
%smin = call i32 @llvm.umin.i32(i32 %x, i32 10)
1509+
%umin = call i32 @llvm.smin.i32(i32 %smin, i32 -20)
1510+
ret i32 %umin
1511+
}
1512+
1513+
define i32 @test_smin_umin4(i32 %x) {
1514+
; CHECK-LABEL: @test_smin_umin4(
1515+
; CHECK-NEXT: [[SMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 -20)
1516+
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[SMIN]], i32 10)
1517+
; CHECK-NEXT: ret i32 [[UMIN]]
1518+
;
1519+
%smin = call i32 @llvm.umin.i32(i32 %x, i32 -20)
1520+
%umin = call i32 @llvm.smin.i32(i32 %smin, i32 10)
1521+
ret i32 %umin
1522+
}
1523+
1524+
define i32 @test_umax_nonminmax(i32 %x) {
1525+
; CHECK-LABEL: @test_umax_nonminmax(
1526+
; CHECK-NEXT: [[Y:%.*]] = call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range [[RNG0:![0-9]+]]
1527+
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[Y]], i32 1)
1528+
; CHECK-NEXT: ret i32 [[UMAX]]
1529+
;
1530+
%y = call i32 @llvm.ctpop.i32(i32 %x)
1531+
%umax = call i32 @llvm.umax.i32(i32 %y, i32 1)
1532+
ret i32 %umax
1533+
}
1534+
1535+
define <2 x i32> @test_umax_smax_vec_neg(<2 x i32> %x) {
1536+
; CHECK-LABEL: @test_umax_smax_vec_neg(
1537+
; CHECK-NEXT: [[SMAX:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 0, i32 -20>)
1538+
; CHECK-NEXT: [[UMAX:%.*]] = call <2 x i32> @llvm.umax.v2i32(<2 x i32> [[SMAX]], <2 x i32> <i32 1, i32 10>)
1539+
; CHECK-NEXT: ret <2 x i32> [[UMAX]]
1540+
;
1541+
%smax = call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 0, i32 -20>)
1542+
%umax = call <2 x i32> @llvm.umax.v2i32(<2 x i32> %smax, <2 x i32> <i32 1, i32 10>)
1543+
ret <2 x i32> %umax
1544+
}

llvm/test/Transforms/InstCombine/select_meta.ll

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,7 @@ define i32 @test72(i32 %x) {
171171
; SMAX(SMAX(X, 36), 75) -> SMAX(X, 75)
172172
define i32 @test74(i32 %x) {
173173
; CHECK-LABEL: @test74(
174-
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 36)
175-
; CHECK-NEXT: [[RETVAL:%.*]] = call i32 @llvm.umax.i32(i32 [[COND]], i32 75)
174+
; CHECK-NEXT: [[RETVAL:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 75)
176175
; CHECK-NEXT: ret i32 [[RETVAL]]
177176
;
178177
%cmp = icmp slt i32 %x, 36
@@ -317,7 +316,7 @@ define <2 x i32> @not_cond_vec_undef(<2 x i1> %c, <2 x i32> %tv, <2 x i32> %fv)
317316

318317
define i64 @select_add(i1 %cond, i64 %x, i64 %y) {
319318
; CHECK-LABEL: @select_add(
320-
; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], i64 [[Y:%.*]], i64 0, !prof [[PROF0]], !unpredictable !2
319+
; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], i64 [[Y:%.*]], i64 0, !prof [[PROF0]], !unpredictable [[META2:![0-9]+]]
321320
; CHECK-NEXT: [[RET:%.*]] = add i64 [[OP]], [[X:%.*]]
322321
; CHECK-NEXT: ret i64 [[RET]]
323322
;
@@ -328,7 +327,7 @@ define i64 @select_add(i1 %cond, i64 %x, i64 %y) {
328327

329328
define <2 x i32> @select_or(<2 x i1> %cond, <2 x i32> %x, <2 x i32> %y) {
330329
; CHECK-LABEL: @select_or(
331-
; CHECK-NEXT: [[OP:%.*]] = select <2 x i1> [[COND:%.*]], <2 x i32> [[Y:%.*]], <2 x i32> zeroinitializer, !prof [[PROF0]], !unpredictable !2
330+
; CHECK-NEXT: [[OP:%.*]] = select <2 x i1> [[COND:%.*]], <2 x i32> [[Y:%.*]], <2 x i32> zeroinitializer, !prof [[PROF0]], !unpredictable [[META2]]
332331
; CHECK-NEXT: [[RET:%.*]] = or <2 x i32> [[OP]], [[X:%.*]]
333332
; CHECK-NEXT: ret <2 x i32> [[RET]]
334333
;
@@ -339,7 +338,7 @@ define <2 x i32> @select_or(<2 x i1> %cond, <2 x i32> %x, <2 x i32> %y) {
339338

340339
define i17 @select_sub(i1 %cond, i17 %x, i17 %y) {
341340
; CHECK-LABEL: @select_sub(
342-
; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], i17 [[Y:%.*]], i17 0, !prof [[PROF0]], !unpredictable !2
341+
; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], i17 [[Y:%.*]], i17 0, !prof [[PROF0]], !unpredictable [[META2]]
343342
; CHECK-NEXT: [[RET:%.*]] = sub i17 [[X:%.*]], [[OP]]
344343
; CHECK-NEXT: ret i17 [[RET]]
345344
;
@@ -350,7 +349,7 @@ define i17 @select_sub(i1 %cond, i17 %x, i17 %y) {
350349

351350
define i128 @select_ashr(i1 %cond, i128 %x, i128 %y) {
352351
; CHECK-LABEL: @select_ashr(
353-
; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], i128 [[Y:%.*]], i128 0, !prof [[PROF0]], !unpredictable !2
352+
; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], i128 [[Y:%.*]], i128 0, !prof [[PROF0]], !unpredictable [[META2]]
354353
; CHECK-NEXT: [[RET:%.*]] = ashr i128 [[X:%.*]], [[OP]]
355354
; CHECK-NEXT: ret i128 [[RET]]
356355
;
@@ -361,7 +360,7 @@ define i128 @select_ashr(i1 %cond, i128 %x, i128 %y) {
361360

362361
define double @select_fmul(i1 %cond, double %x, double %y) {
363362
; CHECK-LABEL: @select_fmul(
364-
; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], double [[Y:%.*]], double 1.000000e+00, !prof [[PROF0]], !unpredictable !2
363+
; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], double [[Y:%.*]], double 1.000000e+00, !prof [[PROF0]], !unpredictable [[META2]]
365364
; CHECK-NEXT: [[RET:%.*]] = fmul double [[OP]], [[X:%.*]]
366365
; CHECK-NEXT: ret double [[RET]]
367366
;
@@ -372,7 +371,7 @@ define double @select_fmul(i1 %cond, double %x, double %y) {
372371

373372
define <2 x float> @select_fdiv(i1 %cond, <2 x float> %x, <2 x float> %y) {
374373
; CHECK-LABEL: @select_fdiv(
375-
; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], <2 x float> [[Y:%.*]], <2 x float> <float 1.000000e+00, float 1.000000e+00>, !prof [[PROF0]], !unpredictable !2
374+
; CHECK-NEXT: [[OP:%.*]] = select i1 [[COND:%.*]], <2 x float> [[Y:%.*]], <2 x float> <float 1.000000e+00, float 1.000000e+00>, !prof [[PROF0]], !unpredictable [[META2]]
376375
; CHECK-NEXT: [[RET:%.*]] = fdiv <2 x float> [[X:%.*]], [[OP]]
377376
; CHECK-NEXT: ret <2 x float> [[RET]]
378377
;
@@ -391,5 +390,5 @@ define <2 x float> @select_fdiv(i1 %cond, <2 x float> %x, <2 x float> %y) {
391390
;.
392391
; CHECK: [[PROF0]] = !{!"branch_weights", i32 2, i32 10}
393392
; CHECK: [[PROF1]] = !{!"branch_weights", i32 10, i32 2}
394-
; CHECK: [[META2:![0-9]+]] = !{}
393+
; CHECK: [[META2]] = !{}
395394
;.

0 commit comments

Comments
 (0)