JIT: Add an IV opt that replaces primary IVs with enregisterable ones #129305
JIT: Add an IV opt that replaces primary IVs with enregisterable ones #129305jakobbotsch wants to merge 4 commits into
Conversation
This optimization detects when a primary IV will not be enregistered based on DNER or due to being EH live, and if possible, creates a new primary IV to split its lifetime to make it enregisterable.
| // We must be able to insert the store-back of the final value into every | ||
| // regular exit where the IV is live. Blocks that are part of a call-finally | ||
| // pair must remain empty, so we cannot sink into them. | ||
| BasicBlockVisit exitResult = loop->VisitRegularExitBlocks([=](BasicBlock* exit) { | ||
| if (optLocalIsLiveIntoBlock(lclNum, exit) && (exit->isBBCallFinallyPair() || exit->isBBCallFinallyPairTail())) | ||
| { | ||
| return BasicBlockVisit::Abort; | ||
| } | ||
|
|
||
| return BasicBlockVisit::Continue; | ||
| }); |
There was a problem hiding this comment.
We should change exit canonicalization to make sure there don't exist as exits, but I think it can be a follow up.
There was a problem hiding this comment.
Pull request overview
This PR extends CoreCLR JIT induction-variable optimizations by adding a late pass that can replace primary IV locals that won’t be enregistered (DNER or EH live-in/out-of-handler) with a fresh temp whose lifetime is constrained to the loop body, and adds a regression test covering try/finally and try/catch interaction.
Changes:
- Add a new IV replacement pass in
optInductionVariables()plus helper legality/liveness checks and an in-loop local replacement walker. - Add a new JIT metadata metric (
EnregisterableIVsCreated) to track how many replacements were performed. - Add a new JIT regression test (
PrimaryIVLiveInHandler) validating correctness across finally paths, throwing loops, and catch-resume paths.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/coreclr/jit/inductionvariableopts.cpp | Implements the new unenregisterable-primary-IV replacement optimization and hooks it into the IV opts phase. |
| src/coreclr/jit/compiler.h | Declares the new Compiler::opt* helpers used by the replacement pass. |
| src/coreclr/jit/jitmetadatalist.h | Adds a new metadata metric to report how many enregisterable IV replacements were created. |
| src/tests/JIT/opt/Loops/PrimaryIVLiveInHandler.cs | Adds regression coverage for IV replacement correctness with try/finally and try/catch shapes. |
| src/tests/JIT/opt/Loops/PrimaryIVLiveInHandler.csproj | Adds the project file to build the new JIT test. |
| // We must be able to insert the store-back of the final value into every | ||
| // regular exit where the IV is live. Blocks that are part of a call-finally | ||
| // pair must remain empty, so we cannot sink into them. | ||
| BasicBlockVisit exitResult = loop->VisitRegularExitBlocks([=](BasicBlock* exit) { | ||
| if (optLocalIsLiveIntoBlock(lclNum, exit) && (exit->isBBCallFinallyPair() || exit->isBBCallFinallyPairTail())) | ||
| { | ||
| return BasicBlockVisit::Abort; | ||
| } | ||
|
|
||
| return BasicBlockVisit::Continue; | ||
| }); | ||
|
|
||
| if (exitResult == BasicBlockVisit::Abort) | ||
| { | ||
| JITDUMP(" Cannot replace V%02u; a live regular exit is part of a call-finally pair\n", lclNum); | ||
| return false; | ||
| } |
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
|
SuperPMI collections show:
Might be worth taking. |
This optimization detects when a primary IV will not be enregistered based on DNER or due to being EH live, and if possible, creates a new primary IV to split its lifetime to make it enregisterable.
Fixes #124285