Skip to content

debug: keep optimization and SSA rewrites DWARF-safe - #2143

Merged
xushiwei merged 13 commits into
xgo-dev:mainfrom
cpunion:codex/dwarf-opt-pipeline
Aug 4, 2026
Merged

debug: keep optimization and SSA rewrites DWARF-safe#2143
xushiwei merged 13 commits into
xgo-dev:mainfrom
cpunion:codex/dwarf-opt-pipeline

Conversation

@cpunion

@cpunion cpunion commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

This is the consolidated DWARF-safe optimization and SSA-rewrite change.

The effective implementation from #2183
(return-load ordering) and #2184
(single-case-select ordering) is included here exactly once. Those PRs are no
longer dependencies of this change; their unrelated CI-only commits are not
carried over.

Problem

DWARF must not change executable semantics. Enabling the normal optimization pipeline for debug builds exposed four places where debug metadata affected code generation:

  • linked builds skipped the configured LLVM pass pipeline whenever DWARF was emitted;
  • conditional defer lowering created inlinable runtime calls without !dbg, so full LTO verification aborted;
  • ssa.DebugRef users blocked return-load and single-case-select order repairs;
  • ssa.DebugRef users blocked valid static global slice folding.

Full LTO with DWARF also exposes aggregate Go strings to the reflect MethodByName plugin. #2159, now in main, owns that boundary; this PR contains no LTO plugin implementation changes.

Changes

  • run the normal LLVM pass pipeline for linked modes with or without DWARF, while keeping ModeGen as raw generated IR;
  • derive the compile unit optimized marker from the actual pass decision and optimization level;
  • inherit the source location when defer lowering splits the entry block;
  • move ssa.DebugRef users with repaired return loads and select dependencies, while rejecting executable early uses;
  • bound the metadata scan before the receive and document the stable instruction-group fallback;
  • ignore DebugRef pseudo-users when proving a static slice initializer.

This consolidates the effective changes from #2144, #2146, #2183, and #2184. It does not change the default -w policy, Python debugging, pclntab policy, C ABI variable homes, LLDB language behavior, or non-debug optimization policy.

Fixes #2118.
Fixes #2121.
Fixes #2122.

Verification

  • focused internal/build SSA-order tests pass in both default and ssa.GlobalDebug modes;
  • TestDWARFReturnOrderSemantics passes with explicit -w=false;
  • focused ssa, internal/build, and LTO/DWARF cl tests pass on macOS arm64;
  • git diff --check passes.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.10145% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cl/static_init.go 87.50% 0 Missing and 1 partial ⚠️
internal/build/ssa_order_fix.go 98.00% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@cpunion
cpunion force-pushed the codex/dwarf-opt-pipeline branch from 8817c9d to 6e8d80a Compare July 22, 2026 08:19
@cpunion cpunion changed the title [Based on #2141] debug: run LLVM passes with DWARF debug: run LLVM passes with DWARF Jul 22, 2026
@cpunion
cpunion marked this pull request as ready for review July 22, 2026 09:19
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@cpunion cpunion changed the title debug: run LLVM passes with DWARF debug: keep optimization and SSA rewrites DWARF-safe Jul 22, 2026
@cpunion
cpunion force-pushed the codex/dwarf-opt-pipeline branch from 31a3bbf to d4f4386 Compare July 23, 2026 00:20
@cpunion cpunion changed the title debug: keep optimization and SSA rewrites DWARF-safe [Based on #2159] debug: keep optimization and SSA rewrites DWARF-safe Jul 23, 2026
@cpunion
cpunion force-pushed the codex/dwarf-opt-pipeline branch 2 times, most recently from 1955174 to 7c57a58 Compare July 23, 2026 05:07
@cpunion
cpunion force-pushed the codex/dwarf-opt-pipeline branch 2 times, most recently from 04c6326 to 822efaa Compare July 25, 2026 03:31
@cpunion cpunion changed the title [Based on #2159] debug: keep optimization and SSA rewrites DWARF-safe debug: keep optimization and SSA rewrites DWARF-safe Jul 25, 2026
@cpunion
cpunion marked this pull request as draft July 25, 2026 04:58
@cpunion
cpunion marked this pull request as ready for review July 26, 2026 09:21

@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 Summary

Solid, well-tested change. The core intent — running LLVM optimization passes even when DWARF is emitted, and making SSA reordering / static-init rewrites ignore DebugRef pseudo-instructions so enabling debug info never alters lowering decisions — is implemented correctly and thoroughly covered.

I verified the areas most likely to hide bugs and found them sound:

  • moveInstrsAfter (internal/build/ssa_order_fix.go) preserves the old "move the load right after the last call" semantics. The anchor is matched by identity, so removing the load first still lands the group immediately after the last call; the moved group keeps stable relative order; and all edge cases (empty moving, nil anchor, anchor not found) return the input unchanged.
  • includeDebugRefsForMovedValues correctly bounds its scan by through (== recvIdx) and runs before moveWouldBreakSSA, which skips already-moved indices — so a DebugRef using a moved value is carried along rather than falsely reported as an SSA break. DebugRefs produce no value, so they never chain into the moved-value set.
  • nonDebugReferrers (cl/static_init.go / cl/ssa_referrers.go) is behavior-preserving for the non-debug path: (nil, false) exactly when Referrers() is nil, and identical to the old filtered list when no DebugRefs are present.
  • deferInitBuilder (ssa/eh.go) guards the location copy behind p.diFunc != nil and a non-nil loc.Scope, so an unset location is safely skipped.
  • Performance: the new allocations in moveInstrsAfter and nonDebugReferrers sit on narrowly-gated, rarely-triggered recognition/repair paths and stay within the same asymptotic complexity as the code they replace — no meaningful compile-time regression.
  • Security: the new test/go/dwarf_semantics_acceptance_test.go uses a static hardcoded arg list, a compile-time-constant temp file at 0o600, and no untrusted input — no injection or unsafe temp-file concerns.

One minor doc-accuracy finding is inline. A minor naming nit (non-blocking): test/go/dwarf_semantics_acceptance_test.go reuses the helper findStringConversionRepoRoot, whose StringConversion-specific name is now misleading as a shared repo-root finder — consider renaming to findRepoRoot in a follow-up.

View job run

Comment thread ssa/package.go Outdated
@cpunion
cpunion force-pushed the codex/dwarf-opt-pipeline branch 2 times, most recently from e792edd to 014b06d Compare July 28, 2026 12:37
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

LLGo baseline benchmarks

2381bb9b69bb | workflow run | long-term charts

Program measurements

Platform Workload File size vs base Build vs base Run vs base
Linux cprintf 18344 B +0.0% 231.865 ms -6.3% (better) 1.003 ms -4.4% (better)
Linux fmtprintf 1831176 B +0.0% 2.634 s +1.1% (worse) 2.689 ms +17.4% (worse)
Linux println 67720 B +0.0% 233.360 ms -7.2% (better) 1.298 ms +7.4% (worse)
macOS cprintf 84672 B +0.0% 321.182 ms -42.9% (better) 2.446 ms -48.2% (better)
macOS fmtprintf 1869328 B +0.0% 2.690 s -28.8% (better) 12.611 ms -14.8% (better)
macOS println 121200 B +0.0% 359.310 ms -33.4% (better) 4.325 ms -14.0% (better)
Core language and compiler benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkLookupPCRandom 10.990 ns/op +8.0% (worse)
Linux BenchmarkMergeCompilerFlags 127.800 ns/op +4.5% (worse)
Linux BenchmarkMergeLinkerFlags 83.620 ns/op -1.7% (better)
Linux BenchmarkChannelBuffered 51.130 ns/op +1.1% (worse)
Linux BenchmarkChannelHandoff 25223 ns/op +0.7% (worse)
Linux BenchmarkDefer 40.470 ns/op -5.4% (better)
Linux BenchmarkDirectCall 1.247 ns/op +3.0% (worse)
Linux BenchmarkGlobalRead 1.223 ns/op +6.0% (worse)
Linux BenchmarkGlobalWrite 7.634 ns/op +2.8% (worse)
Linux BenchmarkGoroutine 34913 ns/op -1.6% (better)
Linux BenchmarkInterfaceCall 5.752 ns/op -10.3% (better)
Linux BenchmarkRuntimeGetG 1.443 ns/op +1.5% (worse)
macOS BenchmarkLookupPCRandom 13.320 ns/op -8.5% (better)
macOS BenchmarkMergeCompilerFlags 122.300 ns/op -12.2% (better)
macOS BenchmarkMergeLinkerFlags 73.960 ns/op -5.7% (better)
macOS BenchmarkChannelBuffered 24.980 ns/op +9.0% (worse)
macOS BenchmarkChannelHandoff 7792 ns/op +10.9% (worse)
macOS BenchmarkDefer 39.080 ns/op +6.0% (worse)
macOS BenchmarkDirectCall 1.093 ns/op +2.9% (worse)
macOS BenchmarkGlobalRead 1.178 ns/op +3.6% (worse)
macOS BenchmarkGlobalWrite 1.142 ns/op +7.3% (worse)
macOS BenchmarkGoroutine 53191 ns/op +31.1% (worse)
macOS BenchmarkInterfaceCall 5.230 ns/op +13.6% (worse)
macOS BenchmarkRuntimeGetG 2.524 ns/op +15.6% (worse)

Compared with d39ed76b102e measured in the same runner job.

@cpunion cpunion closed this Aug 3, 2026
@cpunion cpunion reopened this Aug 3, 2026

@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 summary

This PR makes the SSA order-fix and static-init pipeline debug-info aware so that DebugRef metadata no longer blocks otherwise-safe source-order repairs, plus decouples DWARF Optimized marking from pass selection. The core approach is sound and well-tested (per-mode default/global-debug variants, an end-to-end acceptance test, and a crypto/x509.ParseOID regression). All four review passes (quality, performance, security, docs) found no blocking correctness, security, or performance issues. The notes below are low-severity maintainability/precision items.

Maintainability

  • internal/build/ssa_order_fix.go — the "move DebugRefs along with the value they describe" logic now exists in two forms: the includeDebugRefsForMovedValues helper (index-set driven, used by moveAssignDepsAfterRecv) and the inline loop in fixSSAOrderBlock (instruction-set driven). Both are correct but duplicative with different data-structure conventions; consolidating onto one helper would reduce future drift.
  • internal/build/ssa_order_fix.goincludeDebugRefsForMovedValues and moveWouldBreakSSA run back-to-back in moveAssignDepsAfterRecv and each independently rebuild the same moved set by scanning move. The second rebuild is required (the first mutates move), but the duplicated prefix scan is avoidable. Low impact — this path is gated behind the rare single-case-select receive-assign pattern.

Doc precision

  • internal/build/ssa_order_fix.go:24 — the fixSSAOrder doc comment says it moves "loads of local allocs used only for the final Return results," but fixSSAOrderBlock actually only checks that there is no intervening executable use between the load and the Return (DebugRefs are allowed and moved along). A load also referenced elsewhere without an executable use in the load→Return window would still move. Consider wording closer to "loads that feed a Return result and have no intervening executable use before that Return."

Reviewed against 8dbfab5...1470ef8.

Comment thread internal/build/ssa_order_fix.go
@cpunion
cpunion force-pushed the codex/dwarf-opt-pipeline branch from 29ba321 to 17ac3d3 Compare August 3, 2026 09:22
@xushiwei
xushiwei merged commit 6670dae into xgo-dev:main Aug 4, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants