Skip to content

Commit 86b4d86

Browse files
committed
[InstCombine] canonicalize cmp+select as umin/umax
(V == 0) ? 1 : V --> umax(V, 1) (V == UMAX) ? UMAX-1 : V --> umin(V, UMAX-1) https://alive2.llvm.org/ce/z/pfDBAf This is one pair of the variants discussed in issue llvm#60374. Enhancements for the other end of the constant range and signed variants are potential follow-ups, but that may require more work because we canonicalize at least one min/max like that to icmp+zext.
1 parent b98813f commit 86b4d86

File tree

3 files changed

+27
-9
lines changed

3 files changed

+27
-9
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,13 +1593,26 @@ static Instruction *foldSelectZeroOrOnes(ICmpInst *Cmp, Value *TVal,
15931593
return nullptr;
15941594
}
15951595

1596-
static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI) {
1596+
static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI,
1597+
InstCombiner::BuilderTy &Builder) {
15971598
const APInt *CmpC;
15981599
Value *V;
15991600
CmpInst::Predicate Pred;
16001601
if (!match(ICI, m_ICmp(Pred, m_Value(V), m_APInt(CmpC))))
16011602
return nullptr;
16021603

1604+
// Match clamp away from min/max value as a max/min operation.
1605+
Value *TVal = SI.getTrueValue();
1606+
Value *FVal = SI.getFalseValue();
1607+
if (Pred == ICmpInst::ICMP_EQ && V == FVal) {
1608+
// (V == 0) ? 1 : V --> umax(V, 1)
1609+
if (CmpC->isMinValue() && match(TVal, m_SpecificInt(*CmpC + 1)))
1610+
return Builder.CreateBinaryIntrinsic(Intrinsic::umax, V, TVal);
1611+
// (V == UMAX) ? UMAX-1 : V --> umin(V, UMAX-1)
1612+
if (CmpC->isMaxValue() && match(TVal, m_SpecificInt(*CmpC - 1)))
1613+
return Builder.CreateBinaryIntrinsic(Intrinsic::umin, V, TVal);
1614+
}
1615+
16031616
BinaryOperator *BO;
16041617
const APInt *C;
16051618
CmpInst::Predicate CPred;
@@ -1632,7 +1645,7 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
16321645
if (Instruction *NewSPF = canonicalizeSPF(SI, *ICI, *this))
16331646
return NewSPF;
16341647

1635-
if (Value *V = foldSelectInstWithICmpConst(SI, ICI))
1648+
if (Value *V = foldSelectInstWithICmpConst(SI, ICI, Builder))
16361649
return replaceInstUsesWith(SI, V);
16371650

16381651
if (Value *V = canonicalizeClampLike(SI, *ICI, Builder))

llvm/test/Transforms/InstCombine/div-shift.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ define i32 @t5(i1 %x, i1 %y, i32 %V) {
9090

9191
define i32 @t6(i32 %x, i32 %z) {
9292
; CHECK-LABEL: @t6(
93-
; CHECK-NEXT: [[X_IS_ZERO:%.*]] = icmp eq i32 [[X:%.*]], 0
94-
; CHECK-NEXT: [[DIVISOR:%.*]] = select i1 [[X_IS_ZERO]], i32 1, i32 [[X]]
93+
; CHECK-NEXT: [[DIVISOR:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 1)
9594
; CHECK-NEXT: [[Y:%.*]] = udiv i32 [[Z:%.*]], [[DIVISOR]]
9695
; CHECK-NEXT: ret i32 [[Y]]
9796
;

llvm/test/Transforms/InstCombine/select.ll

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3399,8 +3399,7 @@ define <vscale x 2 x i1> @scalable_non_zero(<vscale x 2 x i32> %x) {
33993399

34003400
define i32 @clamp_zero(i32 %x) {
34013401
; CHECK-LABEL: @clamp_zero(
3402-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
3403-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 1, i32 [[X]]
3402+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 1)
34043403
; CHECK-NEXT: ret i32 [[SEL]]
34053404
;
34063405
%cmp = icmp eq i32 %x, 0
@@ -3412,7 +3411,7 @@ define i32 @clamp_zero_use(i32 %x) {
34123411
; CHECK-LABEL: @clamp_zero_use(
34133412
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
34143413
; CHECK-NEXT: call void @use1(i1 [[CMP]])
3415-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 1, i32 [[X]]
3414+
; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 1)
34163415
; CHECK-NEXT: ret i32 [[SEL]]
34173416
;
34183417
%cmp = icmp eq i32 %x, 0
@@ -3421,6 +3420,8 @@ define i32 @clamp_zero_use(i32 %x) {
34213420
ret i32 %sel
34223421
}
34233422

3423+
; negative test - wrong cmp constant
3424+
34243425
define i32 @not_clamp_zero1(i32 %x) {
34253426
; CHECK-LABEL: @not_clamp_zero1(
34263427
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 2
@@ -3432,6 +3433,8 @@ define i32 @not_clamp_zero1(i32 %x) {
34323433
ret i32 %sel
34333434
}
34343435

3436+
; negative test - wrong select constant
3437+
34353438
define i32 @not_clamp_zero2(i32 %x) {
34363439
; CHECK-LABEL: @not_clamp_zero2(
34373440
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
@@ -3445,15 +3448,16 @@ define i32 @not_clamp_zero2(i32 %x) {
34453448

34463449
define <2 x i8> @clamp_umaxval(<2 x i8> %x) {
34473450
; CHECK-LABEL: @clamp_umaxval(
3448-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
3449-
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 -2, i8 -2>, <2 x i8> [[X]]
3451+
; CHECK-NEXT: [[SEL:%.*]] = call <2 x i8> @llvm.umin.v2i8(<2 x i8> [[X:%.*]], <2 x i8> <i8 -2, i8 -2>)
34503452
; CHECK-NEXT: ret <2 x i8> [[SEL]]
34513453
;
34523454
%cmp = icmp eq <2 x i8> %x, <i8 255, i8 255>
34533455
%sel = select <2 x i1> %cmp, <2 x i8> <i8 254, i8 254>, <2 x i8> %x
34543456
ret <2 x i8> %sel
34553457
}
34563458

3459+
; negative test - wrong cmp constant
3460+
34573461
define i8 @not_clamp_umax1(i8 %x) {
34583462
; CHECK-LABEL: @not_clamp_umax1(
34593463
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -3
@@ -3465,6 +3469,8 @@ define i8 @not_clamp_umax1(i8 %x) {
34653469
ret i8 %sel
34663470
}
34673471

3472+
; negative test - wrong select constant
3473+
34683474
define i8 @not_clamp_umax2(i8 %x) {
34693475
; CHECK-LABEL: @not_clamp_umax2(
34703476
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -1

0 commit comments

Comments
 (0)