@@ -564,4 +564,183 @@ TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
564564#endif
565565}
566566
567+ TEST_F (ConstantFPRangeTest, makeSatisfyingFCmpRegion) {
568+ EXPECT_EQ (ConstantFPRange::makeSatisfyingFCmpRegion (
569+ FCmpInst::FCMP_OLE,
570+ ConstantFPRange::getNonNaN (APFloat (1.0 ), APFloat (2.0 ))),
571+ ConstantFPRange::getNonNaN (APFloat::getInf (Sem, /* Negative=*/ true ),
572+ APFloat (1.0 )));
573+ EXPECT_EQ (
574+ ConstantFPRange::makeSatisfyingFCmpRegion (
575+ FCmpInst::FCMP_OLT, ConstantFPRange::getNonNaN (
576+ APFloat::getSmallest (Sem, /* Negative=*/ false ),
577+ APFloat::getInf (Sem, /* Negative=*/ false ))),
578+ ConstantFPRange::getNonNaN (APFloat::getInf (Sem, /* Negative=*/ true ),
579+ APFloat::getZero (Sem, /* Negative=*/ false )));
580+ EXPECT_EQ (
581+ ConstantFPRange::makeSatisfyingFCmpRegion (
582+ FCmpInst::FCMP_OGT, ConstantFPRange::getNonNaN (
583+ APFloat::getZero (Sem, /* Negative=*/ true ),
584+ APFloat::getZero (Sem, /* Negative=*/ false ))),
585+ ConstantFPRange::getNonNaN (APFloat::getSmallest (Sem, /* Negative=*/ false ),
586+ APFloat::getInf (Sem, /* Negative=*/ false )));
587+ EXPECT_EQ (ConstantFPRange::makeSatisfyingFCmpRegion (
588+ FCmpInst::FCMP_OGE,
589+ ConstantFPRange::getNonNaN (APFloat (1.0 ), APFloat (2.0 ))),
590+ ConstantFPRange::getNonNaN (
591+ APFloat (2.0 ), APFloat::getInf (Sem, /* Negative=*/ false )));
592+ EXPECT_EQ (ConstantFPRange::makeSatisfyingFCmpRegion (
593+ FCmpInst::FCMP_OEQ,
594+ ConstantFPRange::getNonNaN (APFloat (1.0 ), APFloat (2.0 ))),
595+ ConstantFPRange::getEmpty (Sem));
596+ EXPECT_EQ (ConstantFPRange::makeSatisfyingFCmpRegion (
597+ FCmpInst::FCMP_OEQ,
598+ ConstantFPRange::getNonNaN (APFloat (1.0 ), APFloat (1.0 ))),
599+ ConstantFPRange::getNonNaN (APFloat (1.0 ), APFloat (1.0 )));
600+
601+ #if defined(EXPENSIVE_CHECKS)
602+ for (auto Pred : FCmpInst::predicates ()) {
603+ EnumerateConstantFPRanges (
604+ [Pred](const ConstantFPRange &CR) {
605+ ConstantFPRange Res =
606+ ConstantFPRange::makeSatisfyingFCmpRegion (Pred, CR);
607+ // Super set of the optimal set excluding NaNs
608+ ConstantFPRange SuperSet (CR.getSemantics ());
609+ bool ContainsSNaN = false ;
610+ bool ContainsQNaN = false ;
611+ unsigned NonNaNValsInOptimalSet = 0 ;
612+ EnumerateValuesInConstantFPRange (
613+ ConstantFPRange::getFull (CR.getSemantics ()),
614+ [&](const APFloat &V) {
615+ if (AnyOfValueInConstantFPRange (
616+ CR,
617+ [&](const APFloat &U) {
618+ return !FCmpInst::compare (V, U, Pred);
619+ },
620+ /* IgnoreNaNPayload=*/ true )) {
621+ EXPECT_FALSE (Res.contains (V))
622+ << " Wrong result for makeSatisfyingFCmpRegion(" << Pred
623+ << " , " << CR << " ). The result " << Res
624+ << " should not contain " << V;
625+ } else {
626+ if (V.isNaN ()) {
627+ if (V.isSignaling ())
628+ ContainsSNaN = true ;
629+ else
630+ ContainsQNaN = true ;
631+ } else {
632+ SuperSet = SuperSet.unionWith (ConstantFPRange (V));
633+ ++NonNaNValsInOptimalSet;
634+ }
635+ }
636+ },
637+ /* IgnoreNaNPayload=*/ true );
638+
639+ // Check optimality
640+
641+ // The usefullness of making the result optimal for one/une is
642+ // questionable.
643+ if (Pred == FCmpInst::FCMP_ONE || Pred == FCmpInst::FCMP_UNE)
644+ return ;
645+
646+ EXPECT_FALSE (ContainsSNaN && !Res.containsSNaN ())
647+ << " Suboptimal result for makeSatisfyingFCmpRegion(" << Pred
648+ << " , " << CR << " ), should contain SNaN, but got " << Res;
649+ EXPECT_FALSE (ContainsQNaN && !Res.containsQNaN ())
650+ << " Suboptimal result for makeSatisfyingFCmpRegion(" << Pred
651+ << " , " << CR << " ), should contain QNaN, but got " << Res;
652+
653+ // We only care about the cases where the result is representable by
654+ // ConstantFPRange.
655+ unsigned NonNaNValsInSuperSet = 0 ;
656+ EnumerateValuesInConstantFPRange (
657+ SuperSet,
658+ [&](const APFloat &V) {
659+ if (!V.isNaN ())
660+ ++NonNaNValsInSuperSet;
661+ },
662+ /* IgnoreNaNPayload=*/ true );
663+
664+ if (NonNaNValsInSuperSet == NonNaNValsInOptimalSet) {
665+ ConstantFPRange Optimal =
666+ ConstantFPRange (SuperSet.getLower (), SuperSet.getUpper (),
667+ ContainsQNaN, ContainsSNaN);
668+ EXPECT_EQ (Res, Optimal)
669+ << " Suboptimal result for makeSatisfyingFCmpRegion(" << Pred
670+ << " , " << CR << " )" ;
671+ }
672+ },
673+ /* Exhaustive=*/ false );
674+ }
675+ #endif
676+ }
677+
678+ TEST_F (ConstantFPRangeTest, fcmp) {
679+ std::vector<ConstantFPRange> InterestingRanges;
680+ const fltSemantics &Sem = APFloat::Float8E4M3 ();
681+ auto FpImm = [&](double V) {
682+ bool ignored;
683+ APFloat APF (V);
684+ APF.convert (Sem, APFloat::rmNearestTiesToEven, &ignored);
685+ return APF;
686+ };
687+
688+ InterestingRanges.push_back (ConstantFPRange::getEmpty (Sem));
689+ InterestingRanges.push_back (ConstantFPRange::getFull (Sem));
690+ InterestingRanges.push_back (ConstantFPRange::getFinite (Sem));
691+ InterestingRanges.push_back (ConstantFPRange (FpImm (1.0 )));
692+ InterestingRanges.push_back (
693+ ConstantFPRange (APFloat::getZero (Sem, /* Negative=*/ false )));
694+ InterestingRanges.push_back (
695+ ConstantFPRange (APFloat::getZero (Sem, /* Negative=*/ true )));
696+ InterestingRanges.push_back (
697+ ConstantFPRange (APFloat::getInf (Sem, /* Negative=*/ false )));
698+ InterestingRanges.push_back (
699+ ConstantFPRange (APFloat::getInf (Sem, /* Negative=*/ true )));
700+ InterestingRanges.push_back (
701+ ConstantFPRange (APFloat::getSmallest (Sem, /* Negative=*/ false )));
702+ InterestingRanges.push_back (
703+ ConstantFPRange (APFloat::getSmallest (Sem, /* Negative=*/ true )));
704+ InterestingRanges.push_back (
705+ ConstantFPRange (APFloat::getLargest (Sem, /* Negative=*/ false )));
706+ InterestingRanges.push_back (
707+ ConstantFPRange (APFloat::getLargest (Sem, /* Negative=*/ true )));
708+ InterestingRanges.push_back (
709+ ConstantFPRange::getNaNOnly (Sem, /* MayBeQNaN=*/ true , /* MayBeSNaN=*/ true ));
710+ InterestingRanges.push_back (
711+ ConstantFPRange::getNonNaN (FpImm (0.0 ), FpImm (1.0 )));
712+ InterestingRanges.push_back (
713+ ConstantFPRange::getNonNaN (FpImm (2.0 ), FpImm (3.0 )));
714+ InterestingRanges.push_back (
715+ ConstantFPRange::getNonNaN (FpImm (-1.0 ), FpImm (1.0 )));
716+ InterestingRanges.push_back (
717+ ConstantFPRange::getNonNaN (FpImm (-1.0 ), FpImm (-0.0 )));
718+ InterestingRanges.push_back (ConstantFPRange::getNonNaN (
719+ APFloat::getInf (Sem, /* Negative=*/ true ), FpImm (-1.0 )));
720+ InterestingRanges.push_back (ConstantFPRange::getNonNaN (
721+ FpImm (1.0 ), APFloat::getInf (Sem, /* Negative=*/ false )));
722+
723+ for (auto &LHS : InterestingRanges) {
724+ for (auto &RHS : InterestingRanges) {
725+ for (auto Pred : FCmpInst::predicates ()) {
726+ if (LHS.fcmp (Pred, RHS)) {
727+ EnumerateValuesInConstantFPRange (
728+ LHS,
729+ [&](const APFloat &LHSC) {
730+ EnumerateValuesInConstantFPRange (
731+ RHS,
732+ [&](const APFloat &RHSC) {
733+ EXPECT_TRUE (FCmpInst::compare (LHSC, RHSC, Pred))
734+ << LHS << " " << Pred << " " << RHS
735+ << " doesn't hold" ;
736+ },
737+ /* IgnoreNaNPayload=*/ true );
738+ },
739+ /* IgnoreNaNPayload=*/ true );
740+ }
741+ }
742+ }
743+ }
744+ }
745+
567746} // anonymous namespace
0 commit comments