Skip to content

Commit 02000e5

Browse files
committed
[InstCombine] Add missing patterns for scmp and ucmp
Fixes: #146178
1 parent 6cbf72c commit 02000e5

File tree

2 files changed

+196
-14
lines changed

2 files changed

+196
-14
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3635,6 +3635,12 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder,
36353635
// (x < y) ? -1 : zext(x > y)
36363636
// (x > y) ? 1 : sext(x != y)
36373637
// (x > y) ? 1 : sext(x < y)
3638+
// (x == y) ? 0 : (x > y ? 1 : -1)
3639+
// (x == y) ? 0 : (x < y ? -1 : 1)
3640+
// Special cases: x == C ? 0 : (x > C - 1 ? 1 : -1) and
3641+
// Special cases: x == C ? 0 : (x < C - 1 ? -1 : 1) and
3642+
// Special cases: x == C ? 0 : (x > C + 1 ? 1 : -1) and
3643+
// Special cases: x == C ? 0 : (x < C + 1 ? -1 : 1)
36383644
// Into ucmp/scmp(x, y), where signedness is determined by the signedness
36393645
// of the comparison in the original sequence.
36403646
Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
@@ -3703,6 +3709,7 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
37033709
Replace = true;
37043710

37053711
// (x == y) ? 0 : (x > y ? 1 : -1)
3712+
// (x == y) ? 0 : (x < y ? -1 : 1)
37063713
CmpPredicate FalseBranchSelectPredicate;
37073714
const APInt *InnerTV, *InnerFV;
37083715
if (Pred == ICmpInst::ICMP_EQ && match(TV, m_Zero()) &&
@@ -3715,18 +3722,94 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
37153722
std::swap(LHS, RHS);
37163723
}
37173724

3725+
// Check if we need to canonicalize the select values
37183726
if (!InnerTV->isOne()) {
37193727
std::swap(InnerTV, InnerFV);
37203728
std::swap(LHS, RHS);
37213729
}
37223730

3731+
// Handle (x == y) ? 0 : (x > y ? 1 : -1) or its equivalent forms
37233732
if (ICmpInst::isGT(FalseBranchSelectPredicate) && InnerTV->isOne() &&
37243733
InnerFV->isAllOnes()) {
37253734
IsSigned = ICmpInst::isSigned(FalseBranchSelectPredicate);
37263735
Replace = true;
37273736
}
37283737
}
37293738

3739+
// Special cases: x == C ? 0 : (x > C-1 ? 1 : -1), etc.
3740+
if (Pred == ICmpInst::ICMP_EQ && match(TV, m_Zero())) {
3741+
Value *X;
3742+
const APInt *C;
3743+
if (match(LHS, m_Value(X)) && match(RHS, m_APInt(C))) {
3744+
3745+
// Match the nested select - no canonicalization, match each pattern
3746+
// directly
3747+
CmpPredicate InnerPred;
3748+
Value *InnerLHS, *InnerRHS;
3749+
const APInt *InnerTV, *InnerFV;
3750+
if (match(FV, m_Select(
3751+
m_ICmp(InnerPred, m_Value(InnerLHS), m_Value(InnerRHS)),
3752+
m_APInt(InnerTV), m_APInt(InnerFV)))) {
3753+
3754+
// x == C ? 0 : (x > C-1 ? 1 : -1)
3755+
if (ICmpInst::isGT(InnerPred) && InnerTV->isOne() &&
3756+
InnerFV->isAllOnes()) {
3757+
IsSigned = ICmpInst::isSigned(InnerPred);
3758+
bool CanSubOne = IsSigned ? !C->isMinSignedValue() : !C->isMinValue();
3759+
if (CanSubOne) {
3760+
APInt Cminus1 = *C - 1;
3761+
if ((InnerLHS == X && match(InnerRHS, m_SpecificInt(Cminus1))) ||
3762+
(InnerRHS == X && match(InnerLHS, m_SpecificInt(Cminus1)))) {
3763+
Replace = true;
3764+
}
3765+
}
3766+
}
3767+
3768+
// x == C ? 0 : (x < C+1 ? -1 : 1)
3769+
if (ICmpInst::isLT(InnerPred) && InnerTV->isAllOnes() &&
3770+
InnerFV->isOne()) {
3771+
IsSigned = ICmpInst::isSigned(InnerPred);
3772+
bool CanAddOne = IsSigned ? !C->isMaxSignedValue() : !C->isMaxValue();
3773+
if (CanAddOne) {
3774+
APInt CPlus1 = *C + 1;
3775+
if ((InnerLHS == X && match(InnerRHS, m_SpecificInt(CPlus1))) ||
3776+
(InnerRHS == X && match(InnerLHS, m_SpecificInt(CPlus1)))) {
3777+
Replace = true;
3778+
}
3779+
}
3780+
}
3781+
3782+
// x == C ? 0 : (x > C-1 ? 1 : -1)
3783+
if (ICmpInst::isGT(InnerPred) && InnerTV->isOne() &&
3784+
InnerFV->isAllOnes()) {
3785+
IsSigned = ICmpInst::isSigned(InnerPred);
3786+
bool CanSubOne = IsSigned ? !C->isMinSignedValue() : !C->isMinValue();
3787+
if (CanSubOne) {
3788+
APInt CMinusOne = *C - 1;
3789+
if ((InnerLHS == X && match(InnerRHS, m_SpecificInt(CMinusOne))) ||
3790+
(InnerRHS == X && match(InnerLHS, m_SpecificInt(CMinusOne)))) {
3791+
Replace = true;
3792+
}
3793+
}
3794+
}
3795+
3796+
// x == C ? 0 : (x < C+1 ? -1 : 1)
3797+
if (ICmpInst::isLT(InnerPred) && InnerTV->isAllOnes() &&
3798+
InnerFV->isOne()) {
3799+
IsSigned = ICmpInst::isSigned(InnerPred);
3800+
bool CanAddOne = IsSigned ? !C->isMaxSignedValue() : !C->isMaxValue();
3801+
if (CanAddOne) {
3802+
APInt Cplus1 = *C + 1;
3803+
if ((InnerLHS == X && match(InnerRHS, m_SpecificInt(Cplus1))) ||
3804+
(InnerRHS == X && match(InnerLHS, m_SpecificInt(Cplus1)))) {
3805+
Replace = true;
3806+
}
3807+
}
3808+
}
3809+
}
3810+
}
3811+
}
3812+
37303813
Intrinsic::ID IID = IsSigned ? Intrinsic::scmp : Intrinsic::ucmp;
37313814
if (Replace)
37323815
return replaceInstUsesWith(
@@ -4496,5 +4579,20 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
44964579
return replaceOperand(SI, 2, ConstantInt::get(FalseVal->getType(), 0));
44974580
}
44984581

4582+
// Canonicalize sign function ashr pattern: select (icmp slt X, 1), ashr X,
4583+
// bitwidth-1, 1 -> scmp(X, 0)
4584+
Value *X;
4585+
unsigned BitWidth = SI.getType()->getScalarSizeInBits();
4586+
CmpPredicate Pred;
4587+
if (match(&SI, m_Select(m_ICmp(Pred, m_Value(X), m_One()),
4588+
m_AShr(m_Deferred(X), m_SpecificInt(BitWidth - 1)),
4589+
m_One())) &&
4590+
Pred == ICmpInst::ICMP_SLT) {
4591+
4592+
Function *Scmp = Intrinsic::getOrInsertDeclaration(
4593+
SI.getModule(), Intrinsic::scmp, {SI.getType(), SI.getType()});
4594+
return CallInst::Create(Scmp, {X, ConstantInt::get(SI.getType(), 0)});
4595+
}
4596+
44994597
return nullptr;
45004598
}

llvm/test/Transforms/InstCombine/scmp.ll

Lines changed: 98 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -439,9 +439,7 @@ define <3 x i2> @scmp_unary_shuffle_ops(<3 x i8> %x, <3 x i8> %y) {
439439
define i32 @scmp_ashr(i32 %a) {
440440
; CHECK-LABEL: define i32 @scmp_ashr(
441441
; CHECK-SAME: i32 [[A:%.*]]) {
442-
; CHECK-NEXT: [[A_LOBIT:%.*]] = ashr i32 [[A]], 31
443-
; CHECK-NEXT: [[CMP_INV:%.*]] = icmp slt i32 [[A]], 1
444-
; CHECK-NEXT: [[RETVAL_0:%.*]] = select i1 [[CMP_INV]], i32 [[A_LOBIT]], i32 1
442+
; CHECK-NEXT: [[RETVAL_0:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
445443
; CHECK-NEXT: ret i32 [[RETVAL_0]]
446444
;
447445
%a.lobit = ashr i32 %a, 31
@@ -453,9 +451,7 @@ define i32 @scmp_ashr(i32 %a) {
453451
define i32 @scmp_sgt_slt(i32 %a) {
454452
; CHECK-LABEL: define i32 @scmp_sgt_slt(
455453
; CHECK-SAME: i32 [[A:%.*]]) {
456-
; CHECK-NEXT: [[A_LOBIT:%.*]] = ashr i32 [[A]], 31
457-
; CHECK-NEXT: [[CMP_INV:%.*]] = icmp slt i32 [[A]], 1
458-
; CHECK-NEXT: [[RETVAL_0:%.*]] = select i1 [[CMP_INV]], i32 [[A_LOBIT]], i32 1
454+
; CHECK-NEXT: [[RETVAL_0:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
459455
; CHECK-NEXT: ret i32 [[RETVAL_0]]
460456
;
461457
%cmp = icmp sgt i32 %a, 0
@@ -468,10 +464,7 @@ define i32 @scmp_sgt_slt(i32 %a) {
468464
define i32 @scmp_zero_slt(i32 %a) {
469465
; CHECK-LABEL: define i32 @scmp_zero_slt(
470466
; CHECK-SAME: i32 [[A:%.*]]) {
471-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
472-
; CHECK-NEXT: [[CMP1_INV:%.*]] = icmp slt i32 [[A]], 1
473-
; CHECK-NEXT: [[DOT:%.*]] = select i1 [[CMP1_INV]], i32 -1, i32 1
474-
; CHECK-NEXT: [[RETVAL_0:%.*]] = select i1 [[CMP]], i32 0, i32 [[DOT]]
467+
; CHECK-NEXT: [[RETVAL_0:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
475468
; CHECK-NEXT: ret i32 [[RETVAL_0]]
476469
;
477470
%cmp = icmp eq i32 %a, 0
@@ -484,10 +477,7 @@ define i32 @scmp_zero_slt(i32 %a) {
484477
define i32 @scmp_zero_sgt(i32 %a) {
485478
; CHECK-LABEL: define i32 @scmp_zero_sgt(
486479
; CHECK-SAME: i32 [[A:%.*]]) {
487-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
488-
; CHECK-NEXT: [[CMP1_INV:%.*]] = icmp sgt i32 [[A]], -1
489-
; CHECK-NEXT: [[DOT:%.*]] = select i1 [[CMP1_INV]], i32 1, i32 -1
490-
; CHECK-NEXT: [[RETVAL_0:%.*]] = select i1 [[CMP]], i32 0, i32 [[DOT]]
480+
; CHECK-NEXT: [[RETVAL_0:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
491481
; CHECK-NEXT: ret i32 [[RETVAL_0]]
492482
;
493483
%cmp = icmp eq i32 %a, 0
@@ -498,6 +488,100 @@ define i32 @scmp_zero_sgt(i32 %a) {
498488
}
499489

500490

491+
define i32 @scmp_zero_sgt_1(i32 %a) {
492+
; CHECK-LABEL: define i32 @scmp_zero_sgt_1(
493+
; CHECK-SAME: i32 [[A:%.*]]) {
494+
; CHECK-NEXT: [[COND2:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
495+
; CHECK-NEXT: ret i32 [[COND2]]
496+
;
497+
%cmp = icmp eq i32 %a, 0
498+
%cmp1 = icmp sgt i32 %a, -1
499+
%cond = select i1 %cmp1, i32 1, i32 -1
500+
%cond2 = select i1 %cmp, i32 0, i32 %cond
501+
ret i32 %cond2
502+
}
503+
504+
define i32 @scmp_zero_slt_1(i32 %a) {
505+
; CHECK-LABEL: define i32 @scmp_zero_slt_1(
506+
; CHECK-SAME: i32 [[A:%.*]]) {
507+
; CHECK-NEXT: [[COND2:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
508+
; CHECK-NEXT: ret i32 [[COND2]]
509+
;
510+
%cmp = icmp eq i32 %a, 0
511+
%cmp1 = icmp slt i32 %a, 1
512+
%cond = select i1 %cmp1, i32 -1, i32 1
513+
%cond2 = select i1 %cmp, i32 0, i32 %cond
514+
ret i32 %cond2
515+
}
516+
517+
define i32 @scmp_zero_slt_2(i32 %a) {
518+
; CHECK-LABEL: define i32 @scmp_zero_slt_2(
519+
; CHECK-SAME: i32 [[A:%.*]]) {
520+
; CHECK-NEXT: [[COND2:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
521+
; CHECK-NEXT: ret i32 [[COND2]]
522+
;
523+
%cmp = icmp eq i32 %a, 0
524+
%cmp1 = icmp slt i32 %a, -1
525+
%cond = select i1 %cmp1, i32 -1, i32 1
526+
%cond2 = select i1 %cmp, i32 0, i32 %cond
527+
ret i32 %cond2
528+
}
529+
530+
define i32 @scmp_zero_sgt_2(i32 %a) {
531+
; CHECK-LABEL: define i32 @scmp_zero_sgt_2(
532+
; CHECK-SAME: i32 [[A:%.*]]) {
533+
; CHECK-NEXT: [[COND2:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[A]], i32 0)
534+
; CHECK-NEXT: ret i32 [[COND2]]
535+
;
536+
%cmp = icmp eq i32 %a, 0
537+
%cmp1 = icmp sgt i32 %a, 1
538+
%cond = select i1 %cmp1, i32 1, i32 -1
539+
%cond2 = select i1 %cmp, i32 0, i32 %cond
540+
ret i32 %cond2
541+
}
542+
543+
define i32 @ucmp_sgt_slt_neg(i32 %a) {
544+
; CHECK-LABEL: define i32 @ucmp_sgt_slt_neg(
545+
; CHECK-SAME: i32 [[A:%.*]]) {
546+
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp ne i32 [[A]], 0
547+
; CHECK-NEXT: [[RETVAL_0:%.*]] = zext i1 [[CMP_NOT]] to i32
548+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
549+
;
550+
%cmp = icmp ugt i32 %a, 0
551+
%cmp1 = icmp ult i32 %a, 0
552+
%. = select i1 %cmp1, i32 -1, i32 0
553+
%retval.0 = select i1 %cmp, i32 1, i32 %.
554+
ret i32 %retval.0
555+
}
556+
557+
define i32 @ucmp_zero_slt_neg(i32 %a) {
558+
; CHECK-LABEL: define i32 @ucmp_zero_slt_neg(
559+
; CHECK-SAME: i32 [[A:%.*]]) {
560+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A]], 0
561+
; CHECK-NEXT: [[RETVAL_0:%.*]] = zext i1 [[CMP]] to i32
562+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
563+
;
564+
%cmp = icmp eq i32 %a, 0
565+
%cmp1.inv = icmp ult i32 %a, 1
566+
%. = select i1 %cmp1.inv, i32 -1, i32 1
567+
%retval.0 = select i1 %cmp, i32 0, i32 %.
568+
ret i32 %retval.0
569+
}
570+
571+
define i32 @ucmp_zero_sgt_neg(i32 %a) {
572+
; CHECK-LABEL: define i32 @ucmp_zero_sgt_neg(
573+
; CHECK-SAME: i32 [[A:%.*]]) {
574+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A]], 0
575+
; CHECK-NEXT: [[RETVAL_0:%.*]] = sext i1 [[CMP]] to i32
576+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
577+
;
578+
%cmp = icmp eq i32 %a, 0
579+
%cmp1.inv = icmp ugt i32 %a, -1
580+
%. = select i1 %cmp1.inv, i32 1, i32 -1
581+
%retval.0 = select i1 %cmp, i32 0, i32 %.
582+
ret i32 %retval.0
583+
}
584+
501585
define i32 @scmp_sgt_slt_ab(i32 %a, i32 %b) {
502586
; CHECK-LABEL: define i32 @scmp_sgt_slt_ab(
503587
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {

0 commit comments

Comments
 (0)