Skip to content

Commit a92f652

Browse files
authored
[Bounds Checks] Make union/intersect operations more precise (#113862)
1 parent 71cd23b commit a92f652

File tree

2 files changed

+41
-11
lines changed

2 files changed

+41
-11
lines changed

src/coreclr/jit/rangecheck.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -996,8 +996,9 @@ void RangeCheck::MergeEdgeAssertions(Compiler* comp,
996996
return l2;
997997
}
998998

999-
// Otherwise, prefer the BinOpArray(preferredBound) over the constant.
1000-
return l1;
999+
// Otherwise, prefer the BinOpArray(preferredBound) over the constant for the upper bound
1000+
// and the constant for the lower bound.
1001+
return isLower ? l2 : l1;
10011002
}
10021003
unreached();
10031004
};

src/coreclr/jit/rangecheck.h

+38-9
Original file line numberDiff line numberDiff line change
@@ -510,10 +510,15 @@ struct RangeOps
510510
{
511511
result.lLimit = r1lo;
512512
}
513-
// Widen Upper Limit => Max(k, (a.len + n)) yields (a.len + n),
514-
// This is correct if k >= 0 and n >= k, since a.len always >= 0
515-
// (a.len + n) could overflow, but the result (a.len + n) also
513+
514+
// NOTE: in some of the calculations below, we assume that $bnd is never negative
515+
// and we have to be careful by not masking possible overflows.
516+
517+
// Widen Upper Limit => Max(k, ($bnd + n)) yields ($bnd + n),
518+
// This is correct if k >= 0 and n >= k, since $bnd always >= 0
519+
// ($bnd + n) could overflow, but the result ($bnd + n) also
516520
// preserves the overflow.
521+
//
517522
if (r1hi.IsConstant() && r1hi.GetConstant() >= 0 && r2hi.IsBinOpArray() &&
518523
r2hi.GetConstant() >= r1hi.GetConstant())
519524
{
@@ -524,14 +529,38 @@ struct RangeOps
524529
{
525530
result.uLimit = r1hi;
526531
}
532+
533+
// Rule: <$bnd + cns1, ...> U <cns2, ...> = <min(cns1, cns2), ...> when cns1 <= 0
534+
//
535+
// Example: <$bnd - 3, ...> U <0, ...> = <-3, ...>
536+
//
537+
if (r1lo.IsBinOpArray() && r2lo.IsConstant() && (r1lo.cns <= 0))
538+
{
539+
result.lLimit = Limit(Limit::keConstant, min(r1lo.cns, r2lo.cns));
540+
}
541+
if (r2lo.IsBinOpArray() && r1lo.IsConstant() && (r2lo.cns <= 0))
542+
{
543+
result.lLimit = Limit(Limit::keConstant, min(r2lo.cns, r1lo.cns));
544+
}
545+
546+
// Rule: <..., $bnd + cns1> U <..., $bnd + cns2> = <..., $bnd + max(cns1, cns2)>
547+
//
548+
// Example: <..., $bnd + 10> U <..., $bnd + 20> = <..., $bnd + 20>
549+
//
527550
if (r1hi.IsBinOpArray() && r2hi.IsBinOpArray() && r1hi.vn == r2hi.vn)
528551
{
529-
result.uLimit = r1hi;
530-
// Widen the upper bound if the other constant is greater.
531-
if (r2hi.GetConstant() > r1hi.GetConstant())
532-
{
533-
result.uLimit = r2hi;
534-
}
552+
result.uLimit = r1hi; // copy $bnd and kind info
553+
result.uLimit.cns = max(r1hi.cns, r2hi.cns);
554+
}
555+
556+
// Rule: <$bnd + cns1, ...> U <$bnd + cns2, ...> = <$bnd + min(cns1, cns2), ...>
557+
//
558+
// Example: <$bnd + 10, ...> U <$bnd + 20, ...> = <$bnd + 10, ...>
559+
//
560+
if (r1lo.IsBinOpArray() && r2lo.IsBinOpArray() && r1lo.vn == r2lo.vn)
561+
{
562+
result.lLimit = r1lo; // copy $bnd and kind info
563+
result.lLimit.cns = min(r1lo.cns, r2lo.cns);
535564
}
536565
return result;
537566
}

0 commit comments

Comments
 (0)