Skip to content

Conversation

SingleAccretion
Copy link

@SingleAccretion SingleAccretion commented Sep 19, 2025

This paves the way for introducing some RPI/PI optimizations and also moves us a bit closer to the model where all that's possible to do in IR is done in IR.

Setting up the shadow stack in IR is a tricky problem since we don't want to spill it to an alloca even in debug code. We therefore modify how we refer to the shadow stack:

  1. For the main function, we use an untracked SSA local. Note how we are introducing a new concept here - usually all SSA locals are tracked.
  2. For funclets, we repurpose the pre-existing PHYSREG node to allow us to refer to the LLVM argument directly.

However, the IR representation is just one part of the problem. Another is the fact codegen needs to refer to the shadow stack directly, for debug info and helper call generation purposes. Since some of this needs to happen "in the prolog", before any IR is generated, we also introduce a concept of "late" and "early" prologs. They are sequenced as follows:

  • "Early" prolog - codegen (LLVM IR)
  • "Middle" prolog - LSSA (IR)
  • "Late" prolog - codegen (LLVM IR)

This is almost a zero-diff change; the few diffs are due to the different ordering of native stack init and shadow stack init for RPI methods.

Part of #3163.

This paves the way for introducing some RPI/PI optimizations and also moves us
a bit closer to the model where all that's possible to do in IR is done in IR.

Setting up the shadow stack in IR is a tricky problem since we don't want to
spill it to an alloca even in debug code. We therefore modify how we refer
to the shadow stack:
1) For the main function, we use an untracked SSA local. Note how we are
   introducing a new concept here - usually all SSA locals are tracked.
2) For funclets, we repurpose the pre-existing PHYSREG node to allow us
   to refer to the LLVM argument directly.

However, the IR representation is just one part of the problem. Another is the
fact codegen needs to refer to the shadow stack directly, for debug info and helper
call generation purposes. Since some of this needs to happen "in the prolog", before
any IR is generated, we also introduce a concept of "late" and "early" prologs.
They are sequenced as follows:

 - "Early"  prolog - codegen (LLVM IR)
 - "Middle" prolog - LSSA (IR)
 - "Late"   prolog - codegen (LLVM IR)

This is almost a zero-diff change; the few diffs are due to the different
ordering of native stack init and shadow stack init for RPI methods.
@SingleAccretion SingleAccretion changed the title Set up the shadow stack in LSSA [NativeAOT-LLVM] Set up the shadow stack in LSSA Sep 19, 2025
@jkotas jkotas added the area-NativeAOT-LLVM LLVM generation for Native AOT compilation (including Web Assembly) label Sep 19, 2025
@SingleAccretion SingleAccretion marked this pull request as ready for review September 19, 2025 13:05
@SingleAccretion
Copy link
Author

@dotnet/nativeaot-llvm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-NativeAOT-LLVM LLVM generation for Native AOT compilation (including Web Assembly)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants