Skip to content

Fix side-effect reordering when folding constant-zero-mask BlendVariable#130946

Open
tannergooding wants to merge 5 commits into
dotnet:mainfrom
tannergooding:tannergooding-special-spork
Open

Fix side-effect reordering when folding constant-zero-mask BlendVariable#130946
tannergooding wants to merge 5 commits into
dotnet:mainfrom
tannergooding:tannergooding-special-spork

Conversation

@tannergooding

@tannergooding tannergooding commented Jul 17, 2026

Copy link
Copy Markdown
Member

Fixes #125431

gtFoldExprHWIntrinsic folds a BlendVariable/BlendVariableMask with a constant mask down to one of its operands. Operands evaluate in order op1 (selectFalse), op2 (selectTrue), op3 (mask). When the mask is a constant all-zero, the result is op1 and op2 is dropped. The old code did:

return gtWrapWithSideEffects(op1, op2, GTF_ALL_EFFECT);

gtWrapWithSideEffects(op1, op2) builds COMMA(sideEffects(op2), op1), which hoists op2's side effects ahead of op1. But op2 is evaluated after op1 in source order, so this reorders them. In the repro, op1 is CreateScalar(M43(...)) (a call) and op2 is a null-array load (throws NullReferenceException); the fold moved the null-load exception ahead of the M43 call, dropping the observable side effect of M43 (matching Debug prints 1 line, Release prints 0).

Fix: mirror the conservative maskIsAllBitsSet branch directly above -- only fold when op2 has no side effects and return op1 directly; otherwise break and let value numbering handle the value fold (which preserves side-effect ordering), the same way the neighboring maskIsAllBitsSet and ConditionalSelect handlers already do.


Added a deterministic regression test under JitBlue/Runtime_125431 (runs with DOTNET_TieredCompilation=0). Confirmed it fails on the unfixed JIT and passes with the fix; the original Fuzzlyn repro now prints the expected line before the NullReferenceException. jit-format reports no changes.


Known related gap (deferred, not fixed here): the same dropped-operand hazard exists in the shared side-effect extraction machinery. gtNodeHasSideEffects/gtExtractSideEffList only consider GTF_ASG | GTF_CALL | GTF_EXCEPT | GTF_MAKE_CSE and ignore GTF_ORDER_SIDEEFF/GTF_GLOB_REF, even when passed GTF_ALL_EFFECT. A non-faulting volatile load (GLOB_REF | ORDER_SIDEEFF, no EXCEPT) can therefore still be dropped by callers that discard a value-dead operand through that path -- e.g. fgMorphModToZero (x % 1) and the TernaryLogic unused-operand path (gtUnusedValNode). A per-site mask widen does not fix those (the global-morph extraction still drops the load); the correct fix is centralized in gtNodeHasSideEffects/gtExtractSideEffList and has a wider blast radius, so it is tracked separately.

Note

This PR description was drafted by Copilot.

When gtFoldExprHWIntrinsic folds a BlendVariable with a constant all-zero
mask down to op1, gtWrapWithSideEffects(op1, op2) hoisted op2's side effects
ahead of op1 even though op2 is evaluated after op1. Only fold when op2 has
no side effects and return op1 directly; otherwise bail and let VN handle it.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 17, 2026 02:14
@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 17, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
10 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@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 updates RyuJIT’s gtFoldExprHWIntrinsic constant-folding for BlendVariable/BlendVariableMask when the mask is a constant all-zero, to avoid unsafe operand dropping / side-effect reordering, and adds a regression test under JitBlue.

Changes:

  • Adjust BlendVariable* folding so maskIsZero only returns op1 when it’s safe to drop op2.
  • Add a deterministic JitBlue regression test exercising the evaluation-order / exception ordering scenario.
  • Add a test project file that forces DOTNET_TieredCompilation=0 for determinism.
Show a summary per file
File Description
src/coreclr/jit/gentree.cpp Updates BlendVariable* folding behavior for constant masks.
src/tests/JIT/Regression/JitBlue/Runtime_125431/Runtime_125431.cs Adds regression coverage for operand evaluation order and exception behavior.
src/tests/JIT/Regression/JitBlue/Runtime_125431/Runtime_125431.csproj Configures isolated execution + env var for deterministic tiering behavior.

Copilot's findings

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

Comment thread src/coreclr/jit/gentree.cpp Outdated
Comment thread src/tests/JIT/Regression/JitBlue/Runtime_125431/Runtime_125431.cs Outdated
Bail on any op2 effect (including ordering/global refs such as volatile
loads), not just GTF_SIDE_EFFECT. Switch the regression test to
ConditionalFact so unsupported hardware is reported as skipped.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 17, 2026 02:31

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: 2

Comment thread src/coreclr/jit/gentree.cpp Outdated
Comment thread src/tests/JIT/Regression/JitBlue/Runtime_125431/Runtime_125431.cs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 17, 2026 03:07

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: 0 new

@tannergooding

Copy link
Copy Markdown
Member Author

CC. @dotnet/jit-contrib, @dhartglassMSFT a small side-effect preservation fix

@tannergooding

Copy link
Copy Markdown
Member Author

Found a couple more side effect checks that were technically incorrect, so fixed them. Given they require a non-faulting volatile load, getting a regression test added is difficult.

When a constant-fold identity makes an operand value-dead, it may only be dropped if it has no user-visible side effect and no ordered effect. The guards checked GTF_SIDE_EFFECT (or GTF_ALL_EFFECT), so a non-faulting volatile load could be silently dropped. Use the minimal correct mask GTF_SIDE_EFFECT | GTF_ORDER_SIDEEFF for the drop-in-place folds in gtFoldExprHWIntrinsic (BlendVariable, ConditionalSelect), the AVX512 Fixup seed, and fgOptimizeMultiply mul-by-zero.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 17, 2026 19:08

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: 5/5 changed files
  • Comments generated: 0 new

Force optimized codegen with AggressiveOptimization instead of process-isolated tiered-compilation disabling, so the test can drop its standalone project and join Regression_ro_2.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 17, 2026 19:36

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: 5/5 changed files
  • Comments generated: 0 new

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: Invalid result with Avx2.BlendVariable

2 participants