Skip to content

LateLowerGCFrame: Fix GC rooting for stores through select/phi of allocas#61229

Merged
gbaraldi merged 3 commits intomasterfrom
gb/fix-gc-select-phi-store
Mar 9, 2026
Merged

LateLowerGCFrame: Fix GC rooting for stores through select/phi of allocas#61229
gbaraldi merged 3 commits intomasterfrom
gb/fix-gc-select-phi-store

Conversation

@gbaraldi
Copy link
Copy Markdown
Member

@gbaraldi gbaraldi commented Mar 4, 2026

Summary

  • Fix GC corruption when stores to tracked allocas go through a select or phi between two alloca pointers (Repeatable GC corruption on v1.13-beta2 #60985)
  • Rename FindSretAllocas to FindAllocaBases and reuse it in MaybeTrackStore to look through selects/phis to find alloca bases
  • Fix the safepoint check in runOnFunction that skipped GC frame creation when ArrayAllocas/TrackedStores had entries but no numbered def existed before the safepoint in the entry block

Details

LLVM's SROA/InstCombine can merge two conditional alloca stores into a select over the alloca pointers:

%. = select i1 %cond, ptr %alloca1, ptr %alloca2
store ptr addrspace(10) %gc_val, ptr %.

In MaybeTrackStore, stripInBoundsOffsets() returns the select (not an alloca), so dyn_cast<AllocaInst> fails and the function returns early. Neither alloca gets added to ArrayAllocas, no GC frame is created, and tracked values go unrooted → GC corruption.

The fix also addresses a pre-existing issue where the safepoint check in runOnFunction would skip GC frame creation when ArrayAllocas had entries but no numbered def existed before the safepoint in the entry block.

Test plan

  • Added test/llvmpasses/late-lower-gc-select-store.ll with regression tests for both select and phi cases
  • Verified all existing late-lower-gc*.ll FileCheck tests still pass
  • Ran static analysis (clang-tidy, clang-sa, clang-sagc) with no issues
  • Verified the original reproducer from Repeatable GC corruption on v1.13-beta2 #60985 now emits a GC frame

🤖 Generated with Claude Code

…ocas

LLVM's SROA/InstCombine can merge two conditional alloca stores into a
select (or phi) over the alloca pointers:

    %. = select i1 %cond, ptr %alloca1, ptr %alloca2
    store ptr addrspace(10) %gc_val, ptr %.

In MaybeTrackStore, stripInBoundsOffsets() returns the select (not an
alloca), so dyn_cast<AllocaInst> fails and the function returns early
via the `else { return; }` branch. Neither alloca gets added to
ArrayAllocas, no GC frame is created, and tracked values go unrooted,
leading to GC corruption.

This commit fixes two issues:

1. Rename FindSretAllocas to FindAllocaBases and reuse it in
   MaybeTrackStore to look through selects/phis when resolving the
   store target to its underlying alloca(s).

2. Fix the safepoint check in runOnFunction that was skipping GC frame
   creation when ArrayAllocas/TrackedStores had entries but no numbered
   def existed before the safepoint in the entry block. This was a
   pre-existing bug where even a simple `alloca ptr addrspace(10)` in an
   entry-block-only function would fail to get rooted.

Fixes #60985

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@topolarity topolarity added bugfix This change fixes an existing bug backport 1.13 Change should be backported to release-1.13 labels Mar 4, 2026
The SmallSetVector worklist removed elements from the set on
pop_back_val(), allowing cyclic PHI graphs to re-insert and
re-process the same values indefinitely. Use a separate SmallPtrSet
to track visited values that persists across iterations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of the overzealous HasAnySafepoint check (which checked for any
safepoint anywhere in the function), have MaybeTrackStore return whether
it tracked an alloca and set FirstSafepointAfterFirstDef at the call
site. This integrates tracked stores into the existing def/safepoint
analysis, so GC frames are only created when a safepoint actually
follows the store in program order.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JeffBezanson JeffBezanson added GC Garbage collector compiler:codegen Generation of LLVM IR and native code labels Mar 5, 2026
@gbaraldi gbaraldi merged commit 8ce9654 into master Mar 9, 2026
9 of 10 checks passed
@gbaraldi gbaraldi deleted the gb/fix-gc-select-phi-store branch March 9, 2026 14:10
@KristofferC KristofferC mentioned this pull request Mar 13, 2026
27 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport 1.13 Change should be backported to release-1.13 bugfix This change fixes an existing bug compiler:codegen Generation of LLVM IR and native code GC Garbage collector

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants