From 3be84b57c26e3a97ec8cbf85e3f0b86736d944d9 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Fri, 30 Jan 2026 12:31:00 +0100 Subject: [PATCH 1/3] Fix bug in ShiftLeft --- src/coreclr/jit/rangecheck.h | 42 +++++++++---------- .../JitBlue/Runtime_123790/Runtime_123790.cs | 30 +++++++++++++ 2 files changed, 49 insertions(+), 23 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_123790/Runtime_123790.cs diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h index 4e3bc0f18a1af2..b53a00bd9dce9e 100644 --- a/src/coreclr/jit/rangecheck.h +++ b/src/coreclr/jit/rangecheck.h @@ -279,17 +279,6 @@ struct Range return lLimit.IsConstant() && uLimit.IsConstant() && IsValid(); } - // Check if the range represents a single constant value. Example: [7..7] - bool IsSingleConstValue(int* pConstVal) const - { - if (lLimit.IsConstant() && lLimit.Equals(uLimit)) - { - *pConstVal = lLimit.GetConstant(); - return true; - } - return false; - } - bool IsUndef() const { return lLimit.IsUndef() && uLimit.IsUndef(); @@ -380,15 +369,22 @@ struct RangeOps static Range ShiftRight(const Range& r1, const Range& r2, bool logical) { - return ApplyRangeOp(r1, r2, [](const Limit& a, const Limit& b) { - // For now, we only support r1 >> positive_cns (to simplify) - // Hence, it doesn't matter if it's logical or arithmetic. - if (a.IsConstant() && b.IsConstant() && (a.GetConstant() >= 0) && ((unsigned)b.GetConstant() <= 31)) - { - return Limit(Limit::keConstant, a.GetConstant() >> b.GetConstant()); - } - return Limit(Limit::keUnknown); - }); + if (!r2.IsConstantRange() || (static_cast(r2.LowerLimit().GetConstant()) > 31) || + (static_cast(r2.UpperLimit().GetConstant()) > 31)) + { + return Range(Limit(Limit::keUnknown)); + } + + Range result = Limit(Limit::keUnknown); + if (r1.LowerLimit().IsConstant() && (r1.LowerLimit().GetConstant() >= 0)) + { + result.lLimit = Limit(Limit::keConstant, r1.LowerLimit().GetConstant() << r2.UpperLimit().GetConstant()); + } + if (r1.UpperLimit().IsConstant() && (r1.UpperLimit().GetConstant() >= 0)) + { + result.uLimit = Limit(Limit::keConstant, r1.UpperLimit().GetConstant() << r2.LowerLimit().GetConstant()); + } + return result; } static Range ShiftLeft(const Range& r1, const Range& r2) @@ -421,8 +417,8 @@ struct RangeOps // The math gets too complicated otherwise (and rarely useful in practice). int r1ConstVal; int r2ConstVal; - bool r1IsConstVal = r1.IsSingleConstValue(&r1ConstVal); - bool r2IsConstVal = r2.IsSingleConstValue(&r2ConstVal); + bool r1IsConstVal = r1.IsSingleValueConstant(&r1ConstVal); + bool r2IsConstVal = r2.IsSingleValueConstant(&r2ConstVal); // Both ranges are single constant values. // Example: [7..7] & [3..3] = [3..3] @@ -451,7 +447,7 @@ struct RangeOps // For X UMOD Y we only handle the case when Y is a fixed positive constant. // Example: X % 5 -> [0..4] int r2ConstVal; - if (r2.IsSingleConstValue(&r2ConstVal) && (r2ConstVal > 0)) + if (r2.IsSingleValueConstant(&r2ConstVal) && (r2ConstVal > 0)) { return Range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, r2ConstVal - 1)); } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_123790/Runtime_123790.cs b/src/tests/JIT/Regression/JitBlue/Runtime_123790/Runtime_123790.cs new file mode 100644 index 00000000000000..60db8a3ff213a5 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_123790/Runtime_123790.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Generated by Fuzzlyn v3.3 on 2026-01-30 00:24:21 +// Run on Arm Linux +// Seed: 1258975953768210879 +// Reduced from 90.6 KiB to 0.3 KiB in 00:00:49 +// Debug: Outputs 0 +// Release: Outputs 1 + +using System; +using Xunit; + +public class Runtime_123790 +{ + public static ushort s_3; + public static ulong s_4; + public static sbyte s_9 = -1; + + [Fact] + public static void TestEntryPoint() + { + if (1 >= ((ushort)s_9 >> s_3)) + { + s_4 = 1; + } + + Assert.Equal(0UL, s_4); + } +} From 69bdb305b57eb3b5888f569ab47085b31c68af2d Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Fri, 30 Jan 2026 12:46:37 +0100 Subject: [PATCH 2/3] Update src/coreclr/jit/rangecheck.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/coreclr/jit/rangecheck.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h index b53a00bd9dce9e..25695560d1418e 100644 --- a/src/coreclr/jit/rangecheck.h +++ b/src/coreclr/jit/rangecheck.h @@ -378,11 +378,11 @@ struct RangeOps Range result = Limit(Limit::keUnknown); if (r1.LowerLimit().IsConstant() && (r1.LowerLimit().GetConstant() >= 0)) { - result.lLimit = Limit(Limit::keConstant, r1.LowerLimit().GetConstant() << r2.UpperLimit().GetConstant()); + result.lLimit = Limit(Limit::keConstant, r1.LowerLimit().GetConstant() >> r2.UpperLimit().GetConstant()); } if (r1.UpperLimit().IsConstant() && (r1.UpperLimit().GetConstant() >= 0)) { - result.uLimit = Limit(Limit::keConstant, r1.UpperLimit().GetConstant() << r2.LowerLimit().GetConstant()); + result.uLimit = Limit(Limit::keConstant, r1.UpperLimit().GetConstant() >> r2.LowerLimit().GetConstant()); } return result; } From c4ca8057078d9e4285e52535d2d5150b6ac7d784 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Fri, 30 Jan 2026 12:53:51 +0100 Subject: [PATCH 3/3] add comments --- src/coreclr/jit/rangecheck.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h index 25695560d1418e..772f95e826b20a 100644 --- a/src/coreclr/jit/rangecheck.h +++ b/src/coreclr/jit/rangecheck.h @@ -369,13 +369,20 @@ struct RangeOps static Range ShiftRight(const Range& r1, const Range& r2, bool logical) { + Range result = Limit(Limit::keUnknown); + + // For SHR we require the rhs to be a constant range within [0..31]. + // We only perform the shift if the lhs is also a constant range (never-negative for now + // to handle both logical and arithmetic shifts uniformly). if (!r2.IsConstantRange() || (static_cast(r2.LowerLimit().GetConstant()) > 31) || (static_cast(r2.UpperLimit().GetConstant()) > 31)) { - return Range(Limit(Limit::keUnknown)); + return result; } - Range result = Limit(Limit::keUnknown); + // We shift by r2.UpperLimit() for the lower limit and by r2.LowerLimit() for the upper limit. + // Example: [0..65535] >> [0..3] = [0 >> 3 .. 65535 >> 0] = [0..65535] + // [0..65535] >> [2..2] = [0 >> 2 .. 65535 >> 2] = [0..16383] if (r1.LowerLimit().IsConstant() && (r1.LowerLimit().GetConstant() >= 0)) { result.lLimit = Limit(Limit::keConstant, r1.LowerLimit().GetConstant() >> r2.UpperLimit().GetConstant());