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