Skip to content

ssa: use defer selectors on all targets (superseded by #2208) - #2270

Closed
cpunion wants to merge 4 commits into
xgo-dev:mainfrom
cpunion:codex/generic-static-defer-dispatch
Closed

ssa: use defer selectors on all targets (superseded by #2208)#2270
cpunion wants to merge 4 commits into
xgo-dev:mainfrom
cpunion:codex/generic-static-defer-dispatch

Conversation

@cpunion

@cpunion cpunion commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Superseded by #2208.

This PR explored replacing defer continuation block addresses with selectors on every target. After reviewing Native lowering and performance risk, the final design keeps Native blockaddress/indirectbr code generation unchanged and applies selector dispatch only to Wasm.

The complete Rund and Reth implementation, Native/Wasm lit coverage, runtime execution coverage, and Wasm build validation have been moved to #2208. Closing this PR keeps review and CI focused on the target-specific design.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: generic static defer dispatch

Clean, well-motivated refactor. Replacing blockaddress/indirectbr defer dispatch with dense integer continuation selectors dispatched via switch is a net codegen improvement (enables jump-table lowering and unblocks CFG passes), the reserved-selector scheme is documented at both the definition and consumption sites, and the unreachable default is the correct pattern. I traced the rethChain/rethTargets/rundTargets index math and the selectors stay dense and consistent with the emitted switch cases — no off-by-one in the selector math. Good coverage of the tricky RunDefers-before-Defer and i32/i64 switch-width cases in the new test.

A few findings below (2 inline).

Dead code no longer reachable but left in tree

  • ssa/stmt_builder.go:212Builder.IndirectJump (emits CreateIndirectBr) has no remaining callers after this PR removes its only uses from ssa/eh.go. Its companion aBasicBlock.Addr() (ssa/stmt_builder.go:52, emits blockaddress) also appears to have no live callers now (all other .Addr() hits resolve to net/reflect/netip). Since the PR's stated goal is to eliminate defer-generated blockaddress/indirectbr, leaving the helpers that emit them invites accidental reuse — consider removing them here (after confirming no external/generated caller depends on Addr()).

Loop-defer drainer not converted to switch dispatch (optional)

  • ssa/eh.go:452-473 — the reth/rund continuations now use switch, but loopDeferDrainer still dispatches on nodeID with a hand-rolled linear chain of equality tests, emitting 2 extra basic blocks per case and an O(k) compare chain per drained node in the drain loop. The c.id values are dense integer constants, so this is exactly the shape CreateSwitch/jumpDeferTarget handles. Not a regression (this path is unchanged by the PR), but aligning it with the new dispatch strategy would be more consistent and lower IR size. Optional follow-up.

_Reviewed ssa/eh.go, runtime/internal/runtime/z_rt.go, ssa/eh_defer_test.go, and the cl/testgo CHECK updates.

Comment thread ssa/eh.go Outdated
Comment thread ssa/eh.go Outdated
@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 73.01587% with 17 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
ssa/eh.go 73.01% 14 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

@cpunion

cpunion commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up on the two optional/general review notes:

  • Confirmed there are no remaining in-repository callers of BasicBlock.Addr or Builder.IndirectJump. I am keeping them because they are exported general SSA-builder APIs; removing them would be a separate public API compatibility decision. This PR removes every defer-generated use.
  • The loop nodeID chain is existing payload-tag dispatch rather than a continuation selector. Its unknown-ID behavior also exits the drainer rather than being unreachable. Converting that path to an LLVM switch can be evaluated separately without expanding this correctness/portability change.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

LLGo baseline benchmarks

2353dec74d1f | workflow run | long-term charts

Program measurements

Platform Workload File size vs main Build vs main Run vs main
Linux cprintf 18344 B +0.0% 239.146 ms -19.0% (better) 1.003 ms -25.0% (better)
Linux fmtprintf 1833064 B +0.1% (worse) 2.588 s -13.6% (better) 2.540 ms -18.0% (better)
Linux println 67720 B +0.0% 233.233 ms -21.0% (better) 1.149 ms -33.7% (better)
macOS cprintf 84672 B +0.0% 376.967 ms +14.2% (worse) 4.028 ms +58.8% (worse)
macOS fmtprintf 1861456 B -0.4% (better) 5.024 s +96.9% (worse) 16.572 ms +42.4% (worse)
macOS println 121200 B +0.0% 445.398 ms +41.4% (worse) 4.630 ms +33.0% (worse)
Core language and compiler benchmarks
Platform Benchmark ns/op vs main
Linux BenchmarkLookupPCRandom 10.180 ns/op -24.2% (better)
Linux BenchmarkMergeCompilerFlags 123.600 ns/op -17.8% (better)
Linux BenchmarkMergeLinkerFlags 85.860 ns/op -9.0% (better)
Linux BenchmarkChannelBuffered 54.730 ns/op +35.9% (worse)
Linux BenchmarkChannelHandoff 27833 ns/op +7.7% (worse)
Linux BenchmarkDefer 39.810 ns/op -6.5% (better)
Linux BenchmarkDirectCall 0.971 ns/op -37.6% (better)
Linux BenchmarkGlobalRead 1.331 ns/op -14.6% (better)
Linux BenchmarkGlobalWrite 7.914 ns/op +218.2% (worse)
Linux BenchmarkGoroutine 35633 ns/op +4.8% (worse)
Linux BenchmarkInterfaceCall 6.389 ns/op -17.9% (better)
Linux BenchmarkRuntimeGetG 1.220 ns/op -36.9% (better)
macOS BenchmarkLookupPCRandom 17.450 ns/op +62.2% (worse)
macOS BenchmarkMergeCompilerFlags 166.400 ns/op +48.4% (worse)
macOS BenchmarkMergeLinkerFlags 134.700 ns/op +98.8% (worse)
macOS BenchmarkChannelBuffered 32.820 ns/op -6.7% (better)
macOS BenchmarkChannelHandoff 10041 ns/op +116.7% (worse)
macOS BenchmarkDefer 51.290 ns/op +22.8% (worse)
macOS BenchmarkDirectCall 1.408 ns/op +16.4% (worse)
macOS BenchmarkGlobalRead 1.200 ns/op -9.3% (better)
macOS BenchmarkGlobalWrite 1.442 ns/op +2.4% (worse)
macOS BenchmarkGoroutine 50210 ns/op +123.1% (worse)
macOS BenchmarkInterfaceCall 6.557 ns/op +1.1% (worse)
macOS BenchmarkRuntimeGetG 3.042 ns/op +4.5% (worse)

Compared only with the latest matching platform in the main series.

@cpunion
cpunion force-pushed the codex/generic-static-defer-dispatch branch from a830839 to 2353dec Compare August 3, 2026 11:31
@cpunion cpunion changed the title ssa: use static defer continuation selectors ssa: use defer selectors on all targets (superseded by #2208) Aug 3, 2026
@cpunion

cpunion commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #2208, which now contains the tested Wasm-only Rund/Reth selector design while preserving Native defer dispatch.

@cpunion cpunion closed this Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant