@@ -610,28 +610,78 @@ static KnownBits computeForSatAddSub(bool Add, bool Signed,
610
610
const KnownBits &RHS) {
611
611
// We don't see NSW even for sadd/ssub as we want to check if the result has
612
612
// signed overflow.
613
- KnownBits Res =
614
- KnownBits::computeForAddSub (Add, /* NSW=*/ false , /* NUW=*/ false , LHS, RHS);
615
- unsigned BitWidth = Res.getBitWidth ();
616
- auto SignBitKnown = [&](const KnownBits &K) {
617
- return K.Zero [BitWidth - 1 ] || K.One [BitWidth - 1 ];
618
- };
619
- std::optional<bool > Overflow;
613
+ unsigned BitWidth = LHS.getBitWidth ();
620
614
615
+ std::optional<bool > Overflow;
616
+ // Even if we can't entirely rule out overflow, we may be able to rule out
617
+ // overflow in one direction. This allows us to potentially keep some of the
618
+ // add/sub bits. I.e if we can't overflow in the positive direction we won't
619
+ // clamp to INT_MAX so we can keep low 0s from the add/sub result.
620
+ bool MayNegClamp = true ;
621
+ bool MayPosClamp = true ;
621
622
if (Signed) {
622
- // If we can actually detect overflow do so. Otherwise leave Overflow as
623
- // nullopt (we assume it may have happened).
624
- if (SignBitKnown (LHS) && SignBitKnown (RHS) && SignBitKnown (Res)) {
623
+ // Easy cases we can rule out any overflow.
624
+ if (Add && ((LHS.isNegative () && RHS.isNonNegative ()) ||
625
+ (LHS.isNonNegative () && RHS.isNegative ())))
626
+ Overflow = false ;
627
+ else if (!Add && (((LHS.isNegative () && RHS.isNegative ()) ||
628
+ (LHS.isNonNegative () && RHS.isNonNegative ()))))
629
+ Overflow = false ;
630
+ else {
631
+ // Check if we may overflow. If we can't rule out overflow then check if
632
+ // we can rule out a direction at least.
633
+ KnownBits UnsignedLHS = LHS;
634
+ KnownBits UnsignedRHS = RHS;
635
+ UnsignedLHS.One .clearSignBit ();
636
+ UnsignedLHS.Zero .setSignBit ();
637
+ UnsignedRHS.One .clearSignBit ();
638
+ UnsignedRHS.Zero .setSignBit ();
639
+ KnownBits Res =
640
+ KnownBits::computeForAddSub (Add, /* NSW=*/ false ,
641
+ /* NUW=*/ false , UnsignedLHS, UnsignedRHS);
625
642
if (Add) {
626
- // sadd.sat
627
- Overflow = (LHS.isNonNegative () == RHS.isNonNegative () &&
628
- Res.isNonNegative () != LHS.isNonNegative ());
643
+ if (Res.isNegative ()) {
644
+ // Only overflow scenario is Pos + Pos.
645
+ MayNegClamp = false ;
646
+ // Pos + Pos will overflow with extra signbit.
647
+ if (LHS.isNonNegative () && RHS.isNonNegative ())
648
+ Overflow = true ;
649
+ } else if (Res.isNonNegative ()) {
650
+ // Only overflow scenario is Neg + Neg
651
+ MayPosClamp = false ;
652
+ // Neg + Neg will overflow without extra signbit.
653
+ if (LHS.isNegative () && RHS.isNegative ())
654
+ Overflow = true ;
655
+ }
656
+ // We will never clamp to the opposite sign of N-bit result.
657
+ if (LHS.isNegative () || RHS.isNegative ())
658
+ MayPosClamp = false ;
659
+ if (LHS.isNonNegative () || RHS.isNonNegative ())
660
+ MayNegClamp = false ;
629
661
} else {
630
- // ssub.sat
631
- Overflow = (LHS.isNonNegative () != RHS.isNonNegative () &&
632
- Res.isNonNegative () != LHS.isNonNegative ());
662
+ if (Res.isNegative ()) {
663
+ // Only overflow scenario is Neg - Pos.
664
+ MayPosClamp = false ;
665
+ // Neg - Pos will overflow with extra signbit.
666
+ if (LHS.isNegative () && RHS.isNonNegative ())
667
+ Overflow = true ;
668
+ } else if (Res.isNonNegative ()) {
669
+ // Only overflow scenario is Pos - Neg.
670
+ MayNegClamp = false ;
671
+ // Pos - Neg will overflow without extra signbit.
672
+ if (LHS.isNonNegative () && RHS.isNegative ())
673
+ Overflow = true ;
674
+ }
675
+ // We will never clamp to the opposite sign of N-bit result.
676
+ if (LHS.isNegative () || RHS.isNonNegative ())
677
+ MayPosClamp = false ;
678
+ if (LHS.isNonNegative () || RHS.isNegative ())
679
+ MayNegClamp = false ;
633
680
}
634
681
}
682
+ // If we have ruled out all clamping, we will never overflow.
683
+ if (!MayNegClamp && !MayPosClamp)
684
+ Overflow = false ;
635
685
} else if (Add) {
636
686
// uadd.sat
637
687
bool Of;
@@ -656,52 +706,8 @@ static KnownBits computeForSatAddSub(bool Add, bool Signed,
656
706
}
657
707
}
658
708
659
- if (Signed) {
660
- if (Add) {
661
- if (LHS.isNonNegative () && RHS.isNonNegative ()) {
662
- // Pos + Pos -> Pos
663
- Res.One .clearSignBit ();
664
- Res.Zero .setSignBit ();
665
- }
666
- if (LHS.isNegative () && RHS.isNegative ()) {
667
- // Neg + Neg -> Neg
668
- Res.One .setSignBit ();
669
- Res.Zero .clearSignBit ();
670
- }
671
- } else {
672
- if (LHS.isNegative () && RHS.isNonNegative ()) {
673
- // Neg - Pos -> Neg
674
- Res.One .setSignBit ();
675
- Res.Zero .clearSignBit ();
676
- } else if (LHS.isNonNegative () && RHS.isNegative ()) {
677
- // Pos - Neg -> Pos
678
- Res.One .clearSignBit ();
679
- Res.Zero .setSignBit ();
680
- }
681
- }
682
- } else {
683
- // Add: Leading ones of either operand are preserved.
684
- // Sub: Leading zeros of LHS and leading ones of RHS are preserved
685
- // as leading zeros in the result.
686
- unsigned LeadingKnown;
687
- if (Add)
688
- LeadingKnown =
689
- std::max (LHS.countMinLeadingOnes (), RHS.countMinLeadingOnes ());
690
- else
691
- LeadingKnown =
692
- std::max (LHS.countMinLeadingZeros (), RHS.countMinLeadingOnes ());
693
-
694
- // We select between the operation result and all-ones/zero
695
- // respectively, so we can preserve known ones/zeros.
696
- APInt Mask = APInt::getHighBitsSet (BitWidth, LeadingKnown);
697
- if (Add) {
698
- Res.One |= Mask;
699
- Res.Zero &= ~Mask;
700
- } else {
701
- Res.Zero |= Mask;
702
- Res.One &= ~Mask;
703
- }
704
- }
709
+ KnownBits Res = KnownBits::computeForAddSub (Add, /* NSW=*/ Signed,
710
+ /* NUW=*/ !Signed, LHS, RHS);
705
711
706
712
if (Overflow) {
707
713
// We know whether or not we overflowed.
@@ -714,7 +720,7 @@ static KnownBits computeForSatAddSub(bool Add, bool Signed,
714
720
APInt C;
715
721
if (Signed) {
716
722
// sadd.sat / ssub.sat
717
- assert (SignBitKnown ( LHS) &&
723
+ assert (! LHS. isSignUnknown ( ) &&
718
724
" We somehow know overflow without knowing input sign" );
719
725
C = LHS.isNegative () ? APInt::getSignedMinValue (BitWidth)
720
726
: APInt::getSignedMaxValue (BitWidth);
@@ -735,8 +741,10 @@ static KnownBits computeForSatAddSub(bool Add, bool Signed,
735
741
if (Signed) {
736
742
// sadd.sat/ssub.sat
737
743
// We can keep our information about the sign bits.
738
- Res.Zero .clearLowBits (BitWidth - 1 );
739
- Res.One .clearLowBits (BitWidth - 1 );
744
+ if (MayPosClamp)
745
+ Res.Zero .clearLowBits (BitWidth - 1 );
746
+ if (MayNegClamp)
747
+ Res.One .clearLowBits (BitWidth - 1 );
740
748
} else if (Add) {
741
749
// uadd.sat
742
750
// We need to clear all the known zeros as we can only use the leading ones.
0 commit comments