Repository navigation
transform: follow merged pointers during escape analysis - #6236
Open
jakebailey wants to merge 1 commit into
Open
jakebailey wants to merge 1 commit into
jakebailey wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The allocation promotion can collapse overlapping loop-iteration lifetimes into one entry-block alloca, overwriting a still-live previous object and changing loaded values.
1 open issue
What changed in this PR
This PR extends TinyGo’s escape analysis to follow pointers through PHI merges, allowing read-only uses to qualify for stack allocation.
Changes:
- Handle PHI nodes alongside existing bitcast and select traversal.
- Add regression cases for read-only merges, returned pointers, and pointer cycles.
- Update the expected escape diagnostic location.
| File | Description |
|---|---|
| transform/testdata/allocs2.go | Update the expected escape location to the return statement. |
| transform/testdata/allocs.out.ll | Record expected stack and heap allocation results. |
| transform/testdata/allocs.ll | Add select, PHI, and pointer-cycle test cases. |
| transform/allocs.go | Follow PHI users when determining pointer escapes. |
Review effort: Balanced
| } | ||
| case llvm.BitCast: | ||
| // A bitcast escapes if the casted-to value escapes. | ||
| case llvm.BitCast, llvm.PHI, llvm.Select: |
Merging a pointer with another value does not itself make the pointer escape. Treating every phi as an escape forces temporary reflection storage onto the heap even when its users only read it. Follow the merged value to its actual users while preserving conservative handling of cycles and pointers that are returned or stored elsewhere. Loop-carried pointers can outlive the next allocation, so merges in control-flow cycles must remain conservative too.
jakebailey
force-pushed
the
stack-promote-pointer-merges
branch
from
November 9, 2026 18:00
17e1cc0 to
21584e2
Compare
Contributor
|
Thanks @jakebailey. Possible follow-up, not for this PR: blockInCycle rejects every phi inside a loop, including an if/else merge within one iteration, so temporaries in loop bodies stay on the heap. Rejecting only phis that carry a value across the loop's back edge would keep the fix for the loop-carried case and allow those. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Merging a pointer with another value does not itself make the pointer escape. Treating every phi and select as an escape forces temporary reflection storage onto the heap even when its users only read it.
Follow the merged value to its actual users while preserving conservative handling of cycles and pointers that are returned or stored elsewhere.