From 9a0d344d529c964e15cd6afb70a405ebfecd5c10 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 03:05:20 +0000 Subject: [PATCH 1/4] Initial plan From 3320406e3488ebc0e79a3f32211e10d94ceec9fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 03:10:54 +0000 Subject: [PATCH 2/4] Fix RangeOps::Multiply to handle dependent ranges Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com> --- src/coreclr/jit/rangecheck.h | 74 ++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 15 deletions(-) diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h index 5d0e1946d45046..d40eca0893e4f9 100644 --- a/src/coreclr/jit/rangecheck.h +++ b/src/coreclr/jit/rangecheck.h @@ -368,27 +368,71 @@ struct RangeOps static Range Multiply(const Range& r1, const Range& r2, bool unsignedMul = false) { - if (!r1.IsConstantRange() || !r2.IsConstantRange()) + const Limit& r1lo = r1.LowerLimit(); + const Limit& r1hi = r1.UpperLimit(); + const Limit& r2lo = r2.LowerLimit(); + const Limit& r2hi = r2.UpperLimit(); + + // Check if any bounds are dependent + bool anyDep = r1lo.IsDependent() || r1hi.IsDependent() || r2lo.IsDependent() || r2hi.IsDependent(); + + // If both ranges are fully constant, perform the multiplication as before + if (!anyDep && r1.IsConstantRange() && r2.IsConstantRange()) { - return Limit(Limit::keUnknown); - } + int r1loVal = r1lo.GetConstant(); + int r1hiVal = r1hi.GetConstant(); + int r2loVal = r2lo.GetConstant(); + int r2hiVal = r2hi.GetConstant(); + + static_assert(CheckedOps::Unsigned == true); + if (CheckedOps::MulOverflows(r1loVal, r2loVal, unsignedMul) || + CheckedOps::MulOverflows(r1loVal, r2hiVal, unsignedMul) || + CheckedOps::MulOverflows(r1hiVal, r2loVal, unsignedMul) || + CheckedOps::MulOverflows(r1hiVal, r2hiVal, unsignedMul)) + { + return Limit(Limit::keUnknown); + } - int r1lo = r1.LowerLimit().GetConstant(); - int r1hi = r1.UpperLimit().GetConstant(); - int r2lo = r2.LowerLimit().GetConstant(); - int r2hi = r2.UpperLimit().GetConstant(); + int lo = min(min(r1loVal * r2loVal, r1loVal * r2hiVal), min(r1hiVal * r2loVal, r1hiVal * r2hiVal)); + int hi = max(max(r1loVal * r2loVal, r1loVal * r2hiVal), max(r1hiVal * r2loVal, r1hiVal * r2hiVal)); + assert(hi >= lo); + return Range(Limit(Limit::keConstant, lo), Limit(Limit::keConstant, hi)); + } - static_assert(CheckedOps::Unsigned == true); - if (CheckedOps::MulOverflows(r1lo, r2lo, unsignedMul) || CheckedOps::MulOverflows(r1lo, r2hi, unsignedMul) || - CheckedOps::MulOverflows(r1hi, r2lo, unsignedMul) || CheckedOps::MulOverflows(r1hi, r2hi, unsignedMul)) + // If one or more bounds are dependent, check if the constant bounds (if any) would overflow. + // If they would overflow, give up. Otherwise, return a range with dependent bounds. + if (anyDep) { - return Limit(Limit::keUnknown); + // Check all constant bound combinations for overflow + bool wouldOverflow = false; + if (r1lo.IsConstant() && r2lo.IsConstant()) + { + wouldOverflow |= CheckedOps::MulOverflows(r1lo.GetConstant(), r2lo.GetConstant(), unsignedMul); + } + if (r1lo.IsConstant() && r2hi.IsConstant()) + { + wouldOverflow |= CheckedOps::MulOverflows(r1lo.GetConstant(), r2hi.GetConstant(), unsignedMul); + } + if (r1hi.IsConstant() && r2lo.IsConstant()) + { + wouldOverflow |= CheckedOps::MulOverflows(r1hi.GetConstant(), r2lo.GetConstant(), unsignedMul); + } + if (r1hi.IsConstant() && r2hi.IsConstant()) + { + wouldOverflow |= CheckedOps::MulOverflows(r1hi.GetConstant(), r2hi.GetConstant(), unsignedMul); + } + + if (wouldOverflow) + { + return Limit(Limit::keUnknown); + } + + // If no overflow in constant bounds, return a dependent range + return Range(Limit(Limit::keDependent), Limit(Limit::keDependent)); } - int lo = min(min(r1lo * r2lo, r1lo * r2hi), min(r1hi * r2lo, r1hi * r2hi)); - int hi = max(max(r1lo * r2lo, r1lo * r2hi), max(r1hi * r2lo, r1hi * r2hi)); - assert(hi >= lo); - return Range(Limit(Limit::keConstant, lo), Limit(Limit::keConstant, hi)); + // Neither range is constant, give up + return Limit(Limit::keUnknown); } static Range ShiftRight(const Range& r1, const Range& r2, bool logical) From 3b2d1872124635f40895e0dcda757ab842dace0a Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 18 Feb 2026 13:24:08 +0100 Subject: [PATCH 3/4] Update rangecheck.h --- src/coreclr/jit/rangecheck.h | 82 ++++++++++-------------------------- 1 file changed, 22 insertions(+), 60 deletions(-) diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h index d40eca0893e4f9..535289a00ade7c 100644 --- a/src/coreclr/jit/rangecheck.h +++ b/src/coreclr/jit/rangecheck.h @@ -368,71 +368,33 @@ struct RangeOps static Range Multiply(const Range& r1, const Range& r2, bool unsignedMul = false) { - const Limit& r1lo = r1.LowerLimit(); - const Limit& r1hi = r1.UpperLimit(); - const Limit& r2lo = r2.LowerLimit(); - const Limit& r2hi = r2.UpperLimit(); - - // Check if any bounds are dependent - bool anyDep = r1lo.IsDependent() || r1hi.IsDependent() || r2lo.IsDependent() || r2hi.IsDependent(); - - // If both ranges are fully constant, perform the multiplication as before - if (!anyDep && r1.IsConstantRange() && r2.IsConstantRange()) - { - int r1loVal = r1lo.GetConstant(); - int r1hiVal = r1hi.GetConstant(); - int r2loVal = r2lo.GetConstant(); - int r2hiVal = r2hi.GetConstant(); - - static_assert(CheckedOps::Unsigned == true); - if (CheckedOps::MulOverflows(r1loVal, r2loVal, unsignedMul) || - CheckedOps::MulOverflows(r1loVal, r2hiVal, unsignedMul) || - CheckedOps::MulOverflows(r1hiVal, r2loVal, unsignedMul) || - CheckedOps::MulOverflows(r1hiVal, r2hiVal, unsignedMul)) - { - return Limit(Limit::keUnknown); - } - - int lo = min(min(r1loVal * r2loVal, r1loVal * r2hiVal), min(r1hiVal * r2loVal, r1hiVal * r2hiVal)); - int hi = max(max(r1loVal * r2loVal, r1loVal * r2hiVal), max(r1hiVal * r2loVal, r1hiVal * r2hiVal)); - assert(hi >= lo); - return Range(Limit(Limit::keConstant, lo), Limit(Limit::keConstant, hi)); + if (!r1.IsConstantRange() || !r2.IsConstantRange()) + { + Range result = Limit(Limit::keUnknown); + // Propagate the "dependent" property if either of the limits is dependent. + result.lLimit = r1.LowerLimit().IsDependent() || r2.LowerLimit().IsDependent() ? Limit(Limit::keDependent) + : Limit(Limit::keUnknown); + result.uLimit = r1.UpperLimit().IsDependent() || r2.UpperLimit().IsDependent() ? Limit(Limit::keDependent) + : Limit(Limit::keUnknown); + return result; } - // If one or more bounds are dependent, check if the constant bounds (if any) would overflow. - // If they would overflow, give up. Otherwise, return a range with dependent bounds. - if (anyDep) - { - // Check all constant bound combinations for overflow - bool wouldOverflow = false; - if (r1lo.IsConstant() && r2lo.IsConstant()) - { - wouldOverflow |= CheckedOps::MulOverflows(r1lo.GetConstant(), r2lo.GetConstant(), unsignedMul); - } - if (r1lo.IsConstant() && r2hi.IsConstant()) - { - wouldOverflow |= CheckedOps::MulOverflows(r1lo.GetConstant(), r2hi.GetConstant(), unsignedMul); - } - if (r1hi.IsConstant() && r2lo.IsConstant()) - { - wouldOverflow |= CheckedOps::MulOverflows(r1hi.GetConstant(), r2lo.GetConstant(), unsignedMul); - } - if (r1hi.IsConstant() && r2hi.IsConstant()) - { - wouldOverflow |= CheckedOps::MulOverflows(r1hi.GetConstant(), r2hi.GetConstant(), unsignedMul); - } - - if (wouldOverflow) - { - return Limit(Limit::keUnknown); - } + int r1lo = r1.LowerLimit().GetConstant(); + int r1hi = r1.UpperLimit().GetConstant(); + int r2lo = r2.LowerLimit().GetConstant(); + int r2hi = r2.UpperLimit().GetConstant(); - // If no overflow in constant bounds, return a dependent range - return Range(Limit(Limit::keDependent), Limit(Limit::keDependent)); + static_assert(CheckedOps::Unsigned == true); + if (CheckedOps::MulOverflows(r1lo, r2lo, unsignedMul) || CheckedOps::MulOverflows(r1lo, r2hi, unsignedMul) || + CheckedOps::MulOverflows(r1hi, r2lo, unsignedMul) || CheckedOps::MulOverflows(r1hi, r2hi, unsignedMul)) + { + return Limit(Limit::keUnknown); } - // Neither range is constant, give up - return Limit(Limit::keUnknown); + int lo = min(min(r1lo * r2lo, r1lo * r2hi), min(r1hi * r2lo, r1hi * r2hi)); + int hi = max(max(r1lo * r2lo, r1lo * r2hi), max(r1hi * r2lo, r1hi * r2hi)); + assert(hi >= lo); + return Range(Limit(Limit::keConstant, lo), Limit(Limit::keConstant, hi)); } static Range ShiftRight(const Range& r1, const Range& r2, bool logical) From d98dda153308b3f3f1850fdae661ad4794c93b05 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 18 Feb 2026 15:09:11 +0100 Subject: [PATCH 4/4] Update src/coreclr/jit/rangecheck.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/jit/rangecheck.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h index 535289a00ade7c..2ae55b6eaae836 100644 --- a/src/coreclr/jit/rangecheck.h +++ b/src/coreclr/jit/rangecheck.h @@ -370,7 +370,7 @@ struct RangeOps { if (!r1.IsConstantRange() || !r2.IsConstantRange()) { - Range result = Limit(Limit::keUnknown); + Range result = Limit(Limit::keUnknown); // Propagate the "dependent" property if either of the limits is dependent. result.lLimit = r1.LowerLimit().IsDependent() || r2.LowerLimit().IsDependent() ? Limit(Limit::keDependent) : Limit(Limit::keUnknown);