JIT: Reset compGenTreeID on failed Materialize to avoid leaking gen tree IDs - #129528
#129528JIT: Reset compGenTreeID on failed Materialize to avoid leaking gen tree IDs#129528jakobbotsch merged 7 commits intomaindotnet/runtime:mainfrom copilot/jit-fix-assertion-faileddotnet/runtime:copilot/jit-fix-assertion-failedCopy head branch name to clipboard
Conversation
…ree IDs Co-authored-by: jakobbotsch <7887810+jakobbotsch@users.noreply.github.com>
|
@copilot These fields are DEBUG only, so add #ifdef DEBUG too |
…only Co-authored-by: jakobbotsch <7887810+jakobbotsch@users.noreply.github.com>
|
Fixes #129527 |
There was a problem hiding this comment.
Pull request overview
This PR updates JIT scalar-evolution IR materialization so that a failed attempt to materialize a Scev into GenTree IR does not advance the debug-only Compiler::compGenTreeID counter. This keeps Phase::Observations invariants intact when a phase reports MODIFIED_NOTHING but speculative IR construction partially occurred and then aborted.
Changes:
- Snapshot
m_compiler->compGenTreeID(DEBUG-only) before attempting IR materialization and restore it on failure. - Expand the wrapper
ScalarEvolutionContext::Materialize(Scev* scev)from a single conditional expression into an explicit success/failure path with a rollback.
Co-authored-by: jakobbotsch <7887810+jakobbotsch@users.noreply.github.com>
Added the regression test in |
|
cc @dotnet/jit-contrib PTAL @EgorBo Debated with myself the best ways to fix this but eventually ended up with this one. There are a few:
|
|
Btw I believe we have the same thing in if-conversion where we always create a SELECT, but then may bail out without actually changing the IR. Currently it just always returns true from that point on. |
|
@copilot resolve the merge conflicts in this pull request |
|
@copilot nothing was pushed to the branch, resolve the merge conflicts |
…tion-failed # Conflicts: # src/tests/JIT/Regression/Regression_ro_2.csproj Co-authored-by: jakobbotsch <7887810+jakobbotsch@users.noreply.github.com>
|
@copilot Add a check for whether multithreading is enabled in the test. |
Co-authored-by: jakobbotsch <7887810+jakobbotsch@users.noreply.github.com>
Gated |
|
@EgorBo I need a reapproval after pushing |
…ree IDs (#129528) A Fuzzlyn-generated case tripped the `m_compGenTreeID == m_compiler->compGenTreeID` assertion (phase.cpp:47) during 'Optimize Induction Variables'. The phase reported `MODIFIED_NOTHING`, yet `compGenTreeID` had advanced. ## Root cause The `GenTree* Materialize(Scev* scev)` overload calls the internal `Materialize(scev, /*createIR*/ true, ...)`, which allocates IR nodes (bumping `compGenTreeID`) as it recurses but can still return `false` partway through — e.g. on an `AddRec`, a non-null `TYP_REF`/`TYP_BYREF` constant, or a 32-bit `MUL` of `TYP_LONG`. The orphaned nodes leak their ID increments, so a phase that ultimately makes no change observes a changed `compGenTreeID`. ## Changes - **`scev.cpp` — `GenTree* Materialize(Scev* scev)`**: snapshot `compGenTreeID` before materializing IR and restore it on a false return. Since `compGenTreeID` is a DEBUG-only field, the snapshot and reset are guarded with `INDEBUG`. ```cpp INDEBUG(unsigned prevGenTreeID = m_compiler->compGenTreeID); if (Materialize(scev, true, &result, &vnp)) { return result; } INDEBUG(m_compiler->compGenTreeID = prevGenTreeID); return nullptr; ``` `MaterializeVN` uses `createIR=false` and never allocates IR, so it needs no change. - **`src/tests/JIT/Regression/JitBlue/Runtime_129527/Runtime_129527.cs`**: regression test added and wired into the merged `Regression_ro_2.csproj`. The test entry point is gated with `[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsMultithreadingSupported))]`, since it blocks on a `Task.Yield()` continuation via `GetAwaiter().GetResult()` and would deadlock on single-threaded runtimes. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jakobbotsch <7887810+jakobbotsch@users.noreply.github.com> Co-authored-by: Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com> Co-authored-by: copilot-swe-agent[bot] <copilot@github.com>
A Fuzzlyn-generated case tripped the
m_compGenTreeID == m_compiler->compGenTreeIDassertion (phase.cpp:47) during 'Optimize Induction Variables'. The phase reportedMODIFIED_NOTHING, yetcompGenTreeIDhad advanced.Root cause
The
GenTree* Materialize(Scev* scev)overload calls the internalMaterialize(scev, /*createIR*/ true, ...), which allocates IR nodes (bumpingcompGenTreeID) as it recurses but can still returnfalsepartway through — e.g. on anAddRec, a non-nullTYP_REF/TYP_BYREFconstant, or a 32-bitMULofTYP_LONG. The orphaned nodes leak their ID increments, so a phase that ultimately makes no change observes a changedcompGenTreeID.Changes
scev.cpp—GenTree* Materialize(Scev* scev): snapshotcompGenTreeIDbefore materializing IR and restore it on a false return. SincecompGenTreeIDis a DEBUG-only field, the snapshot and reset are guarded withINDEBUG.MaterializeVNusescreateIR=falseand never allocates IR, so it needs no change.src/tests/JIT/Regression/JitBlue/Runtime_129527/Runtime_129527.cs: regression test added and wired into the mergedRegression_ro_2.csproj. The test entry point is gated with[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsMultithreadingSupported))], since it blocks on aTask.Yield()continuation viaGetAwaiter().GetResult()and would deadlock on single-threaded runtimes.