@@ -651,13 +651,10 @@ bool RangeCheck::TryGetRangeFromAssertions(Compiler* comp, ValueNum num, ASSERT_
651651// assertions - the assertions to use
652652// pRange - the range to tighten with assertions
653653//
654- void RangeCheck::MergeEdgeAssertions (Compiler* comp,
655- ValueNum normalLclVN,
656- ValueNum preferredBoundVN,
657- ASSERT_VALARG_TP assertions,
658- Range* pRange,
659- bool log)
654+ void RangeCheck::MergeEdgeAssertions (
655+ Compiler* comp, ValueNum normalLclVN, ValueNum preferredBoundVN, ASSERT_VALARG_TP assertions, Range* pRange)
660656{
657+ Range assertedRange = Range (Limit (Limit::keUnknown));
661658 if (BitVecOps::IsEmpty (comp->apTraits , assertions))
662659 {
663660 return ;
@@ -897,90 +894,15 @@ void RangeCheck::MergeEdgeAssertions(Compiler* comp,
897894 continue ;
898895 }
899896
900- // Skip if it doesn't tighten the current bound:
901- if (pRange->uLimit .IsConstant () && ((cmpOper == GT_LE) || (cmpOper == GT_LT)))
902- {
903- if (!limit.IsConstant () && (limit.vn != arrLenVN))
904- {
905- // If our new limit is not constant and doesn't represent the array's length - bail out.
906- // NOTE: it's fine to replace the current constant limit with a non-constant arrLenVN.
907- continue ;
908- }
909- if (limit.IsConstant () && (limit.cns > pRange->uLimit .cns ))
910- {
911- // The new constant limit doesn't tighten the current constant bound.
912- // E.g. current is "X < 10" and the new one is "X < 100"
913- continue ;
914- }
915- }
916- // Same for the lower bound:
917- if (pRange->lLimit .IsConstant () && ((cmpOper == GT_GE) || (cmpOper == GT_GT)))
918- {
919- if (!limit.IsConstant () && (limit.vn != arrLenVN))
920- {
921- // If our new limit is not constant and doesn't represent the array's length - bail out.
922- // NOTE: it's fine to replace the current constant limit with a non-constant arrLenVN.
923- continue ;
924- }
925- if (limit.IsConstant () && (limit.cns < pRange->lLimit .cns ))
926- {
927- // The new constant limit doesn't tighten the current constant bound.
928- // E.g. current is "X > 10" and the new one is "X > 5"
929- continue ;
930- }
931- }
932-
933- // Check if the incoming limit from assertions tightens the existing upper limit.
934- if (pRange->uLimit .IsBinOpArray () && (pRange->uLimit .vn == arrLenVN))
935- {
936- // We have checked the current range's (pRange's) upper limit is either of the form:
937- // length + cns
938- // and length == the bndsChkCandidate's arrLen
939- //
940- // We want to check if the incoming limit tightens the bound, and for that
941- // we need to make sure that incoming limit is also on the same length (or
942- // length + cns) and not some other length.
943-
944- if (limit.vn != arrLenVN)
945- {
946- if (log)
947- {
948- JITDUMP (" Array length VN did not match arrLen=" FMT_VN " , limit=" FMT_VN " \n " , arrLenVN, limit.vn );
949- }
950- continue ;
951- }
952-
953- int curCns = pRange->uLimit .cns ;
954- int limCns = limit.IsBinOpArray () ? limit.cns : 0 ;
955-
956- // Incoming limit doesn't tighten the existing upper limit.
957- if (limCns >= curCns)
958- {
959- if (log)
960- {
961- JITDUMP (" Bound limit %d doesn't tighten current bound %d\n " , limCns, curCns);
962- }
963- continue ;
964- }
965- }
966- else
967- {
968- // Current range's upper bound is not "length + cns" and the
969- // incoming limit is not on the same length as the bounds check candidate.
970- // So we could skip this assertion. But in cases, of Dependent or Unknown
971- // type of upper limit, the incoming assertion still tightens the upper
972- // bound to a saner value. So do not skip the assertion.
973- }
974-
975897 // cmpOp (loop index i) cmpOper len +/- cns
976898 switch (cmpOper)
977899 {
978900 case GT_LT:
979901 case GT_LE:
980- pRange-> uLimit = limit;
902+ assertedRange. uLimit = limit;
981903 if (isUnsigned)
982904 {
983- pRange-> lLimit = Limit (Limit::keConstant, 0 );
905+ assertedRange. lLimit = Limit (Limit::keConstant, 0 );
984906 }
985907 break ;
986908
@@ -990,31 +912,98 @@ void RangeCheck::MergeEdgeAssertions(Compiler* comp,
990912 // using single Range object.
991913 if (!isUnsigned)
992914 {
993- pRange->lLimit = limit;
994- // INT32_MAX as the upper limit is better than UNKNOWN for a constant lower limit.
995- if (limit.IsConstant () && pRange->UpperLimit ().IsUnknown ())
996- {
997- pRange->uLimit = Limit (Limit::keConstant, INT32_MAX);
998- }
915+ assertedRange.lLimit = limit;
999916 }
1000917 break ;
1001918
1002919 case GT_EQ:
1003- pRange-> uLimit = limit;
1004- pRange-> lLimit = limit;
920+ assertedRange. uLimit = limit;
921+ assertedRange. lLimit = limit;
1005922 break ;
1006923
1007924 default :
1008925 // All other 'cmpOper' kinds leave lLimit/uLimit unchanged
1009926 break ;
1010927 }
1011928
1012- if (log)
1013- {
1014- JITDUMP (" The range after edge merging:" );
1015- JITDUMP (pRange->ToString (comp));
1016- JITDUMP (" \n " );
1017- }
929+ // We have two ranges - we need to merge (tighten) them.
930+
931+ auto tightenLimit = [](Limit l1, Limit l2, ValueNum preferredBound, bool isLower) -> Limit {
932+ // 1) One of the limits is undef, unknown or dependent
933+ if (l1.IsUndef () || l2.IsUndef ())
934+ {
935+ // Anything is better than undef.
936+ return l1.IsUndef () ? l2 : l1;
937+ }
938+ if (l1.IsUnknown () || l2.IsUnknown ())
939+ {
940+ // Anything is better than unknown.
941+ return l1.IsUnknown () ? l2 : l1;
942+ }
943+ if (l1.IsDependent () || l2.IsDependent ())
944+ {
945+ // Anything is better than dependent.
946+ return l1.IsDependent () ? l2 : l1;
947+ }
948+
949+ // 2) Both limits are constants
950+ if (l1.IsConstant () && l2.IsConstant ())
951+ {
952+ // isLower: whatever is higher is better.
953+ // !isLower: whatever is lower is better.
954+ return isLower ? (l1.cns > l2.cns ? l1 : l2) : (l1.cns < l2.cns ? l1 : l2);
955+ }
956+
957+ // 3) Both limits are BinOpArray (which is "arrLen + cns")
958+ if (l1.IsBinOpArray () && l2.IsBinOpArray ())
959+ {
960+ // If one of them is preferredBound and the other is not, use the preferredBound.
961+ if (preferredBound != ValueNumStore::NoVN)
962+ {
963+ if ((l1.vn == preferredBound) && (l2.vn != preferredBound))
964+ {
965+ return l1;
966+ }
967+ if ((l2.vn == preferredBound) && (l1.vn != preferredBound))
968+ {
969+ return l2;
970+ }
971+ }
972+
973+ // Otherwise, just use the one with the higher/lower constant.
974+ // even if they use different arrLen.
975+ return isLower ? (l1.cns > l2.cns ? l1 : l2) : (l1.cns < l2.cns ? l1 : l2);
976+ }
977+
978+ // 4) One of the limits is a constant and the other is BinOpArray
979+ if ((l1.IsConstant () && l2.IsBinOpArray ()) || (l2.IsConstant () && l1.IsBinOpArray ()))
980+ {
981+ // l1 - BinOpArray, l2 - constant
982+ if (l1.IsConstant ())
983+ {
984+ std::swap (l1, l2);
985+ }
986+
987+ if (((preferredBound == ValueNumStore::NoVN) || (l1.vn != preferredBound)))
988+ {
989+ // if we don't have a preferred bound,
990+ // or it doesn't match l1.vn, use the constant (l2).
991+ return l2;
992+ }
993+
994+ // Otherwise, prefer the BinOpArray(preferredBound) over the constant.
995+ return l1;
996+ }
997+ unreached ();
998+ };
999+
1000+ JITDUMP (" Tightening pRange: [%s] with assertedRange: [%s] into " , pRange->ToString (comp),
1001+ assertedRange.ToString (comp));
1002+
1003+ pRange->lLimit = tightenLimit (assertedRange.lLimit , pRange->lLimit , preferredBoundVN, true );
1004+ pRange->uLimit = tightenLimit (assertedRange.uLimit , pRange->uLimit , preferredBoundVN, false );
1005+
1006+ JITDUMP (" [%s]\n " , pRange->ToString (comp));
10181007 }
10191008}
10201009
0 commit comments