diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp index 7d7e20fde9daff..277ec31f6fb2e6 100644 --- a/src/coreclr/jit/rangecheck.cpp +++ b/src/coreclr/jit/rangecheck.cpp @@ -996,8 +996,9 @@ void RangeCheck::MergeEdgeAssertions(Compiler* comp, return l2; } - // Otherwise, prefer the BinOpArray(preferredBound) over the constant. - return l1; + // Otherwise, prefer the BinOpArray(preferredBound) over the constant for the upper bound + // and the constant for the lower bound. + return isLower ? l2 : l1; } unreached(); }; diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h index d90257a990bc2e..8df2fc19ea791c 100644 --- a/src/coreclr/jit/rangecheck.h +++ b/src/coreclr/jit/rangecheck.h @@ -510,10 +510,15 @@ struct RangeOps { result.lLimit = r1lo; } - // Widen Upper Limit => Max(k, (a.len + n)) yields (a.len + n), - // This is correct if k >= 0 and n >= k, since a.len always >= 0 - // (a.len + n) could overflow, but the result (a.len + n) also + + // NOTE: in some of the calculations below, we assume that $bnd is never negative + // and we have to be careful by not masking possible overflows. + + // Widen Upper Limit => Max(k, ($bnd + n)) yields ($bnd + n), + // This is correct if k >= 0 and n >= k, since $bnd always >= 0 + // ($bnd + n) could overflow, but the result ($bnd + n) also // preserves the overflow. + // if (r1hi.IsConstant() && r1hi.GetConstant() >= 0 && r2hi.IsBinOpArray() && r2hi.GetConstant() >= r1hi.GetConstant()) { @@ -524,14 +529,38 @@ struct RangeOps { result.uLimit = r1hi; } + + // Rule: <$bnd + cns1, ...> U = when cns1 <= 0 + // + // Example: <$bnd - 3, ...> U <0, ...> = <-3, ...> + // + if (r1lo.IsBinOpArray() && r2lo.IsConstant() && (r1lo.cns <= 0)) + { + result.lLimit = Limit(Limit::keConstant, min(r1lo.cns, r2lo.cns)); + } + if (r2lo.IsBinOpArray() && r1lo.IsConstant() && (r2lo.cns <= 0)) + { + result.lLimit = Limit(Limit::keConstant, min(r2lo.cns, r1lo.cns)); + } + + // Rule: <..., $bnd + cns1> U <..., $bnd + cns2> = <..., $bnd + max(cns1, cns2)> + // + // Example: <..., $bnd + 10> U <..., $bnd + 20> = <..., $bnd + 20> + // if (r1hi.IsBinOpArray() && r2hi.IsBinOpArray() && r1hi.vn == r2hi.vn) { - result.uLimit = r1hi; - // Widen the upper bound if the other constant is greater. - if (r2hi.GetConstant() > r1hi.GetConstant()) - { - result.uLimit = r2hi; - } + result.uLimit = r1hi; // copy $bnd and kind info + result.uLimit.cns = max(r1hi.cns, r2hi.cns); + } + + // Rule: <$bnd + cns1, ...> U <$bnd + cns2, ...> = <$bnd + min(cns1, cns2), ...> + // + // Example: <$bnd + 10, ...> U <$bnd + 20, ...> = <$bnd + 10, ...> + // + if (r1lo.IsBinOpArray() && r2lo.IsBinOpArray() && r1lo.vn == r2lo.vn) + { + result.lLimit = r1lo; // copy $bnd and kind info + result.lLimit.cns = min(r1lo.cns, r2lo.cns); } return result; }