@@ -648,13 +648,19 @@ void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP
648648// Return Value:
649649// The computed range
650650//
651- Range RangeCheck::GetRangeFromAssertions (Compiler* comp, ValueNum num, ASSERT_VALARG_TP assertions, int maxDepth )
651+ Range RangeCheck::GetRangeFromAssertions (Compiler* comp, ValueNum num, ASSERT_VALARG_TP assertions, int budget )
652652{
653- if (num == ValueNumStore::NoVN || maxDepth <= 0 )
653+ // Start with the widest possible constant range.
654+ Range result = Range (Limit (Limit::keConstant, INT32_MIN), Limit (Limit::keConstant, INT32_MAX));
655+
656+ if ((num == ValueNumStore::NoVN) || (budget <= 0 ))
654657 {
655- return Range ( Limit (Limit::keUnknown)) ;
658+ return result ;
656659 }
657660
661+ // Currently, we only handle int32 and smaller integer types.
662+ assert (varTypeIsInt (comp->vnStore ->TypeOfVN (num)) || varTypeIsSmall (comp->vnStore ->TypeOfVN (num)));
663+
658664 //
659665 // First, let's see if we can tighten the range based on VN information.
660666 //
@@ -666,9 +672,6 @@ Range RangeCheck::GetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_VA
666672 return Range (Limit (Limit::keConstant, cns));
667673 }
668674
669- // Start with the widest possible constant range.
670- Range result = Range (Limit (Limit::keConstant, INT32_MIN), Limit (Limit::keConstant, INT32_MAX));
671-
672675 VNFuncApp funcApp;
673676 if (comp->vnStore ->GetVNFunc (num, &funcApp))
674677 {
@@ -713,12 +716,11 @@ Range RangeCheck::GetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_VA
713716
714717 case VNF_NEG:
715718 {
716- Range r1 = GetRangeFromAssertions (comp, funcApp.m_args [0 ], assertions, maxDepth - 1 );
719+ Range r1 = GetRangeFromAssertions (comp, funcApp.m_args [0 ], assertions, --budget );
717720 Range unaryOpResult = RangeOps::Negate (r1);
718- if (unaryOpResult.IsConstantRange ())
719- {
720- result = unaryOpResult;
721- }
721+
722+ // We can use the result only if it never overflows.
723+ result = unaryOpResult.IsConstantRange () ? unaryOpResult : result;
722724 break ;
723725 }
724726
@@ -732,8 +734,8 @@ Range RangeCheck::GetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_VA
732734 case VNF_UMOD:
733735 {
734736 // Get ranges of both operands and perform the same operation on the ranges.
735- Range r1 = GetRangeFromAssertions (comp, funcApp.m_args [0 ], assertions, maxDepth - 1 );
736- Range r2 = GetRangeFromAssertions (comp, funcApp.m_args [1 ], assertions, maxDepth - 1 );
737+ Range r1 = GetRangeFromAssertions (comp, funcApp.m_args [0 ], assertions, --budget );
738+ Range r2 = GetRangeFromAssertions (comp, funcApp.m_args [1 ], assertions, --budget );
737739 Range binOpResult = Range (Limit (Limit::keUnknown));
738740 switch (funcApp.m_func )
739741 {
@@ -765,12 +767,8 @@ Range RangeCheck::GetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_VA
765767 unreached ();
766768 }
767769
768- if (binOpResult.IsConstantRange ())
769- {
770- result = binOpResult;
771- }
772- // if the result is unknown (or may overflow), we'll just analyze the binop itself based on the
773- // assertions
770+ // We can use the result only if it never overflows.
771+ result = binOpResult.IsConstantRange () ? binOpResult : result;
774772 break ;
775773 }
776774
@@ -808,12 +806,17 @@ Range RangeCheck::GetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_VA
808806 }
809807
810808 Range phiRange = Range (Limit (Limit::keUndef));
809+ if (optVisitReachingAssertions (comp, num,
810+ [comp, &phiRange, &budget](ValueNum reachingVN, ASSERT_TP reachingAssertions) {
811+ // call GetRangeFromAssertions for each reaching VN using reachingAssertions
812+ Range edgeRange = GetRangeFromAssertions (comp, reachingVN, reachingAssertions, --budget);
813+
814+ // If phiRange is not yet set, set it to the first edgeRange
815+ // else merge it with the new edgeRange. Example: [10..100] U [50..150] = [10..150]
816+ phiRange = phiRange.LowerLimit ().IsUndef () ? edgeRange : RangeOps::Merge (phiRange, edgeRange, false );
811817
812- if ((maxDepth > 1 ) &&
813- optVisitReachingAssertions (comp, num,
814- [comp, &phiRange, maxDepth](ValueNum reachingVN, ASSERT_TP reachingAssertions) {
815- Range edgeRange = GetRangeFromAssertions (comp, reachingVN, reachingAssertions, maxDepth - 1 );
816- phiRange = phiRange.LowerLimit ().IsUndef () ? edgeRange : RangeOps::Union (phiRange, edgeRange);
818+ // if any edge produces a non-constant range, we abort further processing
819+ // We also give up if the range is full, as it won't help tighten the result.
817820 return edgeRange.IsConstantRange () && !edgeRange.IsFullRange () ? AssertVisit::Continue : AssertVisit::Abort;
818821 }) == AssertVisit::Continue)
819822 {
0 commit comments