@@ -610,28 +610,82 @@ 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
+ // Get version of LHS/RHS with clearer signbit. This allows us to detect
636
+ // how the addition/subtraction might overflow into the signbit. Then
637
+ // using the actual known signbits of LHS/RHS, we can figure out which
638
+ // overflows are/aren't possible.
639
+ UnsignedLHS.One .clearSignBit ();
640
+ UnsignedLHS.Zero .setSignBit ();
641
+ UnsignedRHS.One .clearSignBit ();
642
+ UnsignedRHS.Zero .setSignBit ();
643
+ KnownBits Res =
644
+ KnownBits::computeForAddSub (Add, /* NSW=*/ false ,
645
+ /* NUW=*/ false , UnsignedLHS, UnsignedRHS);
625
646
if (Add) {
626
- // sadd.sat
627
- Overflow = (LHS.isNonNegative () == RHS.isNonNegative () &&
628
- Res.isNonNegative () != LHS.isNonNegative ());
647
+ if (Res.isNegative ()) {
648
+ // Only overflow scenario is Pos + Pos.
649
+ MayNegClamp = false ;
650
+ // Pos + Pos will overflow with extra signbit.
651
+ if (LHS.isNonNegative () && RHS.isNonNegative ())
652
+ Overflow = true ;
653
+ } else if (Res.isNonNegative ()) {
654
+ // Only overflow scenario is Neg + Neg
655
+ MayPosClamp = false ;
656
+ // Neg + Neg will overflow without extra signbit.
657
+ if (LHS.isNegative () && RHS.isNegative ())
658
+ Overflow = true ;
659
+ }
660
+ // We will never clamp to the opposite sign of N-bit result.
661
+ if (LHS.isNegative () || RHS.isNegative ())
662
+ MayPosClamp = false ;
663
+ if (LHS.isNonNegative () || RHS.isNonNegative ())
664
+ MayNegClamp = false ;
629
665
} else {
630
- // ssub.sat
631
- Overflow = (LHS.isNonNegative () != RHS.isNonNegative () &&
632
- Res.isNonNegative () != LHS.isNonNegative ());
666
+ if (Res.isNegative ()) {
667
+ // Only overflow scenario is Neg - Pos.
668
+ MayPosClamp = false ;
669
+ // Neg - Pos will overflow with extra signbit.
670
+ if (LHS.isNegative () && RHS.isNonNegative ())
671
+ Overflow = true ;
672
+ } else if (Res.isNonNegative ()) {
673
+ // Only overflow scenario is Pos - Neg.
674
+ MayNegClamp = false ;
675
+ // Pos - Neg will overflow without extra signbit.
676
+ if (LHS.isNonNegative () && RHS.isNegative ())
677
+ Overflow = true ;
678
+ }
679
+ // We will never clamp to the opposite sign of N-bit result.
680
+ if (LHS.isNegative () || RHS.isNonNegative ())
681
+ MayPosClamp = false ;
682
+ if (LHS.isNonNegative () || RHS.isNegative ())
683
+ MayNegClamp = false ;
633
684
}
634
685
}
686
+ // If we have ruled out all clamping, we will never overflow.
687
+ if (!MayNegClamp && !MayPosClamp)
688
+ Overflow = false ;
635
689
} else if (Add) {
636
690
// uadd.sat
637
691
bool Of;
@@ -656,52 +710,8 @@ static KnownBits computeForSatAddSub(bool Add, bool Signed,
656
710
}
657
711
}
658
712
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
- }
713
+ KnownBits Res = KnownBits::computeForAddSub (Add, /* NSW=*/ Signed,
714
+ /* NUW=*/ !Signed, LHS, RHS);
705
715
706
716
if (Overflow) {
707
717
// We know whether or not we overflowed.
@@ -714,7 +724,7 @@ static KnownBits computeForSatAddSub(bool Add, bool Signed,
714
724
APInt C;
715
725
if (Signed) {
716
726
// sadd.sat / ssub.sat
717
- assert (SignBitKnown ( LHS) &&
727
+ assert (! LHS. isSignUnknown ( ) &&
718
728
" We somehow know overflow without knowing input sign" );
719
729
C = LHS.isNegative () ? APInt::getSignedMinValue (BitWidth)
720
730
: APInt::getSignedMaxValue (BitWidth);
@@ -735,8 +745,10 @@ static KnownBits computeForSatAddSub(bool Add, bool Signed,
735
745
if (Signed) {
736
746
// sadd.sat/ssub.sat
737
747
// We can keep our information about the sign bits.
738
- Res.Zero .clearLowBits (BitWidth - 1 );
739
- Res.One .clearLowBits (BitWidth - 1 );
748
+ if (MayPosClamp)
749
+ Res.Zero .clearLowBits (BitWidth - 1 );
750
+ if (MayNegClamp)
751
+ Res.One .clearLowBits (BitWidth - 1 );
740
752
} else if (Add) {
741
753
// uadd.sat
742
754
// We need to clear all the known zeros as we can only use the leading ones.
0 commit comments