Skip to content

Fix Avx.CompareScalar and Avx512F.Compare incorrectly folded with True/False comparison modes#125179

Draft
Copilot wants to merge 4 commits intomainfrom
copilot/fix-avx-compare-scalar-folding
Draft

Fix Avx.CompareScalar and Avx512F.Compare incorrectly folded with True/False comparison modes#125179
Copilot wants to merge 4 commits intomainfrom
copilot/fix-avx-compare-scalar-folding

Conversation

Copy link
Contributor

Copilot AI commented Mar 4, 2026

Description

Fixes two issues in JIT constant folding of comparison intrinsics with OrderedFalse*/UnorderedTrue* modes in gtFoldExprHWIntrinsic:

  1. Avx.CompareScalar: CompareScalar preserves upper elements from the first operand, but the folding replaced the entire vector with zero or AllBitsSet, discarding those upper elements.
[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<float> CompareFalse(Vector128<float> x, Vector128<float> y)
    => Avx.CompareScalar(x, y, FloatComparisonMode.OrderedFalseSignaling);

// Expected: <0, 1, 1, 1>
// Actual:   <0, 0, 0, 0>
CompareFalse(Vector128<float>.One, Vector128<float>.Zero);
  1. Avx512F.Compare (NI_AVX512_CompareMask): CompareMask returns TYP_MASK, but gtNewZeroConNode/gtNewAllBitsSetConNode don't handle mask types, causing an unreached assertion failure.
static Vector512<float> CompareFalse(Vector512<float> x, Vector512<float> y)
    => Avx512F.Compare(x, y, FloatComparisonMode.OrderedFalseSignaling);
// Assert failure: 'unreached'

Changes

  • src/coreclr/jit/gentree.cpp:
    • Skip the True/False constant-folding when ni == NI_AVX_CompareScalar, since CompareScalar must preserve upper elements from op1.
    • For NI_AVX512_CompareMask, use getSIMDTypeForSize(simdSize) instead of retType when creating zero/AllBitsSet constants, since retType is TYP_MASK. The existing varTypeIsMask conversion at the end of the function wraps the result with CvtVectorToMask.
  • Regression test (Runtime_125160): Covers all four True/False modes for both float and double scalar comparisons (asserting lowest element result and upper element preservation), and all four True/False modes for Avx512F.Compare with Vector512<float> and Vector512<double> (using Vector512<T>.AllBitsSet for UnorderedTrue assertions since all-bits-set produces 0xFFFFFFFF per element, not -1f).
Original prompt

This section details on the original issue you should resolve

<issue_title>JIT: Avx.CompareScalar incorrectly folded with True/False comparison modes</issue_title>
<issue_description>### Description

CompareScalar is supposed to return the upper elements of the first operand unchanged, but folding for True/False comparison modes returns a full Zero or AllBitsSet vector.

https://github.com/dotnet/runtime/blob/f62984ce62deecfb90a8ab991e972d1bc460b93e/src/coreclr/jit/gentree.cpp#L33828-L33842

Reproduction Steps

using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;

Console.WriteLine(CompareFalse(Vector128<float>.One, Vector128<float>.Zero));

[MethodImpl(MethodImplOptions.NoInlining)]
static Vector128<float> CompareFalse(Vector128<float> x, Vector128<float> y)
	=> Avx.CompareScalar(x, y, FloatComparisonMode.OrderedFalseSignaling);

Expected behavior

> dotnet run -c release -f net9.0

<0, 1, 1, 1>

Actual behavior

> dotnet run -c release -f net10.0

<0, 0, 0, 0>

Regression?

Yes

Known Workarounds

No response

Configuration

No response

Other information

No response</issue_description>

<agent_instructions>Please fix #125160 and create a jit regression test for it</agent_instructions>

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


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@github-actions github-actions bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 4, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

…gression test

CompareScalar preserves upper elements from the first operand, so folding
to a full zero or AllBitsSet vector is incorrect. Skip folding for
NI_AVX_CompareScalar with True/False modes so the hardware instruction
produces the correct result.

Fixes #125160

Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix avx.CompareScalar folding for True/False comparison modes Fix Avx.CompareScalar incorrectly folded with True/False comparison modes Mar 4, 2026
@EgorBo EgorBo requested a review from Copilot March 4, 2026 16:18
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

This PR fixes a JIT constant-folding regression introduced in net10.0 where Avx.CompareScalar with OrderedFalse* or UnorderedTrue* comparison modes was incorrectly folded to a full zero or AllBitsSet vector, discarding the upper elements that should be preserved from the first operand.

Changes:

  • Skip constant folding for NI_AVX_CompareScalar in the OrderedFalse* and UnorderedTrue* cases in gtFoldExprHWIntrinsic, since CompareScalar only affects element 0 and must preserve upper elements from op1
  • Add regression test covering all four True/False modes for both float and double, asserting correct scalar result in element 0 and upper element preservation

Reviewed changes

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

File Description
src/coreclr/jit/gentree.cpp Adds an early break guard for NI_AVX_CompareScalar in both OrderedFalse* and UnorderedTrue* comparison mode cases to prevent incorrect whole-vector folding
src/tests/JIT/Regression/JitBlue/Runtime_125160/Runtime_125160.cs New regression test covering all four True/False comparison modes for both float and double, verifying scalar result in element 0 and upper element preservation
src/tests/JIT/Regression/Regression_ro_2.csproj Registers the new regression test in the merged test runner project

@saucecontrol
Copy link
Member

@copilot there's also an issue with CompareMask in that same folding code, because CnsVec is not the correct return type.

static Vector512<float> CompareFalse(Vector512<float> x, Vector512<float> y)
    => Avx512F.Compare(x, y, FloatComparisonMode.OrderedFalseSignaling);
Assert failure(PID 49888 [0x0000c2e0], Thread: 21696[0x54c0]): Assertion failed 'unreached' in 'Program:<<Main>$>g__CompareFalse|0_1(System.Runtime.Intrinsics.Vector512`1[float],System.Runtime.Intrinsics.Vector512`1[float]):System.Runtime.Intrinsics.Vector512`1[float]' during 'Importation' (IL size 10; hash 0x21e0833f; FullOpts)

    File: C:\git\runtime\src\coreclr\jit\gentree.cpp:8229
    Image: c:\git\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe

1 similar comment
@EgorBo
Copy link
Member

EgorBo commented Mar 4, 2026

@copilot there's also an issue with CompareMask in that same folding code, because CnsVec is not the correct return type.

static Vector512<float> CompareFalse(Vector512<float> x, Vector512<float> y)
    => Avx512F.Compare(x, y, FloatComparisonMode.OrderedFalseSignaling);
Assert failure(PID 49888 [0x0000c2e0], Thread: 21696[0x54c0]): Assertion failed 'unreached' in 'Program:<<Main>$>g__CompareFalse|0_1(System.Runtime.Intrinsics.Vector512`1[float],System.Runtime.Intrinsics.Vector512`1[float]):System.Runtime.Intrinsics.Vector512`1[float]' during 'Importation' (IL size 10; hash 0x21e0833f; FullOpts)

    File: C:\git\runtime\src\coreclr\jit\gentree.cpp:8229
    Image: c:\git\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe

…2 test

For NI_AVX512_CompareMask, retType is TYP_MASK which gtNewZeroConNode and
gtNewAllBitsSetConNode don't handle (hitting unreached()). Use the SIMD
vector type instead; the existing varTypeIsMask conversion at the end of
gtFoldExprHWIntrinsic will wrap the result with CvtVectorToMask.

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

Copilot AI commented Mar 4, 2026

@copilot there's also an issue with CompareMask in that same folding code, because CnsVec is not the correct return type.

...

Fixed in 01f88f3. gtNewZeroConNode/gtNewAllBitsSetConNode don't handle TYP_MASK, so now when retType is a mask type, we create the constant using getSIMDTypeForSize(simdSize) instead. The existing varTypeIsMask conversion at the end of gtFoldExprHWIntrinsic then wraps it with CvtVectorToMask. Also added Avx512F.Compare test coverage for all four True/False modes.

Copilot AI changed the title Fix Avx.CompareScalar incorrectly folded with True/False comparison modes Fix Avx.CompareScalar and Avx512F.Compare incorrectly folded with True/False comparison modes Mar 4, 2026
@EgorBo
Copy link
Member

EgorBo commented Mar 4, 2026

@copilot address the CI failures, e.g. Test global::Runtime_125160.TestCompareMask() has failed

…redTrue assertions

Vector512.Create(-1f) has bit pattern 0xBF800000 per element, but
UnorderedTrue comparison modes produce all-bits-set (0xFFFFFFFF per
element, which is NaN). Use Vector512<T>.AllBitsSet to correctly match
the expected result.

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

Copilot AI commented Mar 4, 2026

@copilot address the CI failures, e.g. Test global::Runtime_125160.TestCompareMask() has failed

Fixed in 1826aad. The TestCompareMask failure was due to incorrect expected values: Vector512.Create(-1f) has bit pattern 0xBF800000 per element, but UnorderedTrue comparison modes produce all-bits-set (0xFFFFFFFF per float element = NaN). Replaced with Vector512<float>.AllBitsSet / Vector512<double>.AllBitsSet.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh pr checks 125178 --repo dotnet/runtime (http block)
    • Triggering command: /usr/bin/gh gh pr checks 125178 --json name,state,link (http block)

If you need me to access, download, or install something from one of these locations, you can either:

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

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIT: Avx.CompareScalar incorrectly folded with True/False comparison modes

4 participants