return m_CombineOr(m_Xor(L, R), m_Xor(R, L));
}
-// TODO: Add the related SMax, UMax, UMin commuted matchers.
+// TODO: Add the related UMax and UMin commuted matchers.
/// Matches an SMin with LHS and RHS in either order.
-template<typename LHS, typename RHS>
+template <typename LHS, typename RHS>
inline match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty>,
MaxMin_match<ICmpInst, RHS, LHS, smin_pred_ty>>
m_c_SMin(const LHS &L, const RHS &R) {
return m_CombineOr(m_SMin(L, R), m_SMin(R, L));
}
+/// Matches an SMax with LHS and RHS in either order.
+template <typename LHS, typename RHS>
+inline match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty>,
+ MaxMin_match<ICmpInst, RHS, LHS, smax_pred_ty>>
+m_c_SMax(const LHS &L, const RHS &R) {
+ return m_CombineOr(m_SMax(L, R), m_SMax(R, L));
+}
} // end namespace PatternMatch
} // end namespace llvm
return nullptr;
}
-/// Fold icmp Pred smin(X, Y), X.
-static Instruction *foldICmpWithSMin(ICmpInst &Cmp) {
+/// Fold icmp Pred smin|smax(X, Y), X.
+static Instruction *foldICmpWithSMinMax(ICmpInst &Cmp) {
ICmpInst::Predicate Pred = Cmp.getPredicate();
Value *Op0 = Cmp.getOperand(0);
Value *X = Cmp.getOperand(1);
- // TODO: This should be expanded to handle smax/umax/umin.
+ // TODO: This should be expanded to handle umax/umin.
// Canonicalize minimum operand to LHS of the icmp.
- if (match(X, m_c_SMin(m_Specific(Op0), m_Value()))) {
+ if (match(X, m_c_SMin(m_Specific(Op0), m_Value())) ||
+ match(X, m_c_SMax(m_Specific(Op0), m_Value()))) {
std::swap(Op0, X);
Pred = Cmp.getSwappedPredicate();
}
Value *Y;
- if (!match(Op0, m_c_SMin(m_Specific(X), m_Value(Y))))
+ if (match(Op0, m_c_SMin(m_Specific(X), m_Value(Y)))) {
+ // smin(X, Y) == X --> X <= Y
+ // smin(X, Y) >= X --> X <= Y
+ if (Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_SGE)
+ return new ICmpInst(ICmpInst::ICMP_SLE, X, Y);
+
+ // smin(X, Y) != X --> X > Y
+ // smin(X, Y) < X --> X > Y
+ if (Pred == CmpInst::ICMP_NE || Pred == CmpInst::ICMP_SLT)
+ return new ICmpInst(ICmpInst::ICMP_SGT, X, Y);
+
+ // These cases should be handled in InstSimplify:
+ // smin(X, Y) <= X --> true
+ // smin(X, Y) > X --> false
return nullptr;
+ }
+ if (match(Op0, m_c_SMax(m_Specific(X), m_Value(Y)))) {
+ // smax(X, Y) == X --> X >= Y
+ // smax(X, Y) <= X --> X >= Y
+ if (Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_SLE)
+ return new ICmpInst(ICmpInst::ICMP_SGE, X, Y);
- // smin(X, Y) == X --> X <= Y
- // smin(X, Y) >= X --> X <= Y
- if (Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_SGE)
- return new ICmpInst(ICmpInst::ICMP_SLE, X, Y);
+ // smax(X, Y) != X --> X < Y
+ // smax(X, Y) > X --> X < Y
+ if (Pred == CmpInst::ICMP_NE || Pred == CmpInst::ICMP_SGT)
+ return new ICmpInst(ICmpInst::ICMP_SLT, X, Y);
- // smin(X, Y) != X --> X > Y
- // smin(X, Y) < X --> X > Y
- if (Pred == CmpInst::ICMP_NE || Pred == CmpInst::ICMP_SLT)
- return new ICmpInst(ICmpInst::ICMP_SGT, X, Y);
+ // These cases should be handled in InstSimplify:
+ // smax(X, Y) >= X --> true
+ // smax(X, Y) < X --> false
+ return nullptr;
+ }
- // These cases should be handled in InstSimplify:
- // smin(X, Y) <= X --> true
- // smin(X, Y) > X --> false
return nullptr;
}
if (Instruction *Res = foldICmpBinOp(I))
return Res;
- if (Instruction *Res = foldICmpWithSMin(I))
+ if (Instruction *Res = foldICmpWithSMinMax(I))
return Res;
{
define i1 @eq_smax1(i32 %x, i32 %y) {
; CHECK-LABEL: @eq_smax1(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 %x, %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %x, i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[SEL]], %x
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp sgt i32 %x, %y
define i1 @eq_smax2(i32 %x, i32 %y) {
; CHECK-LABEL: @eq_smax2(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 %y, %x
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %y, i32 %x
-; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[SEL]], %x
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp sgt i32 %y, %x
define i1 @eq_smax3(i32 %a, i32 %y) {
; CHECK-LABEL: @eq_smax3(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[X]], i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[X]], [[SEL]]
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization
define i1 @eq_smax4(i32 %a, i32 %y) {
; CHECK-LABEL: @eq_smax4(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X]], %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %y, i32 [[X]]
-; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[X]], [[SEL]]
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization
define i1 @sle_smax1(i32 %x, i32 %y) {
; CHECK-LABEL: @sle_smax1(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 %x, %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %x, i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[SEL]], %x
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp sgt i32 %x, %y
define i1 @sle_smax2(i32 %x, i32 %y) {
; CHECK-LABEL: @sle_smax2(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 %y, %x
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %y, i32 %x
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[SEL]], %x
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp sgt i32 %y, %x
define i1 @sle_smax3(i32 %a, i32 %y) {
; CHECK-LABEL: @sle_smax3(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[X]], i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[X]], [[SEL]]
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization
define i1 @sle_smax4(i32 %a, i32 %y) {
; CHECK-LABEL: @sle_smax4(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X]], %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %y, i32 [[X]]
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[X]], [[SEL]]
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization
define i1 @ne_smax1(i32 %x, i32 %y) {
; CHECK-LABEL: @ne_smax1(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 %x, %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %x, i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[SEL]], %x
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp sgt i32 %x, %y
define i1 @ne_smax3(i32 %a, i32 %y) {
; CHECK-LABEL: @ne_smax3(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[X]], i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[X]], [[SEL]]
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization
define i1 @sgt_smax1(i32 %x, i32 %y) {
; CHECK-LABEL: @sgt_smax1(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 %x, %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %x, i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[SEL]], %x
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp sgt i32 %x, %y
define i1 @sgt_smax3(i32 %a, i32 %y) {
; CHECK-LABEL: @sgt_smax3(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[X]], i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], [[SEL]]
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization