@@ -3635,6 +3635,12 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder,
3635
3635
// (x < y) ? -1 : zext(x > y)
3636
3636
// (x > y) ? 1 : sext(x != y)
3637
3637
// (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)
3638
3644
// Into ucmp/scmp(x, y), where signedness is determined by the signedness
3639
3645
// of the comparison in the original sequence.
3640
3646
Instruction *InstCombinerImpl::foldSelectToCmp (SelectInst &SI) {
@@ -3680,10 +3686,12 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
3680
3686
Pred = ICmpInst::getSwappedPredicate (Pred);
3681
3687
std::swap (LHS, RHS);
3682
3688
}
3689
+
3683
3690
bool IsSigned = ICmpInst::isSigned (Pred);
3684
3691
3685
3692
bool Replace = false ;
3686
3693
CmpPredicate ExtendedCmpPredicate;
3694
+
3687
3695
// (x < y) ? -1 : zext(x != y)
3688
3696
// (x < y) ? -1 : zext(x > y)
3689
3697
if (ICmpInst::isLT (Pred) && match (TV, m_AllOnes ()) &&
@@ -3703,34 +3711,134 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
3703
3711
Replace = true ;
3704
3712
3705
3713
// (x == y) ? 0 : (x > y ? 1 : -1)
3714
+ // (x == y) ? 0 : (x < y ? -1 : 1)
3706
3715
CmpPredicate FalseBranchSelectPredicate;
3707
3716
const APInt *InnerTV, *InnerFV;
3708
3717
if (Pred == ICmpInst::ICMP_EQ && match (TV, m_Zero ()) &&
3709
3718
match (FV, m_Select (m_c_ICmp (FalseBranchSelectPredicate, m_Specific (LHS),
3710
3719
m_Specific (RHS)),
3711
3720
m_APInt (InnerTV), m_APInt (InnerFV)))) {
3712
- if (!ICmpInst::isGT (FalseBranchSelectPredicate)) {
3713
- FalseBranchSelectPredicate =
3714
- ICmpInst::getSwappedPredicate (FalseBranchSelectPredicate);
3715
- std::swap (LHS, RHS);
3721
+
3722
+ // Check if we need to canonicalize the comparison predicate
3723
+ bool PredicateSwapped = false ;
3724
+ if (!ICmpInst::isGT (FalseBranchSelectPredicate) && !ICmpInst::isLT (FalseBranchSelectPredicate)) {
3725
+ // Not a GT or LT, nothing to do
3726
+ } else if (!ICmpInst::isGT (FalseBranchSelectPredicate)) {
3727
+ // We have LT, see if swapping gives us GT
3728
+ CmpPredicate SwappedPred = ICmpInst::getSwappedPredicate (FalseBranchSelectPredicate);
3729
+ if (ICmpInst::isGT (SwappedPred)) {
3730
+ FalseBranchSelectPredicate = SwappedPred;
3731
+ PredicateSwapped = true ;
3732
+ }
3716
3733
}
3717
3734
3718
- if (!InnerTV->isOne ()) {
3735
+ // Check if we need to canonicalize the select values
3736
+ bool ValuesSwapped = false ;
3737
+ if (!InnerTV->isOne () && InnerFV->isOne ()) {
3719
3738
std::swap (InnerTV, InnerFV);
3720
- std::swap (LHS, RHS) ;
3739
+ ValuesSwapped = true ;
3721
3740
}
3722
3741
3742
+ // Handle (x == y) ? 0 : (x > y ? 1 : -1) or its equivalent forms
3723
3743
if (ICmpInst::isGT (FalseBranchSelectPredicate) && InnerTV->isOne () &&
3724
3744
InnerFV->isAllOnes ()) {
3725
3745
IsSigned = ICmpInst::isSigned (FalseBranchSelectPredicate);
3746
+ // If we swapped the predicate XOR swapped the values, we need to swap LHS/RHS for scmp
3747
+ if (PredicateSwapped != ValuesSwapped) {
3748
+ std::swap (LHS, RHS);
3749
+ }
3750
+ Replace = true ;
3751
+ }
3752
+ // Handle (x == y) ? 0 : (x < y ? -1 : 1) or its equivalent forms
3753
+ else if (ICmpInst::isLT (FalseBranchSelectPredicate) && InnerTV->isAllOnes () &&
3754
+ InnerFV->isOne ()) {
3755
+ IsSigned = ICmpInst::isSigned (FalseBranchSelectPredicate);
3756
+ // For LT pattern, operand order is already correct
3726
3757
Replace = true ;
3727
3758
}
3728
3759
}
3729
3760
3761
+
3762
+
3763
+ // Special cases: x == C ? 0 : (x > C-1 ? 1 : -1), etc.
3764
+ if (Pred == ICmpInst::ICMP_EQ && match (TV, m_Zero ())) {
3765
+ Value *X;
3766
+ const APInt *C;
3767
+ if (match (LHS, m_Value (X)) && match (RHS, m_APInt (C))) {
3768
+
3769
+ // Match the nested select - no canonicalization, match each pattern
3770
+ // directly
3771
+ CmpPredicate InnerPred;
3772
+ Value *InnerLHS, *InnerRHS;
3773
+ const APInt *InnerTV, *InnerFV;
3774
+ if (match (FV, m_Select (
3775
+ m_ICmp (InnerPred, m_Value (InnerLHS), m_Value (InnerRHS)),
3776
+ m_APInt (InnerTV), m_APInt (InnerFV)))) {
3777
+
3778
+ // x == C ? 0 : (x > C-1 ? 1 : -1)
3779
+ if (ICmpInst::isGT (InnerPred) && InnerTV->isOne () &&
3780
+ InnerFV->isAllOnes ()) {
3781
+ IsSigned = ICmpInst::isSigned (InnerPred);
3782
+ bool CanSubOne = IsSigned ? !C->isMinSignedValue () : !C->isMinValue ();
3783
+ if (CanSubOne) {
3784
+ APInt Cminus1 = *C - 1 ;
3785
+ if ((InnerLHS == X && match (InnerRHS, m_SpecificInt (Cminus1))) ||
3786
+ (InnerRHS == X && match (InnerLHS, m_SpecificInt (Cminus1)))) {
3787
+ Replace = true ;
3788
+ }
3789
+ }
3790
+ }
3791
+
3792
+ // x == C ? 0 : (x < C-1 ? -1 : 1)
3793
+ if (ICmpInst::isLT (InnerPred) && InnerTV->isAllOnes () &&
3794
+ InnerFV->isOne ()) {
3795
+ IsSigned = ICmpInst::isSigned (InnerPred);
3796
+ bool CanSubOne = IsSigned ? !C->isMinSignedValue () : !C->isMinValue ();
3797
+ if (CanSubOne) {
3798
+ APInt Cminus1 = *C - 1 ;
3799
+ if ((InnerLHS == X && match (InnerRHS, m_SpecificInt (Cminus1))) ||
3800
+ (InnerRHS == X && match (InnerLHS, m_SpecificInt (Cminus1)))) {
3801
+ Replace = true ;
3802
+ }
3803
+ }
3804
+ }
3805
+
3806
+ // x == C ? 0 : (x > C+1 ? 1 : -1)
3807
+ if (ICmpInst::isGT (InnerPred) && InnerTV->isOne () &&
3808
+ InnerFV->isAllOnes ()) {
3809
+ IsSigned = ICmpInst::isSigned (InnerPred);
3810
+ bool CanAddOne = IsSigned ? !C->isMaxSignedValue () : !C->isMaxValue ();
3811
+ if (CanAddOne) {
3812
+ APInt Cplus1 = *C + 1 ;
3813
+ if ((InnerLHS == X && match (InnerRHS, m_SpecificInt (Cplus1))) ||
3814
+ (InnerRHS == X && match (InnerLHS, m_SpecificInt (Cplus1)))) {
3815
+ Replace = true ;
3816
+ }
3817
+ }
3818
+ }
3819
+
3820
+ // x == C ? 0 : (x < C+1 ? -1 : 1)
3821
+ if (ICmpInst::isLT (InnerPred) && InnerTV->isAllOnes () &&
3822
+ InnerFV->isOne ()) {
3823
+ IsSigned = ICmpInst::isSigned (InnerPred);
3824
+ bool CanAddOne = IsSigned ? !C->isMaxSignedValue () : !C->isMaxValue ();
3825
+ if (CanAddOne) {
3826
+ APInt Cplus1 = *C + 1 ;
3827
+ if ((InnerLHS == X && match (InnerRHS, m_SpecificInt (Cplus1))) ||
3828
+ (InnerRHS == X && match (InnerLHS, m_SpecificInt (Cplus1)))) {
3829
+ Replace = true ;
3830
+ }
3831
+ }
3832
+ }
3833
+ }
3834
+ }
3835
+ }
3836
+
3730
3837
Intrinsic::ID IID = IsSigned ? Intrinsic::scmp : Intrinsic::ucmp;
3731
3838
if (Replace)
3732
3839
return replaceInstUsesWith (
3733
3840
SI, Builder.CreateIntrinsic (SI.getType (), IID, {LHS, RHS}));
3841
+
3734
3842
return nullptr ;
3735
3843
}
3736
3844
@@ -4496,5 +4604,21 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
4496
4604
return replaceOperand (SI, 2 , ConstantInt::get (FalseVal->getType (), 0 ));
4497
4605
}
4498
4606
4607
+ // Canonicalize sign function ashr pattern: select (icmp slt X, 1), ashr X, bitwidth-1, 1 -> scmp(X, 0)
4608
+ Value *X;
4609
+ unsigned BitWidth = SI.getType ()->getScalarSizeInBits ();
4610
+ CmpPredicate Pred;
4611
+ if (match (&SI,
4612
+ m_Select (
4613
+ m_ICmp (Pred, m_Value (X), m_One ()),
4614
+ m_AShr (m_Deferred (X), m_SpecificInt (BitWidth - 1 )),
4615
+ m_One ())) &&
4616
+ Pred == ICmpInst::ICMP_SLT) {
4617
+
4618
+ Function *Scmp = Intrinsic::getOrInsertDeclaration (
4619
+ SI.getModule (), Intrinsic::scmp, {SI.getType (), SI.getType ()});
4620
+ return CallInst::Create (Scmp, {X, ConstantInt::get (SI.getType (), 0 )});
4621
+ }
4622
+
4499
4623
return nullptr ;
4500
4624
}
0 commit comments