return nullptr;
}
+/// Fold icmp Pred smin(X, Y), X.
+static Instruction *foldICmpWithSMin(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.
+
+ // Canonicalize minimum operand to LHS of the icmp.
+ if (match(X, m_c_SMin(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))))
+ return nullptr;
+
+ // 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;
+}
+
Instruction *InstCombiner::foldICmpEquality(ICmpInst &I) {
if (!I.isEquality())
return nullptr;
if (Instruction *Res = foldICmpBinOp(I))
return Res;
+ if (Instruction *Res = foldICmpWithSMin(I))
+ return Res;
+
{
Value *A, *B;
// Transform (A & ~B) == 0 --> (A & B) != 0
define i1 @eq_smin1(i32 %x, i32 %y) {
; CHECK-LABEL: @eq_smin1(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt 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 sle i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp slt i32 %x, %y
define i1 @eq_smin2(i32 %x, i32 %y) {
; CHECK-LABEL: @eq_smin2(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt 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 sle i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp slt i32 %y, %x
define i1 @eq_smin3(i32 %a, i32 %y) {
; CHECK-LABEL: @eq_smin3(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt 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 sle i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization
define i1 @eq_smin4(i32 %a, i32 %y) {
; CHECK-LABEL: @eq_smin4(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt 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 sle i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization
define i1 @sge_smin1(i32 %x, i32 %y) {
; CHECK-LABEL: @sge_smin1(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 %x, %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %x, i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[SEL]], %x
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp slt i32 %x, %y
define i1 @sge_smin2(i32 %x, i32 %y) {
; CHECK-LABEL: @sge_smin2(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 %y, %x
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %y, i32 %x
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[SEL]], %x
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp slt i32 %y, %x
define i1 @sge_smin3(i32 %a, i32 %y) {
; CHECK-LABEL: @sge_smin3(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X]], %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[X]], i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[X]], [[SEL]]
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization
define i1 @sge_smin4(i32 %a, i32 %y) {
; CHECK-LABEL: @sge_smin4(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %y, i32 [[X]]
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[X]], [[SEL]]
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization
define i1 @ne_smin1(i32 %x, i32 %y) {
; CHECK-LABEL: @ne_smin1(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt 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 sgt i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp slt i32 %x, %y
define i1 @ne_smin3(i32 %a, i32 %y) {
; CHECK-LABEL: @ne_smin3(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt 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 sgt i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization
define i1 @slt_smin1(i32 %x, i32 %y) {
; CHECK-LABEL: @slt_smin1(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 %x, %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 %x, i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[SEL]], %x
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 %x, %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp slt i32 %x, %y
define i1 @slt_smin3(i32 %a, i32 %y) {
; CHECK-LABEL: @slt_smin3(
; CHECK-NEXT: [[X:%.*]] = add i32 %a, 3
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X]], %y
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[X]], i32 %y
-; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], [[SEL]]
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], %y
; CHECK-NEXT: ret i1 [[CMP2]]
;
%x = add i32 %a, 3 ; thwart complexity-based canonicalization