diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h index 272eeb784a5335..1e5b3906e416ef 100644 --- a/src/coreclr/jit/rangecheck.h +++ b/src/coreclr/jit/rangecheck.h @@ -279,6 +279,17 @@ 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(); @@ -393,61 +404,45 @@ struct RangeOps static Range And(const Range& r1, const Range& r2) { - const Limit& r1lo = r1.LowerLimit(); - const Limit& r2lo = r2.LowerLimit(); - - const Limit& r1hi = r1.UpperLimit(); - const Limit& r2hi = r2.UpperLimit(); - - Range result = Limit(Limit::keUnknown); + // Conservatively expect at least one operand to be a single-value constant. + // 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); - // if either lower bound is a non-negative constant, result >= 0 - if ((r1lo.IsConstant() && (r1lo.GetConstant() >= 0)) || (r2lo.IsConstant() && (r2lo.GetConstant() >= 0))) + // Both ranges are single constant values. + // Example: [7..7] & [3..3] = [3..3] + if (r1IsConstVal && r2IsConstVal) { - // Example: [4.. ] & [unknown.. ] = [4.. ] - result.lLimit = Limit(Limit::keConstant, 0); + return Range(Limit(Limit::keConstant, r1ConstVal & r2ConstVal)); } - // Even if both r1 and r2 lower bounds are known non-negative constants, still the best we can do - // is >= 0 in a general case due to the way bitwise AND works. - // if either upper bound is a non-negative constant, result <= cns - if (r2hi.IsConstant() && (r2hi.GetConstant() >= 0)) - { - // Example: [ ..X] & [ ..5] = [ ..5] - result.uLimit = Limit(Limit::keConstant, r2hi.GetConstant()); - } - else if (r1hi.IsConstant() && (r1hi.GetConstant() >= 0)) + // One of the ranges is a single constant value. + // Example: [unknown..unknown] & [3..3] = [0..3] + if (r1IsConstVal && (r1ConstVal >= 0)) { - // Example: [ ..5] & [ ..X] = [ ..5] - result.uLimit = Limit(Limit::keConstant, r1hi.GetConstant()); + return Range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, r1ConstVal)); } - - // Both upper bounds are constant, take the min - if (r1hi.IsConstant() && r2hi.IsConstant() && (r1hi.GetConstant() >= 0) && (r2hi.GetConstant() >= 0)) + if (r2IsConstVal && (r2ConstVal >= 0)) { - // Example: [ ..7] & [ ..5] = [ ..5] - result.uLimit = Limit(Limit::keConstant, min(r1hi.GetConstant(), r2hi.GetConstant())); + return Range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, r2ConstVal)); } - return result; + // Otherwise, we cannot determine the result range. + return Range(Limit(Limit::keUnknown)); } static Range UnsignedMod(const Range& r1, const Range& r2) { - Range result = Limit(Limit::keUnknown); - - const Limit& r2lo = r2.LowerLimit(); - const Limit& r2hi = r2.UpperLimit(); - - // For X UMOD Y we only handle the case when Y is a fixed non-negative constant. + // For X UMOD Y we only handle the case when Y is a fixed positive constant. // Example: X % 5 -> [0..4] - // - if (r2lo.IsConstant() && r2lo.Equals(r2hi) && (r2lo.GetConstant() > 0)) + int r2ConstVal; + if (r2.IsSingleConstValue(&r2ConstVal) && (r2ConstVal > 0)) { - result.lLimit = Limit(Limit::keConstant, 0); - result.uLimit = Limit(Limit::keConstant, r2lo.GetConstant() - 1); + return Range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, r2ConstVal - 1)); } - return result; + return Range(Limit(Limit::keUnknown)); } // Given two ranges "r1" and "r2", do a Phi merge. If "monIncreasing" is true, diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_123583/Runtime_123583.cs b/src/tests/JIT/Regression/JitBlue/Runtime_123583/Runtime_123583.cs new file mode 100644 index 00000000000000..a799d22f019d94 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_123583/Runtime_123583.cs @@ -0,0 +1,25 @@ +// 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-24 18:57:51 +// Run on X86 Windows +// Seed: 1391773829286756241-vectort,vector128,vector256,x86aes,x86avx,x86avx2,x86avx512bw,x86avx512bwvl,x86avx512cd,x86avx512cdvl,x86avx512dq,x86avx512dqvl,x86avx512f,x86avx512fvl,x86bmi1,x86bmi2,x86fma,x86lzcnt,x86pclmulqdq,x86popcnt,x86sse,x86sse2,x86sse3,x86sse41,x86sse42,x86ssse3,x86x86base +// Reduced from 51.8 KiB to 0.2 KiB in 00:01:36 +// Debug: Prints 0 line(s) +// Release: Prints 1 line(s) + +using Xunit; + +public class Runtime_123583 +{ + public static sbyte s_4 = 1; + + [Fact] + public static void TestEntryPoint() + { + if (35009 > (1264240267 & (sbyte)(-s_4))) + { + throw new System.InvalidOperationException(); + } + } +}