return nullptr;
}
-static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI) {
+static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI,
+ InstCombiner::BuilderTy &Builder) {
const APInt *CmpC;
Value *V;
CmpInst::Predicate Pred;
if (!match(ICI, m_ICmp(Pred, m_Value(V), m_APInt(CmpC))))
return nullptr;
+ // Match clamp away from min/max value as a max/min operation.
+ Value *TVal = SI.getTrueValue();
+ Value *FVal = SI.getFalseValue();
+ if (Pred == ICmpInst::ICMP_EQ && V == FVal) {
+ // (V == 0) ? 1 : V --> umax(V, 1)
+ if (CmpC->isMinValue() && match(TVal, m_SpecificInt(*CmpC + 1)))
+ return Builder.CreateBinaryIntrinsic(Intrinsic::umax, V, TVal);
+ // (V == UMAX) ? UMAX-1 : V --> umin(V, UMAX-1)
+ if (CmpC->isMaxValue() && match(TVal, m_SpecificInt(*CmpC - 1)))
+ return Builder.CreateBinaryIntrinsic(Intrinsic::umin, V, TVal);
+ }
+
BinaryOperator *BO;
const APInt *C;
CmpInst::Predicate CPred;
if (Instruction *NewSPF = canonicalizeSPF(SI, *ICI, *this))
return NewSPF;
- if (Value *V = foldSelectInstWithICmpConst(SI, ICI))
+ if (Value *V = foldSelectInstWithICmpConst(SI, ICI, Builder))
return replaceInstUsesWith(SI, V);
if (Value *V = canonicalizeClampLike(SI, *ICI, Builder))
define i32 @clamp_zero(i32 %x) {
; CHECK-LABEL: @clamp_zero(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 1, i32 [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 1)
; CHECK-NEXT: ret i32 [[SEL]]
;
%cmp = icmp eq i32 %x, 0
; CHECK-LABEL: @clamp_zero_use(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: call void @use1(i1 [[CMP]])
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 1, i32 [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 1)
; CHECK-NEXT: ret i32 [[SEL]]
;
%cmp = icmp eq i32 %x, 0
ret i32 %sel
}
+; negative test - wrong cmp constant
+
define i32 @not_clamp_zero1(i32 %x) {
; CHECK-LABEL: @not_clamp_zero1(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 2
ret i32 %sel
}
+; negative test - wrong select constant
+
define i32 @not_clamp_zero2(i32 %x) {
; CHECK-LABEL: @not_clamp_zero2(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
define <2 x i8> @clamp_umaxval(<2 x i8> %x) {
; CHECK-LABEL: @clamp_umaxval(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 -2, i8 -2>, <2 x i8> [[X]]
+; CHECK-NEXT: [[SEL:%.*]] = call <2 x i8> @llvm.umin.v2i8(<2 x i8> [[X:%.*]], <2 x i8> <i8 -2, i8 -2>)
; CHECK-NEXT: ret <2 x i8> [[SEL]]
;
%cmp = icmp eq <2 x i8> %x, <i8 255, i8 255>
ret <2 x i8> %sel
}
+; negative test - wrong cmp constant
+
define i8 @not_clamp_umax1(i8 %x) {
; CHECK-LABEL: @not_clamp_umax1(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -3
ret i8 %sel
}
+; negative test - wrong select constant
+
define i8 @not_clamp_umax2(i8 %x) {
; CHECK-LABEL: @not_clamp_umax2(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -1