Skip to content

Commit 746b21c

Browse files
AZero13github-actions[bot]
authored andcommitted
Automerge: [InstCombine] Add missing patterns for scmp and ucmp (#149225)
Fixes: [#146178](llvm/llvm-project#146178) https://alive2.llvm.org/ce/z/ZitMnX https://alive2.llvm.org/ce/z/aJZ2BQ
2 parents b2a45c6 + 49180d8 commit 746b21c

File tree

2 files changed

+303
-0
lines changed

2 files changed

+303
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3757,6 +3757,10 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder,
37573757
// (x < y) ? -1 : zext(x > y)
37583758
// (x > y) ? 1 : sext(x != y)
37593759
// (x > y) ? 1 : sext(x < y)
3760+
// (x == y) ? 0 : (x > y ? 1 : -1)
3761+
// (x == y) ? 0 : (x < y ? -1 : 1)
3762+
// Special case: x == C ? 0 : (x > C - 1 ? 1 : -1)
3763+
// Special case: x == C ? 0 : (x < C + 1 ? -1 : 1)
37603764
// Into ucmp/scmp(x, y), where signedness is determined by the signedness
37613765
// of the comparison in the original sequence.
37623766
Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
@@ -3849,6 +3853,44 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
38493853
}
38503854
}
38513855

3856+
// Special cases with constants: x == C ? 0 : (x > C-1 ? 1 : -1)
3857+
if (Pred == ICmpInst::ICMP_EQ && match(TV, m_Zero())) {
3858+
const APInt *C;
3859+
if (match(RHS, m_APInt(C))) {
3860+
CmpPredicate InnerPred;
3861+
Value *InnerRHS;
3862+
const APInt *InnerTV, *InnerFV;
3863+
if (match(FV,
3864+
m_Select(m_ICmp(InnerPred, m_Specific(LHS), m_Value(InnerRHS)),
3865+
m_APInt(InnerTV), m_APInt(InnerFV)))) {
3866+
3867+
// x == C ? 0 : (x > C-1 ? 1 : -1)
3868+
if (ICmpInst::isGT(InnerPred) && InnerTV->isOne() &&
3869+
InnerFV->isAllOnes()) {
3870+
IsSigned = ICmpInst::isSigned(InnerPred);
3871+
bool CanSubOne = IsSigned ? !C->isMinSignedValue() : !C->isMinValue();
3872+
if (CanSubOne) {
3873+
APInt Cminus1 = *C - 1;
3874+
if (match(InnerRHS, m_SpecificInt(Cminus1)))
3875+
Replace = true;
3876+
}
3877+
}
3878+
3879+
// x == C ? 0 : (x < C+1 ? -1 : 1)
3880+
if (ICmpInst::isLT(InnerPred) && InnerTV->isAllOnes() &&
3881+
InnerFV->isOne()) {
3882+
IsSigned = ICmpInst::isSigned(InnerPred);
3883+
bool CanAddOne = IsSigned ? !C->isMaxSignedValue() : !C->isMaxValue();
3884+
if (CanAddOne) {
3885+
APInt Cplus1 = *C + 1;
3886+
if (match(InnerRHS, m_SpecificInt(Cplus1)))
3887+
Replace = true;
3888+
}
3889+
}
3890+
}
3891+
}
3892+
}
3893+
38523894
Intrinsic::ID IID = IsSigned ? Intrinsic::scmp : Intrinsic::ucmp;
38533895
if (Replace)
38543896
return replaceInstUsesWith(

llvm/test/Transforms/InstCombine/scmp.ll

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,86 @@ define i8 @scmp_from_select_eq_and_gt_commuted3(i32 %x, i32 %y) {
423423
ret i8 %r
424424
}
425425

426+
; Commutative tests for (x != y) ? (x > y ? 1 : -1) : 0
427+
define i8 @scmp_from_select_ne_and_gt_commuted1(i32 %x, i32 %y) {
428+
; CHECK-LABEL: define i8 @scmp_from_select_ne_and_gt_commuted1(
429+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
430+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[Y]], i32 [[X]])
431+
; CHECK-NEXT: ret i8 [[R]]
432+
;
433+
%ne = icmp ne i32 %x, %y
434+
%gt = icmp slt i32 %x, %y
435+
%sel1 = select i1 %gt, i8 1, i8 -1
436+
%r = select i1 %ne, i8 %sel1, i8 0
437+
ret i8 %r
438+
}
439+
440+
define i8 @scmp_from_select_ne_and_gt_commuted2(i32 %x, i32 %y) {
441+
; CHECK-LABEL: define i8 @scmp_from_select_ne_and_gt_commuted2(
442+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
443+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[Y]], i32 [[X]])
444+
; CHECK-NEXT: ret i8 [[R]]
445+
;
446+
%ne = icmp ne i32 %x, %y
447+
%gt = icmp sgt i32 %x, %y
448+
%sel1 = select i1 %gt, i8 -1, i8 1
449+
%r = select i1 %ne, i8 %sel1, i8 0
450+
ret i8 %r
451+
}
452+
453+
define i8 @scmp_from_select_ne_and_gt_commuted3(i32 %x, i32 %y) {
454+
; CHECK-LABEL: define i8 @scmp_from_select_ne_and_gt_commuted3(
455+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
456+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
457+
; CHECK-NEXT: ret i8 [[R]]
458+
;
459+
%ne = icmp ne i32 %x, %y
460+
%gt = icmp sgt i32 %x, %y
461+
%sel1 = select i1 %gt, i8 1, i8 -1
462+
%r = select i1 %ne, i8 %sel1, i8 0
463+
ret i8 %r
464+
}
465+
466+
; Commutative tests for x != C ? (x > C - 1 ? 1 : -1) : 0
467+
define i8 @scmp_from_select_ne_const_and_gt_commuted1(i32 %x) {
468+
; CHECK-LABEL: define i8 @scmp_from_select_ne_const_and_gt_commuted1(
469+
; CHECK-SAME: i32 [[X:%.*]]) {
470+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 5)
471+
; CHECK-NEXT: ret i8 [[R]]
472+
;
473+
%ne = icmp ne i32 %x, 5
474+
%gt = icmp sgt i32 %x, 4
475+
%sel1 = select i1 %gt, i8 1, i8 -1
476+
%r = select i1 %ne, i8 %sel1, i8 0
477+
ret i8 %r
478+
}
479+
480+
define i8 @scmp_from_select_ne_const_and_gt_commuted2(i32 %x) {
481+
; CHECK-LABEL: define i8 @scmp_from_select_ne_const_and_gt_commuted2(
482+
; CHECK-SAME: i32 [[X:%.*]]) {
483+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 5)
484+
; CHECK-NEXT: ret i8 [[R]]
485+
;
486+
%ne = icmp ne i32 %x, 5
487+
%gt = icmp sgt i32 %x, 4
488+
%sel1 = select i1 %gt, i8 1, i8 -1
489+
%r = select i1 %ne, i8 %sel1, i8 0
490+
ret i8 %r
491+
}
492+
493+
define i8 @scmp_from_select_ne_const_and_gt_commuted3(i32 %x) {
494+
; CHECK-LABEL: define i8 @scmp_from_select_ne_const_and_gt_commuted3(
495+
; CHECK-SAME: i32 [[X:%.*]]) {
496+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 5)
497+
; CHECK-NEXT: ret i8 [[R]]
498+
;
499+
%ne = icmp ne i32 %x, 5
500+
%gt = icmp sgt i32 %x, 4
501+
%sel1 = select i1 %gt, i8 1, i8 -1
502+
%r = select i1 %ne, i8 %sel1, i8 0
503+
ret i8 %r
504+
}
505+
426506
define <3 x i2> @scmp_unary_shuffle_ops(<3 x i8> %x, <3 x i8> %y) {
427507
; CHECK-LABEL: define <3 x i2> @scmp_unary_shuffle_ops(
428508
; CHECK-SAME: <3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]]) {
@@ -436,6 +516,187 @@ define <3 x i2> @scmp_unary_shuffle_ops(<3 x i8> %x, <3 x i8> %y) {
436516
ret <3 x i2> %r
437517
}
438518

519+
define i32 @scmp_sgt_slt(i32 %a) {
520+
; CHECK-LABEL: define i32 @scmp_sgt_slt(
521+
; CHECK-SAME: i32 [[A:%.*]]) {
522+
; CHECK-NEXT: [[A_LOBIT:%.*]] = ashr i32 [[A]], 31
523+
; CHECK-NEXT: [[CMP_INV:%.*]] = icmp slt i32 [[A]], 1
524+
; CHECK-NEXT: [[RETVAL_0:%.*]] = select i1 [[CMP_INV]], i32 [[A_LOBIT]], i32 1
525+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
526+
;
527+
%cmp = icmp sgt i32 %a, 0
528+
%cmp1 = icmp slt i32 %a, 0
529+
%. = select i1 %cmp1, i32 -1, i32 0
530+
%retval.0 = select i1 %cmp, i32 1, i32 %.
531+
ret i32 %retval.0
532+
}
533+
534+
define i32 @scmp_zero_slt(i32 %a) {
535+
; CHECK-LABEL: define i32 @scmp_zero_slt(
536+
; CHECK-SAME: i32 [[A:%.*]]) {
537+
; CHECK-NEXT: [[RETVAL_0:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
538+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
539+
;
540+
%cmp = icmp eq i32 %a, 0
541+
%cmp1.inv = icmp slt i32 %a, 1
542+
%. = select i1 %cmp1.inv, i32 -1, i32 1
543+
%retval.0 = select i1 %cmp, i32 0, i32 %.
544+
ret i32 %retval.0
545+
}
546+
547+
define i32 @scmp_zero_sgt(i32 %a) {
548+
; CHECK-LABEL: define i32 @scmp_zero_sgt(
549+
; CHECK-SAME: i32 [[A:%.*]]) {
550+
; CHECK-NEXT: [[RETVAL_0:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
551+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
552+
;
553+
%cmp = icmp eq i32 %a, 0
554+
%cmp1.inv = icmp sgt i32 %a, -1
555+
%. = select i1 %cmp1.inv, i32 1, i32 -1
556+
%retval.0 = select i1 %cmp, i32 0, i32 %.
557+
ret i32 %retval.0
558+
}
559+
560+
561+
define i32 @scmp_zero_sgt_1(i32 %a) {
562+
; CHECK-LABEL: define i32 @scmp_zero_sgt_1(
563+
; CHECK-SAME: i32 [[A:%.*]]) {
564+
; CHECK-NEXT: [[COND2:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
565+
; CHECK-NEXT: ret i32 [[COND2]]
566+
;
567+
%cmp = icmp eq i32 %a, 0
568+
%cmp1 = icmp sgt i32 %a, -1
569+
%cond = select i1 %cmp1, i32 1, i32 -1
570+
%cond2 = select i1 %cmp, i32 0, i32 %cond
571+
ret i32 %cond2
572+
}
573+
574+
define i32 @scmp_zero_slt_1(i32 %a) {
575+
; CHECK-LABEL: define i32 @scmp_zero_slt_1(
576+
; CHECK-SAME: i32 [[A:%.*]]) {
577+
; CHECK-NEXT: [[COND2:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
578+
; CHECK-NEXT: ret i32 [[COND2]]
579+
;
580+
%cmp = icmp eq i32 %a, 0
581+
%cmp1 = icmp slt i32 %a, 1
582+
%cond = select i1 %cmp1, i32 -1, i32 1
583+
%cond2 = select i1 %cmp, i32 0, i32 %cond
584+
ret i32 %cond2
585+
}
586+
587+
define i32 @scmp_zero_slt_neg(i32 %a) {
588+
; CHECK-LABEL: define i32 @scmp_zero_slt_neg(
589+
; CHECK-SAME: i32 [[A:%.*]]) {
590+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
591+
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A]], -1
592+
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP1]], i32 -1, i32 1
593+
; CHECK-NEXT: [[COND2:%.*]] = select i1 [[CMP]], i32 0, i32 [[COND]]
594+
; CHECK-NEXT: ret i32 [[COND2]]
595+
;
596+
%cmp = icmp eq i32 %a, 0
597+
%cmp1 = icmp slt i32 %a, -1
598+
%cond = select i1 %cmp1, i32 -1, i32 1
599+
%cond2 = select i1 %cmp, i32 0, i32 %cond
600+
ret i32 %cond2
601+
}
602+
603+
define i32 @scmp_zero_sgt_neg(i32 %a) {
604+
; CHECK-LABEL: define i32 @scmp_zero_sgt_neg(
605+
; CHECK-SAME: i32 [[A:%.*]]) {
606+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
607+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A]], 1
608+
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP1]], i32 1, i32 -1
609+
; CHECK-NEXT: [[COND2:%.*]] = select i1 [[CMP]], i32 0, i32 [[COND]]
610+
; CHECK-NEXT: ret i32 [[COND2]]
611+
;
612+
%cmp = icmp eq i32 %a, 0
613+
%cmp1 = icmp sgt i32 %a, 1
614+
%cond = select i1 %cmp1, i32 1, i32 -1
615+
%cond2 = select i1 %cmp, i32 0, i32 %cond
616+
ret i32 %cond2
617+
}
618+
619+
define i32 @ucmp_ugt_ult_neg(i32 %a) {
620+
; CHECK-LABEL: define i32 @ucmp_ugt_ult_neg(
621+
; CHECK-SAME: i32 [[A:%.*]]) {
622+
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp ne i32 [[A]], 0
623+
; CHECK-NEXT: [[RETVAL_0:%.*]] = zext i1 [[CMP_NOT]] to i32
624+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
625+
;
626+
%cmp = icmp ugt i32 %a, 0
627+
%cmp1 = icmp ult i32 %a, 0
628+
%. = select i1 %cmp1, i32 -1, i32 0
629+
%retval.0 = select i1 %cmp, i32 1, i32 %.
630+
ret i32 %retval.0
631+
}
632+
633+
define i32 @ucmp_zero_ult_neg(i32 %a) {
634+
; CHECK-LABEL: define i32 @ucmp_zero_ult_neg(
635+
; CHECK-SAME: i32 [[A:%.*]]) {
636+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A]], 0
637+
; CHECK-NEXT: [[RETVAL_0:%.*]] = zext i1 [[CMP]] to i32
638+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
639+
;
640+
%cmp = icmp eq i32 %a, 0
641+
%cmp1.inv = icmp ult i32 %a, 1
642+
%. = select i1 %cmp1.inv, i32 -1, i32 1
643+
%retval.0 = select i1 %cmp, i32 0, i32 %.
644+
ret i32 %retval.0
645+
}
646+
647+
define i32 @ucmp_zero_ugt_neg(i32 %a) {
648+
; CHECK-LABEL: define i32 @ucmp_zero_ugt_neg(
649+
; CHECK-SAME: i32 [[A:%.*]]) {
650+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A]], 0
651+
; CHECK-NEXT: [[RETVAL_0:%.*]] = sext i1 [[CMP]] to i32
652+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
653+
;
654+
%cmp = icmp eq i32 %a, 0
655+
%cmp1.inv = icmp ugt i32 %a, -1
656+
%. = select i1 %cmp1.inv, i32 1, i32 -1
657+
%retval.0 = select i1 %cmp, i32 0, i32 %.
658+
ret i32 %retval.0
659+
}
660+
661+
define i32 @scmp_sgt_slt_ab(i32 %a, i32 %b) {
662+
; CHECK-LABEL: define i32 @scmp_sgt_slt_ab(
663+
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
664+
; CHECK-NEXT: [[RETVAL_0:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 [[B]])
665+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
666+
;
667+
%cmp = icmp sgt i32 %a, %b
668+
%cmp1 = icmp slt i32 %a, %b
669+
%. = select i1 %cmp1, i32 -1, i32 0
670+
%retval.0 = select i1 %cmp, i32 1, i32 %.
671+
ret i32 %retval.0
672+
}
673+
674+
define i32 @scmp_zero_slt_ab(i32 %a, i32 %b) {
675+
; CHECK-LABEL: define i32 @scmp_zero_slt_ab(
676+
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
677+
; CHECK-NEXT: [[RETVAL_0:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 [[B]])
678+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
679+
;
680+
%cmp = icmp eq i32 %a, %b
681+
%cmp1.inv = icmp slt i32 %a, %b
682+
%. = select i1 %cmp1.inv, i32 -1, i32 1
683+
%retval.0 = select i1 %cmp, i32 0, i32 %.
684+
ret i32 %retval.0
685+
}
686+
687+
define i32 @scmp_zero_sgt_ab(i32 %a, i32 %b) {
688+
; CHECK-LABEL: define i32 @scmp_zero_sgt_ab(
689+
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
690+
; CHECK-NEXT: [[RETVAL_0:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 [[B]])
691+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
692+
;
693+
%cmp = icmp eq i32 %a, %b
694+
%cmp1.inv = icmp sgt i32 %a, %b
695+
%. = select i1 %cmp1.inv, i32 1, i32 -1
696+
%retval.0 = select i1 %cmp, i32 0, i32 %.
697+
ret i32 %retval.0
698+
}
699+
439700
; Negative test: true value of outer select is not zero
440701
define i8 @scmp_from_select_eq_and_gt_neg1(i32 %x, i32 %y) {
441702
; CHECK-LABEL: define i8 @scmp_from_select_eq_and_gt_neg1(

0 commit comments

Comments
 (0)