Skip to content

Fix JIT range analysis Multiply for ranges spanning negative values#124128

Open
Copilot wants to merge 5 commits intomainfrom
copilot/fix-jit-multiplication-cast-issue
Open

Fix JIT range analysis Multiply for ranges spanning negative values#124128
Copilot wants to merge 5 commits intomainfrom
copilot/fix-jit-multiplication-cast-issue

Conversation

Copy link
Contributor

Copilot AI commented Feb 7, 2026

Description

RangeOps::Multiply used ApplyRangeOp which independently multiplied lo*lo and hi*hi. This is wrong when ranges span negative values — e.g. [-100..100] * [0..10] produced [0..1000] instead of [-1000..1000], causing incorrect codegen for expressions involving multiplication with casts.

The fix computes min/max across all four endpoint products (r1lo*r2lo, r1lo*r2hi, r1hi*r2lo, r1hi*r2hi), which is the standard interval arithmetic approach for multiplication.

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));
  • src/coreclr/jit/rangecheck.h: Replace Multiply — require constant ranges, check all four products for overflow, compute correct min/max bounds
  • src/tests/JIT/Regression/JitBlue/Runtime_124082/: Add Fuzzlyn regression test from the issue
Original prompt

This section details on the original issue you should resolve

<issue_title>JIT: Bad result with multiplication and casts</issue_title>
<issue_description>```csharp
// Generated by Fuzzlyn v3.3 on 2026-02-05 22:00:13
// Run on X64 Windows
// Seed: 3325744140221827777-vectort,vector128,vector256,x86aes,x86avx,x86avx2,x86avx512bw,x86avx512bwvl,x86avx512cd,x86avx512cdvl,x86avx512dq,x86avx512dqvl,x86avx512f,x86avx512fvl,x86avx512fx64,x86bmi1,x86bmi1x64,x86bmi2,x86bmi2x64,x86fma,x86lzcnt,x86lzcntx64,x86pclmulqdq,x86popcnt,x86popcntx64,x86sse,x86ssex64,x86sse2,x86sse2x64,x86sse3,x86sse41,x86sse41x64,x86sse42,x86sse42x64,x86ssse3,x86x86base
// Reduced from 64.4 KiB to 0.3 KiB in 00:01:42
// Debug: Outputs -1
// Release: Outputs 4294967295
public class Program
{
public static sbyte s_4 = 1;
public static byte[][] s_12 = new byte[][]
{
new byte[]
{
1
}
};
public static void Main()
{
byte[] vr9 = s_12[0];
long vr10 = (ushort)s_4 * (sbyte)(-s_4);
System.Console.WriteLine(vr10);
}
}


Bisected to dotnet/runtime#123233, cc @EgorBo </issue_description>

<agent_instructions>Fix the https://github.com/dotnet/runtime/issues/124082 bug. Replace Multiply impl with the following code:

```cpp
static Range Multiply(const Range& r1, const Range& r2)
{
    if (!r1.IsConstantRange() || !r2.IsConstantRange())
    {
        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 (CheckedOps::MulOverflows(r1lo, r2lo, CheckedOps::Signed) ||
        CheckedOps::MulOverflows(r1lo, r2hi, CheckedOps::Signed) ||
        CheckedOps::MulOverflows(r1hi, r2lo, CheckedOps::Signed) ||
        CheckedOps::MulOverflows(r1hi, r2hi, CheckedOps::Signed))
    {
        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));
}

the problem that the original code for e.g. [-100..100] * [0..10] would return [0..1000] instead of [-1000..1000]. You can ignore "IsDependent" check here - it's not useful anyway.

Add the JIT regression test for this case from issue (maintain the Fuzzlyn comment header in the test)</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 7, 2026
Copilot AI and others added 3 commits February 7, 2026 06:08
…ll endpoint products and add regression test for #124082

Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
@EgorBo
Copy link
Member

EgorBo commented Feb 7, 2026

@jakobbotsch @dotnet/jit-contrib PTAL fix for fuzzlyn failures.

Previous logic was incorrectly multiplying [-100..100] * [0..100] into [0..10000] instead of [-10000..10000]

@EgorBo EgorBo requested a review from jakobbotsch February 7, 2026 16:01
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes CoreCLR JIT range analysis for multiplication when operand ranges span negative values, preventing incorrect bounds that can lead to wrong codegen (notably around casts).

Changes:

  • Update RangeOps::Multiply to use standard interval-arithmetic multiplication (min/max of all four endpoint products) with overflow checking.
  • Add a JIT regression test reproducing #124082 (Fuzzlyn-reduced).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/coreclr/jit/rangecheck.h Correct range multiplication by considering all endpoint product combinations and rejecting overflow cases.
src/tests/JIT/Regression/JitBlue/Runtime_124082/Runtime_124082.cs Adds regression coverage for the cast/multiply miscompile reported in #124082.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIT: Bad result with multiplication and casts

3 participants