Skip to content

Conversation

@jakobbotsch
Copy link
Member

@jakobbotsch jakobbotsch commented Jan 7, 2026

Functions with GS cookie checks may furthermore shadow parameters to make sure that the GS cookie ends up above all parameters on the stack. This is done by creating a copy of parameters used like a pointer and redirecting all uses to act on the shadow. IR is inserted in the beginning of the function to copy the parameters to their shadows.

For async this introduces a problem when it comes to implicit byrefs. The shadowing ceremony introduces a pointer to a local (the storage area in the caller) and that pointer remains live across suspension points, resulting in illegal IR.

This PR moves the GS phase so that it runs after the async transformation. To do so rewrite the analysis to run on LIR and the IR insertion/rewriting to be compatible with LIR.

Fix #122954

… transformation

Functions with GS cookie checks may furthermore shadow parameters to
make sure that the GS cookie ends up above all parameters on the stack.
This is done by creating a copy of parameters used like a pointer and
redirection all uses to act on the shadow. IR is inserted in the
beginning of the function to copy the parameters to their shadows.

For async this introduces a problem when it comes to implicit byrefs.
The shadowing ceremony introduces a pointer to a local (the storage area
in the caller) and that pointer remains live across suspension points,
resulting in illegal IR.

Ideally we would move the shadowing pass to run after the async
transformation, but this requires rewriting the analysis from HIR to
LIR. This change instead fixes the issue by keeping the analysis where
it is, but by delaying the rewrite of the IR until after the async
transformation (for async functions only).
@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 Jan 7, 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.

@jakobbotsch

This comment was marked as outdated.

@jakobbotsch jakobbotsch changed the title JIT: Delay rewriting IR for GS cookie shadow copies until after async transformation JIT: Make GS cookie phase run on LIR and move it after async phase Jan 9, 2026
@jakobbotsch
Copy link
Member Author

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@jakobbotsch
Copy link
Member Author

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@jakobbotsch
Copy link
Member Author

/azp run runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@jakobbotsch jakobbotsch marked this pull request as ready for review January 14, 2026 14:20
Copilot AI review requested due to automatic review settings January 14, 2026 14:20
@jakobbotsch
Copy link
Member Author

jakobbotsch commented Jan 14, 2026

cc @dotnet/jit-contrib PTAL @AndyAyersMS

jitstress failure is #122481.

The main change here is rewriting the analysis to work on LIR. Previously we started the tree walk at the root of each statement and kept track of the current context -- whether we are under an indirection or under a store -- and used it to either flag dependent locals as pointers or unify locals with destinations being stored to.
We now instead look for indirections/stores first, and once found we do a similar recursive visit of its address/source to determine the locals that the address/source depends on (still using a GenTreeVisitor even though we are in LIR).

There were a couple of sources of regressions after the move:

  • GT_SELECT now exist and resulted in spurious unifications between the "condition" and source destinations. Added an optimization that skips the condition of selects
  • lvSingleDefRegCandidate is now no longer computed for the shadowed locals, so propagate this from the parameter local that is shadowed (this field already models parameters as having one definition by default, so it should be fine to propagate to the shadows unconditionally)

Diffs. Some minor improvements.

This comment was marked as resolved.

Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

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

Looks good, just a few comments about comments.

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

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

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

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

@agocke agocke merged commit 541b7ab into dotnet:main Jan 15, 2026
134 of 136 checks passed
@jakobbotsch jakobbotsch deleted the fix-122954 branch January 16, 2026 14:26
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.

Test failure: _shared_generic::Async2SharedGeneric.TestEntryPoint()

4 participants