@@ -528,3 +528,147 @@ void ConstantFPRange::flushDenormals(DenormalMode::DenormalModeKind Mode) {
528528 Lower = minnum (Lower, APFloat::getZero (Sem, ZeroLowerNegative));
529529 Upper = maxnum (Upper, APFloat::getZero (Sem, ZeroUpperNegative));
530530}
531+
532+ // / Represent a contiguous range of values sharing the same sign.
533+ struct SameSignRange {
534+ bool HasZero;
535+ bool HasNonZero;
536+ bool HasInf;
537+ // The lower and upper bounds of the range (inclusive).
538+ // The sign is dropped and infinities are excluded.
539+ std::optional<std::pair<APFloat, APFloat>> FinitePart;
540+
541+ explicit SameSignRange (const APFloat &Lower, const APFloat &Upper)
542+ : HasZero(Lower.isZero()), HasNonZero(!Upper.isZero()),
543+ HasInf(Upper.isInfinity()) {
544+ assert (!Lower.isNegative () && !Upper.isNegative () &&
545+ " The sign should be dropped." );
546+ assert (strictCompare (Lower, Upper) != APFloat::cmpGreaterThan &&
547+ " Empty set." );
548+ if (!Lower.isInfinity ())
549+ FinitePart = {Lower,
550+ HasInf ? APFloat::getLargest (Lower.getSemantics ()) : Upper};
551+ }
552+ };
553+
554+ // / Split the range into positive and negative components.
555+ static void splitPosNeg (const APFloat &Lower, const APFloat &Upper,
556+ std::optional<SameSignRange> &NegPart,
557+ std::optional<SameSignRange> &PosPart) {
558+ assert (strictCompare (Lower, Upper) != APFloat::cmpGreaterThan &&
559+ " Non-NaN part is empty." );
560+ if (Lower.isNegative () == Upper.isNegative ()) {
561+ if (Lower.isNegative ())
562+ NegPart = SameSignRange{abs (Upper), abs (Lower)};
563+ else
564+ PosPart = SameSignRange{Lower, Upper};
565+ return ;
566+ }
567+ auto &Sem = Lower.getSemantics ();
568+ NegPart = SameSignRange{APFloat::getZero (Sem), abs (Lower)};
569+ PosPart = SameSignRange{APFloat::getZero (Sem), Upper};
570+ }
571+
572+ ConstantFPRange ConstantFPRange::mul (const ConstantFPRange &Other) const {
573+ auto &Sem = getSemantics ();
574+ bool ResMayBeQNaN = ((MayBeQNaN || MayBeSNaN) && !Other.isEmptySet ()) ||
575+ ((Other.MayBeQNaN || Other.MayBeSNaN ) && !isEmptySet ());
576+ if (isNaNOnly () || Other.isNaNOnly ())
577+ return getNaNOnly (Sem, /* MayBeQNaN=*/ ResMayBeQNaN,
578+ /* MayBeSNaN=*/ false );
579+ std::optional<SameSignRange> LHSNeg, LHSPos, RHSNeg, RHSPos;
580+ splitPosNeg (Lower, Upper, LHSNeg, LHSPos);
581+ splitPosNeg (Other.Lower , Other.Upper , RHSNeg, RHSPos);
582+ APFloat ResLower = APFloat::getInf (Sem, /* Negative=*/ false );
583+ APFloat ResUpper = APFloat::getInf (Sem, /* Negative=*/ true );
584+ auto Update = [&](std::optional<SameSignRange> &LHS,
585+ std::optional<SameSignRange> &RHS, bool Negative) {
586+ if (!LHS || !RHS)
587+ return ;
588+ // 0 * inf = QNaN
589+ ResMayBeQNaN |= LHS->HasZero && RHS->HasInf ;
590+ ResMayBeQNaN |= RHS->HasZero && LHS->HasInf ;
591+ // NonZero * inf = inf
592+ if ((LHS->HasInf && RHS->HasNonZero ) || (RHS->HasInf && LHS->HasNonZero ))
593+ (Negative ? ResLower : ResUpper) = APFloat::getInf (Sem, Negative);
594+ // Finite * Finite
595+ if (LHS->FinitePart && RHS->FinitePart ) {
596+ APFloat NewLower = LHS->FinitePart ->first * RHS->FinitePart ->first ;
597+ APFloat NewUpper = LHS->FinitePart ->second * RHS->FinitePart ->second ;
598+ if (Negative) {
599+ ResLower = minnum (ResLower, -NewUpper);
600+ ResUpper = maxnum (ResUpper, -NewLower);
601+ } else {
602+ ResLower = minnum (ResLower, NewLower);
603+ ResUpper = maxnum (ResUpper, NewUpper);
604+ }
605+ }
606+ };
607+ Update (LHSNeg, RHSNeg, /* Negative=*/ false );
608+ Update (LHSNeg, RHSPos, /* Negative=*/ true );
609+ Update (LHSPos, RHSNeg, /* Negative=*/ true );
610+ Update (LHSPos, RHSPos, /* Negative=*/ false );
611+ return ConstantFPRange (ResLower, ResUpper, ResMayBeQNaN, /* MayBeSNaN=*/ false );
612+ }
613+
614+ ConstantFPRange ConstantFPRange::div (const ConstantFPRange &Other) const {
615+ auto &Sem = getSemantics ();
616+ bool ResMayBeQNaN = ((MayBeQNaN || MayBeSNaN) && !Other.isEmptySet ()) ||
617+ ((Other.MayBeQNaN || Other.MayBeSNaN ) && !isEmptySet ());
618+ if (isNaNOnly () || Other.isNaNOnly ())
619+ return getNaNOnly (Sem, /* MayBeQNaN=*/ ResMayBeQNaN,
620+ /* MayBeSNaN=*/ false );
621+ std::optional<SameSignRange> LHSNeg, LHSPos, RHSNeg, RHSPos;
622+ splitPosNeg (Lower, Upper, LHSNeg, LHSPos);
623+ splitPosNeg (Other.Lower , Other.Upper , RHSNeg, RHSPos);
624+ APFloat ResLower = APFloat::getInf (Sem, /* Negative=*/ false );
625+ APFloat ResUpper = APFloat::getInf (Sem, /* Negative=*/ true );
626+ auto Update = [&](std::optional<SameSignRange> &LHS,
627+ std::optional<SameSignRange> &RHS, bool Negative) {
628+ if (!LHS || !RHS)
629+ return ;
630+ // inf / inf = QNaN 0 / 0 = QNaN
631+ ResMayBeQNaN |= LHS->HasInf && RHS->HasInf ;
632+ ResMayBeQNaN |= LHS->HasZero && RHS->HasZero ;
633+ // It is not straightforward to infer HasNonZeroFinite = HasFinite &&
634+ // HasNonZero. By definitions we have:
635+ // HasFinite = HasNonZeroFinite || HasZero
636+ // HasNonZero = HasNonZeroFinite || HasInf
637+ // Since the range is contiguous, if both HasFinite and HasNonZero are true,
638+ // HasNonZeroFinite must be true.
639+ bool LHSHasNonZeroFinite = LHS->FinitePart && LHS->HasNonZero ;
640+ bool RHSHasNonZeroFinite = RHS->FinitePart && RHS->HasNonZero ;
641+ // inf / Finite = inf FiniteNonZero / 0 = inf
642+ if ((LHS->HasInf && RHS->FinitePart ) ||
643+ (LHSHasNonZeroFinite && RHS->HasZero ))
644+ (Negative ? ResLower : ResUpper) = APFloat::getInf (Sem, Negative);
645+ // Finite / inf = 0
646+ if (LHS->FinitePart && RHS->HasInf ) {
647+ APFloat Zero = APFloat::getZero (Sem, /* Negative=*/ Negative);
648+ ResLower = minnum (ResLower, Zero);
649+ ResUpper = maxnum (ResUpper, Zero);
650+ }
651+ // Finite / FiniteNonZero
652+ if (LHS->FinitePart && RHSHasNonZeroFinite) {
653+ assert (!RHS->FinitePart ->second .isZero () &&
654+ " Divisor should be non-zero." );
655+ APFloat NewLower = LHS->FinitePart ->first / RHS->FinitePart ->second ;
656+ APFloat NewUpper = LHS->FinitePart ->second /
657+ (RHS->FinitePart ->first .isZero ()
658+ ? APFloat::getSmallest (Sem, /* Negative=*/ false )
659+ : RHS->FinitePart ->first );
660+ if (Negative) {
661+ ResLower = minnum (ResLower, -NewUpper);
662+ ResUpper = maxnum (ResUpper, -NewLower);
663+ } else {
664+ ResLower = minnum (ResLower, NewLower);
665+ ResUpper = maxnum (ResUpper, NewUpper);
666+ }
667+ }
668+ };
669+ Update (LHSNeg, RHSNeg, /* Negative=*/ false );
670+ Update (LHSNeg, RHSPos, /* Negative=*/ true );
671+ Update (LHSPos, RHSNeg, /* Negative=*/ true );
672+ Update (LHSPos, RHSPos, /* Negative=*/ false );
673+ return ConstantFPRange (ResLower, ResUpper, ResMayBeQNaN, /* MayBeSNaN=*/ false );
674+ }
0 commit comments