Skip to content

Fix incorrect constant folding of CompareScalar True/False comparisons#130222

Open
tannergooding wants to merge 2 commits into
dotnet:mainfrom
tannergooding:tannergooding-fix-comparescalar-folding
Open

Fix incorrect constant folding of CompareScalar True/False comparisons#130222
tannergooding wants to merge 2 commits into
dotnet:mainfrom
tannergooding:tannergooding-fix-comparescalar-folding

Conversation

@tannergooding

Copy link
Copy Markdown
Member

Why

Avx.CompareScalar with a constant "always true"/"always false" float comparison mode (OrderedFalse*, UnorderedTrue*) was being constant folded to a full Zero/AllBitsSet vector. That is wrong for the scalar form: CompareScalar only writes the lowest element and must copy the remaining upper elements unchanged from op1. The fold discarded those upper elements, producing incorrect results (e.g. CompareScalar(<1,2,3,4>, ..., OrderedFalse) yielded <0,0,0,0> instead of <0,2,3,4>).

Separately, gtNewZeroConNode and gtNewAllBitsSetConNode did not support TYP_MASK (they hit unreached()), so folding the AVX512 mask compare (NI_AVX512_CompareMask, whose result type is TYP_MASK) for these modes crashed.

Fixes #125160

Approach

  • gtNewZeroConNode now handles TYP_MASK by returning a zero GenTreeMskCon (guarded by FEATURE_MASKED_HW_INTRINSICS).
  • gtFoldExprHWIntrinsic True/False handling for NI_AVX_Compare / NI_AVX_CompareScalar / NI_AVX512_CompareMask:
    • For CompareScalar, bail out of folding entirely unless op1 is itself a constant. When it is, set only the lowest element (0 for false modes, all-ones for true modes) and leave the upper elements of op1 intact.
    • For the non-scalar false case, use the now mask-safe gtNewZeroConNode(retType).
    • For the non-scalar true case producing a mask, build a canonical true mask via simdmask_t::AllBitsSet(elementCount) (matching VNAllBitsForType) rather than relying on gtNewAllBitsSetConNode, which cannot know the element count. Vector (non-mask) results still use gtNewAllBitsSetConNode.

Notes

  • The scalar fold reuses the constant op1 node as the result and wraps it with gtWrapWithSideEffects(tree, ...); because op1 is a side-effect-free constant, this preserves any side effects from the other operands without duplicating op1.
  • Direct bit writes (gtSimdVal.u32[0] / u64[0]) are used for the true-mode all-ones pattern since SetElementIntegral asserts on floating base types.

Testing

Added Runtime_125160 regression test covering all four True/False modes for float and double Avx.CompareScalar (asserting both the low-element result and upper-element preservation) plus Avx512F.Compare for Vector512<float>/<double>. Verified the test fails without the fix (Expected 2, Actual 0) and passes with it. Baseline clr+libs (checked) build is clean.

Note

This pull request was authored by GitHub Copilot.

The True/False float comparison modes were constant folded to a full
Zero/AllBitsSet result, which is wrong for CompareScalar since it must
copy the upper elements unchanged from op1. Also, gtNewZeroConNode and
gtNewAllBitsSetConNode did not support TYP_MASK, crashing the AVX512
mask compare fold.

- Add TYP_MASK support to gtNewZeroConNode.
- Only fold CompareScalar when op1 is a constant, setting just the
  lowest element and preserving the upper elements.
- Build a canonical true mask (AllBitsSet(elementCount)) for mask
  results instead of relying on gtNewAllBitsSetConNode.
- Add regression test Runtime_125160.

Fixes dotnet#125160

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 5, 2026 16:31
@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 Jul 5, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 corrects JIT constant-folding for AVX compare intrinsics in the “always true/always false” comparison modes, ensuring Avx.CompareScalar preserves the upper elements from op1 and avoiding crashes when folding AVX512 mask-typed compares.

Changes:

  • Extend gtNewZeroConNode to support TYP_MASK (via GenTreeMskCon) under FEATURE_MASKED_HW_INTRINSICS.
  • Update gtFoldExprHWIntrinsic folding for NI_AVX_Compare / NI_AVX_CompareScalar / NI_AVX512_CompareMask, with special handling for CompareScalar to only fold when op1 is a constant vector and to preserve upper elements.
  • Add and wire up a new JIT regression test Runtime_125160.
Show a summary per file
File Description
src/coreclr/jit/gentree.cpp Fixes compare folding behavior for scalar compares and makes zero-constant creation mask-safe.
src/tests/JIT/Regression/JitBlue/Runtime_125160/Runtime_125160.cs Adds regression coverage for CompareScalar true/false modes and AVX512 compare folding scenarios.
src/tests/JIT/Regression/Regression_ro_2.csproj Includes the new Runtime_125160 test in the regression suite.

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 3

Comment thread src/tests/JIT/Regression/JitBlue/Runtime_125160/Runtime_125160.cs
Comment thread src/tests/JIT/Regression/JitBlue/Runtime_125160/Runtime_125160.cs Outdated
Comment thread src/coreclr/jit/gentree.cpp
Copilot AI review requested due to automatic review settings July 5, 2026 18:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 3

Comment thread src/tests/JIT/Regression/JitBlue/Runtime_125160/Runtime_125160.cs
Comment thread src/tests/JIT/Regression/JitBlue/Runtime_125160/Runtime_125160.cs
Comment thread src/coreclr/jit/gentree.cpp
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
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

2 participants