Skip to content

Commit 854ded9

Browse files
authored
Reapply "[DAG] Enhance SDPatternMatch to match integer minimum and maximum patterns in addition to the existing ISD nodes." (#112203)
This patch adds icmp+select patterns for integer min/max matchers in SDPatternMatch, similar to those in IR PatternMatch. Reapply #111774. Closes #108218.
1 parent aabdd8f commit 854ded9

File tree

11 files changed

+1087
-1098
lines changed

11 files changed

+1087
-1098
lines changed

llvm/include/llvm/CodeGen/SDPatternMatch.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,81 @@ struct BinaryOpc_match {
542542
}
543543
};
544544

545+
template <typename LHS_P, typename RHS_P, typename Pred_t,
546+
bool Commutable = false, bool ExcludeChain = false>
547+
struct MaxMin_match {
548+
using PredType = Pred_t;
549+
LHS_P LHS;
550+
RHS_P RHS;
551+
552+
MaxMin_match(const LHS_P &L, const RHS_P &R) : LHS(L), RHS(R) {}
553+
554+
template <typename MatchContext>
555+
bool match(const MatchContext &Ctx, SDValue N) {
556+
if (sd_context_match(N, Ctx, m_Opc(ISD::SELECT)) ||
557+
sd_context_match(N, Ctx, m_Opc(ISD::VSELECT))) {
558+
EffectiveOperands<ExcludeChain> EO_SELECT(N, Ctx);
559+
assert(EO_SELECT.Size == 3);
560+
SDValue Cond = N->getOperand(EO_SELECT.FirstIndex);
561+
SDValue TrueValue = N->getOperand(EO_SELECT.FirstIndex + 1);
562+
SDValue FalseValue = N->getOperand(EO_SELECT.FirstIndex + 2);
563+
564+
if (sd_context_match(Cond, Ctx, m_Opc(ISD::SETCC))) {
565+
EffectiveOperands<ExcludeChain> EO_SETCC(Cond, Ctx);
566+
assert(EO_SETCC.Size == 3);
567+
SDValue L = Cond->getOperand(EO_SETCC.FirstIndex);
568+
SDValue R = Cond->getOperand(EO_SETCC.FirstIndex + 1);
569+
auto *CondNode =
570+
cast<CondCodeSDNode>(Cond->getOperand(EO_SETCC.FirstIndex + 2));
571+
572+
if ((TrueValue != L || FalseValue != R) &&
573+
(TrueValue != R || FalseValue != L)) {
574+
return false;
575+
}
576+
577+
ISD::CondCode Cond =
578+
TrueValue == L ? CondNode->get()
579+
: getSetCCInverse(CondNode->get(), L.getValueType());
580+
if (!Pred_t::match(Cond)) {
581+
return false;
582+
}
583+
return (LHS.match(Ctx, L) && RHS.match(Ctx, R)) ||
584+
(Commutable && LHS.match(Ctx, R) && RHS.match(Ctx, L));
585+
}
586+
}
587+
588+
return false;
589+
}
590+
};
591+
592+
// Helper class for identifying signed max predicates.
593+
struct smax_pred_ty {
594+
static bool match(ISD::CondCode Cond) {
595+
return Cond == ISD::CondCode::SETGT || Cond == ISD::CondCode::SETGE;
596+
}
597+
};
598+
599+
// Helper class for identifying unsigned max predicates.
600+
struct umax_pred_ty {
601+
static bool match(ISD::CondCode Cond) {
602+
return Cond == ISD::CondCode::SETUGT || Cond == ISD::CondCode::SETUGE;
603+
}
604+
};
605+
606+
// Helper class for identifying signed min predicates.
607+
struct smin_pred_ty {
608+
static bool match(ISD::CondCode Cond) {
609+
return Cond == ISD::CondCode::SETLT || Cond == ISD::CondCode::SETLE;
610+
}
611+
};
612+
613+
// Helper class for identifying unsigned min predicates.
614+
struct umin_pred_ty {
615+
static bool match(ISD::CondCode Cond) {
616+
return Cond == ISD::CondCode::SETULT || Cond == ISD::CondCode::SETULE;
617+
}
618+
};
619+
545620
template <typename LHS, typename RHS>
546621
inline BinaryOpc_match<LHS, RHS> m_BinOp(unsigned Opc, const LHS &L,
547622
const RHS &R) {
@@ -613,21 +688,45 @@ inline BinaryOpc_match<LHS, RHS, true> m_SMin(const LHS &L, const RHS &R) {
613688
return BinaryOpc_match<LHS, RHS, true>(ISD::SMIN, L, R);
614689
}
615690

691+
template <typename LHS, typename RHS>
692+
inline auto m_SMinLike(const LHS &L, const RHS &R) {
693+
return m_AnyOf(BinaryOpc_match<LHS, RHS, true>(ISD::SMIN, L, R),
694+
MaxMin_match<LHS, RHS, smin_pred_ty, true>(L, R));
695+
}
696+
616697
template <typename LHS, typename RHS>
617698
inline BinaryOpc_match<LHS, RHS, true> m_SMax(const LHS &L, const RHS &R) {
618699
return BinaryOpc_match<LHS, RHS, true>(ISD::SMAX, L, R);
619700
}
620701

702+
template <typename LHS, typename RHS>
703+
inline auto m_SMaxLike(const LHS &L, const RHS &R) {
704+
return m_AnyOf(BinaryOpc_match<LHS, RHS, true>(ISD::SMAX, L, R),
705+
MaxMin_match<LHS, RHS, smax_pred_ty, true>(L, R));
706+
}
707+
621708
template <typename LHS, typename RHS>
622709
inline BinaryOpc_match<LHS, RHS, true> m_UMin(const LHS &L, const RHS &R) {
623710
return BinaryOpc_match<LHS, RHS, true>(ISD::UMIN, L, R);
624711
}
625712

713+
template <typename LHS, typename RHS>
714+
inline auto m_UMinLike(const LHS &L, const RHS &R) {
715+
return m_AnyOf(BinaryOpc_match<LHS, RHS, true>(ISD::UMIN, L, R),
716+
MaxMin_match<LHS, RHS, umin_pred_ty, true>(L, R));
717+
}
718+
626719
template <typename LHS, typename RHS>
627720
inline BinaryOpc_match<LHS, RHS, true> m_UMax(const LHS &L, const RHS &R) {
628721
return BinaryOpc_match<LHS, RHS, true>(ISD::UMAX, L, R);
629722
}
630723

724+
template <typename LHS, typename RHS>
725+
inline auto m_UMaxLike(const LHS &L, const RHS &R) {
726+
return m_AnyOf(BinaryOpc_match<LHS, RHS, true>(ISD::UMAX, L, R),
727+
MaxMin_match<LHS, RHS, umax_pred_ty, true>(L, R));
728+
}
729+
631730
template <typename LHS, typename RHS>
632731
inline BinaryOpc_match<LHS, RHS> m_UDiv(const LHS &L, const RHS &R) {
633732
return BinaryOpc_match<LHS, RHS>(ISD::UDIV, L, R);

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4190,26 +4190,26 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
41904190

41914191
// smax(a,b) - smin(a,b) --> abds(a,b)
41924192
if ((!LegalOperations || hasOperation(ISD::ABDS, VT)) &&
4193-
sd_match(N0, m_SMax(m_Value(A), m_Value(B))) &&
4194-
sd_match(N1, m_SMin(m_Specific(A), m_Specific(B))))
4193+
sd_match(N0, m_SMaxLike(m_Value(A), m_Value(B))) &&
4194+
sd_match(N1, m_SMinLike(m_Specific(A), m_Specific(B))))
41954195
return DAG.getNode(ISD::ABDS, DL, VT, A, B);
41964196

41974197
// smin(a,b) - smax(a,b) --> neg(abds(a,b))
41984198
if (hasOperation(ISD::ABDS, VT) &&
4199-
sd_match(N0, m_SMin(m_Value(A), m_Value(B))) &&
4200-
sd_match(N1, m_SMax(m_Specific(A), m_Specific(B))))
4199+
sd_match(N0, m_SMinLike(m_Value(A), m_Value(B))) &&
4200+
sd_match(N1, m_SMaxLike(m_Specific(A), m_Specific(B))))
42014201
return DAG.getNegative(DAG.getNode(ISD::ABDS, DL, VT, A, B), DL, VT);
42024202

42034203
// umax(a,b) - umin(a,b) --> abdu(a,b)
42044204
if ((!LegalOperations || hasOperation(ISD::ABDU, VT)) &&
4205-
sd_match(N0, m_UMax(m_Value(A), m_Value(B))) &&
4206-
sd_match(N1, m_UMin(m_Specific(A), m_Specific(B))))
4205+
sd_match(N0, m_UMaxLike(m_Value(A), m_Value(B))) &&
4206+
sd_match(N1, m_UMinLike(m_Specific(A), m_Specific(B))))
42074207
return DAG.getNode(ISD::ABDU, DL, VT, A, B);
42084208

42094209
// umin(a,b) - umax(a,b) --> neg(abdu(a,b))
42104210
if (hasOperation(ISD::ABDU, VT) &&
4211-
sd_match(N0, m_UMin(m_Value(A), m_Value(B))) &&
4212-
sd_match(N1, m_UMax(m_Specific(A), m_Specific(B))))
4211+
sd_match(N0, m_UMinLike(m_Value(A), m_Value(B))) &&
4212+
sd_match(N1, m_UMaxLike(m_Specific(A), m_Specific(B))))
42134213
return DAG.getNegative(DAG.getNode(ISD::ABDU, DL, VT, A, B), DL, VT);
42144214

42154215
return SDValue();

llvm/test/CodeGen/AArch64/abds.ll

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -547,10 +547,9 @@ define i8 @abd_select_i8(i8 %a, i8 %b) nounwind {
547547
; CHECK-LABEL: abd_select_i8:
548548
; CHECK: // %bb.0:
549549
; CHECK-NEXT: sxtb w8, w0
550-
; CHECK-NEXT: cmp w8, w1, sxtb
551-
; CHECK-NEXT: csel w8, w0, w1, lt
552-
; CHECK-NEXT: csel w9, w1, w0, lt
553-
; CHECK-NEXT: sub w0, w9, w8
550+
; CHECK-NEXT: sub w8, w8, w1, sxtb
551+
; CHECK-NEXT: cmp w8, #0
552+
; CHECK-NEXT: cneg w0, w8, mi
554553
; CHECK-NEXT: ret
555554
%cmp = icmp slt i8 %a, %b
556555
%ab = select i1 %cmp, i8 %a, i8 %b
@@ -563,10 +562,9 @@ define i16 @abd_select_i16(i16 %a, i16 %b) nounwind {
563562
; CHECK-LABEL: abd_select_i16:
564563
; CHECK: // %bb.0:
565564
; CHECK-NEXT: sxth w8, w0
566-
; CHECK-NEXT: cmp w8, w1, sxth
567-
; CHECK-NEXT: csel w8, w0, w1, le
568-
; CHECK-NEXT: csel w9, w1, w0, le
569-
; CHECK-NEXT: sub w0, w9, w8
565+
; CHECK-NEXT: sub w8, w8, w1, sxth
566+
; CHECK-NEXT: cmp w8, #0
567+
; CHECK-NEXT: cneg w0, w8, mi
570568
; CHECK-NEXT: ret
571569
%cmp = icmp sle i16 %a, %b
572570
%ab = select i1 %cmp, i16 %a, i16 %b
@@ -578,10 +576,9 @@ define i16 @abd_select_i16(i16 %a, i16 %b) nounwind {
578576
define i32 @abd_select_i32(i32 %a, i32 %b) nounwind {
579577
; CHECK-LABEL: abd_select_i32:
580578
; CHECK: // %bb.0:
581-
; CHECK-NEXT: cmp w0, w1
582-
; CHECK-NEXT: csel w8, w0, w1, gt
583-
; CHECK-NEXT: csel w9, w1, w0, gt
584-
; CHECK-NEXT: sub w0, w8, w9
579+
; CHECK-NEXT: sub w8, w1, w0
580+
; CHECK-NEXT: subs w9, w0, w1
581+
; CHECK-NEXT: csel w0, w9, w8, gt
585582
; CHECK-NEXT: ret
586583
%cmp = icmp sgt i32 %a, %b
587584
%ab = select i1 %cmp, i32 %a, i32 %b
@@ -593,10 +590,9 @@ define i32 @abd_select_i32(i32 %a, i32 %b) nounwind {
593590
define i64 @abd_select_i64(i64 %a, i64 %b) nounwind {
594591
; CHECK-LABEL: abd_select_i64:
595592
; CHECK: // %bb.0:
596-
; CHECK-NEXT: cmp x0, x1
597-
; CHECK-NEXT: csel x8, x0, x1, ge
598-
; CHECK-NEXT: csel x9, x1, x0, ge
599-
; CHECK-NEXT: sub x0, x8, x9
593+
; CHECK-NEXT: sub x8, x1, x0
594+
; CHECK-NEXT: subs x9, x0, x1
595+
; CHECK-NEXT: csel x0, x9, x8, gt
600596
; CHECK-NEXT: ret
601597
%cmp = icmp sge i64 %a, %b
602598
%ab = select i1 %cmp, i64 %a, i64 %b
@@ -608,14 +604,13 @@ define i64 @abd_select_i64(i64 %a, i64 %b) nounwind {
608604
define i128 @abd_select_i128(i128 %a, i128 %b) nounwind {
609605
; CHECK-LABEL: abd_select_i128:
610606
; CHECK: // %bb.0:
611-
; CHECK-NEXT: cmp x0, x2
612-
; CHECK-NEXT: sbcs xzr, x1, x3
613-
; CHECK-NEXT: csel x8, x0, x2, lt
614-
; CHECK-NEXT: csel x9, x2, x0, lt
615-
; CHECK-NEXT: csel x10, x1, x3, lt
616-
; CHECK-NEXT: csel x11, x3, x1, lt
617-
; CHECK-NEXT: subs x0, x9, x8
618-
; CHECK-NEXT: sbc x1, x11, x10
607+
; CHECK-NEXT: subs x8, x0, x2
608+
; CHECK-NEXT: sbc x9, x1, x3
609+
; CHECK-NEXT: subs x10, x2, x0
610+
; CHECK-NEXT: sbc x11, x3, x1
611+
; CHECK-NEXT: sbcs xzr, x3, x1
612+
; CHECK-NEXT: csel x0, x8, x10, lt
613+
; CHECK-NEXT: csel x1, x9, x11, lt
619614
; CHECK-NEXT: ret
620615
%cmp = icmp slt i128 %a, %b
621616
%ab = select i1 %cmp, i128 %a, i128 %b

llvm/test/CodeGen/AArch64/abdu.ll

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -408,10 +408,9 @@ define i8 @abd_select_i8(i8 %a, i8 %b) nounwind {
408408
; CHECK-LABEL: abd_select_i8:
409409
; CHECK: // %bb.0:
410410
; CHECK-NEXT: and w8, w0, #0xff
411-
; CHECK-NEXT: cmp w8, w1, uxtb
412-
; CHECK-NEXT: csel w8, w0, w1, lo
413-
; CHECK-NEXT: csel w9, w1, w0, lo
414-
; CHECK-NEXT: sub w0, w9, w8
411+
; CHECK-NEXT: sub w8, w8, w1, uxtb
412+
; CHECK-NEXT: cmp w8, #0
413+
; CHECK-NEXT: cneg w0, w8, mi
415414
; CHECK-NEXT: ret
416415
%cmp = icmp ult i8 %a, %b
417416
%ab = select i1 %cmp, i8 %a, i8 %b
@@ -424,10 +423,9 @@ define i16 @abd_select_i16(i16 %a, i16 %b) nounwind {
424423
; CHECK-LABEL: abd_select_i16:
425424
; CHECK: // %bb.0:
426425
; CHECK-NEXT: and w8, w0, #0xffff
427-
; CHECK-NEXT: cmp w8, w1, uxth
428-
; CHECK-NEXT: csel w8, w0, w1, ls
429-
; CHECK-NEXT: csel w9, w1, w0, ls
430-
; CHECK-NEXT: sub w0, w9, w8
426+
; CHECK-NEXT: sub w8, w8, w1, uxth
427+
; CHECK-NEXT: cmp w8, #0
428+
; CHECK-NEXT: cneg w0, w8, mi
431429
; CHECK-NEXT: ret
432430
%cmp = icmp ule i16 %a, %b
433431
%ab = select i1 %cmp, i16 %a, i16 %b
@@ -439,10 +437,9 @@ define i16 @abd_select_i16(i16 %a, i16 %b) nounwind {
439437
define i32 @abd_select_i32(i32 %a, i32 %b) nounwind {
440438
; CHECK-LABEL: abd_select_i32:
441439
; CHECK: // %bb.0:
442-
; CHECK-NEXT: cmp w0, w1
443-
; CHECK-NEXT: csel w8, w0, w1, hi
444-
; CHECK-NEXT: csel w9, w1, w0, hi
445-
; CHECK-NEXT: sub w0, w8, w9
440+
; CHECK-NEXT: sub w8, w1, w0
441+
; CHECK-NEXT: subs w9, w0, w1
442+
; CHECK-NEXT: csel w0, w9, w8, hi
446443
; CHECK-NEXT: ret
447444
%cmp = icmp ugt i32 %a, %b
448445
%ab = select i1 %cmp, i32 %a, i32 %b
@@ -454,10 +451,9 @@ define i32 @abd_select_i32(i32 %a, i32 %b) nounwind {
454451
define i64 @abd_select_i64(i64 %a, i64 %b) nounwind {
455452
; CHECK-LABEL: abd_select_i64:
456453
; CHECK: // %bb.0:
457-
; CHECK-NEXT: cmp x0, x1
458-
; CHECK-NEXT: csel x8, x0, x1, hs
459-
; CHECK-NEXT: csel x9, x1, x0, hs
460-
; CHECK-NEXT: sub x0, x8, x9
454+
; CHECK-NEXT: sub x8, x1, x0
455+
; CHECK-NEXT: subs x9, x0, x1
456+
; CHECK-NEXT: csel x0, x9, x8, hi
461457
; CHECK-NEXT: ret
462458
%cmp = icmp uge i64 %a, %b
463459
%ab = select i1 %cmp, i64 %a, i64 %b
@@ -469,14 +465,14 @@ define i64 @abd_select_i64(i64 %a, i64 %b) nounwind {
469465
define i128 @abd_select_i128(i128 %a, i128 %b) nounwind {
470466
; CHECK-LABEL: abd_select_i128:
471467
; CHECK: // %bb.0:
472-
; CHECK-NEXT: cmp x0, x2
473-
; CHECK-NEXT: sbcs xzr, x1, x3
474-
; CHECK-NEXT: csel x8, x0, x2, lo
475-
; CHECK-NEXT: csel x9, x2, x0, lo
476-
; CHECK-NEXT: csel x10, x1, x3, lo
477-
; CHECK-NEXT: csel x11, x3, x1, lo
478-
; CHECK-NEXT: subs x0, x9, x8
479-
; CHECK-NEXT: sbc x1, x11, x10
468+
; CHECK-NEXT: subs x8, x0, x2
469+
; CHECK-NEXT: sbcs x9, x1, x3
470+
; CHECK-NEXT: cset w10, lo
471+
; CHECK-NEXT: sbfx x10, x10, #0, #1
472+
; CHECK-NEXT: eor x8, x8, x10
473+
; CHECK-NEXT: eor x9, x9, x10
474+
; CHECK-NEXT: subs x0, x8, x10
475+
; CHECK-NEXT: sbc x1, x9, x10
480476
; CHECK-NEXT: ret
481477
%cmp = icmp ult i128 %a, %b
482478
%ab = select i1 %cmp, i128 %a, i128 %b

0 commit comments

Comments
 (0)