Skip to content

fix: pad trailing zero-sized Go struct fields on amd64 and arm64 - #2860

Open
MeteorsLiu wants to merge 2 commits into
xgo-dev:mainfrom
MeteorsLiu:codex/fix-go-trailing-zero-field
Open

MeteorsLiu wants to merge 2 commits into
xgo-dev:mainfrom
MeteorsLiu:codex/fix-go-trailing-zero-field

Conversation

@MeteorsLiu

@MeteorsLiu MeteorsLiu commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2797 by reserving the physical storage required for ordinary Go structs with trailing zero-sized fields, so compiled access and reflection agree on element sizes and nested field offsets.

The implementation includes:

  • A private tail-padding helper that appends one LLVM byte only when the final zero-sized field lies at the end of a nonempty allocation, preserving existing implicit padding and native C types.
  • Explicit target dispatch in toLLVMStructBody, with comments distinguishing tail-only correction from the existing 386 and profiled Wasm field-layout conversion.
  • A platform-selected reflection padding helper that describes the added storage to libffi while preserving natural alignment and the existing Windows/386 call layout.
  • A golden regression in runtime/_test/codegen/trailingzero: expect.txt covers physical strides, reflection reads/writes, copy guards, nested fields, zero-sized objects, and reflected calls; source CHECK directives cover LLVM layouts on Linux, macOS, and Windows for amd64/arm64 through the existing runner.
  • Validation against Go reference output, confirmed golden mismatches with the unpatched compiler, and passing Linux/arm64 O0/O2 runs plus all six target IR checks. The SSA suite, targeted C ABI regressions, existing reflection and MakeFunc tests, and LLDB-based layoutlint checks also passed.

Reflective indexing, writes, and copying now agree with physical storage without changing the Windows/386 call convention; native execution on other platforms remains for CI.

@MeteorsLiu MeteorsLiu changed the title fix: preserve storage for trailing zero-sized Go fields fix: pad trailing zero-sized Go struct fields on amd64 and arm64 Oct 18, 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.

This PR fixes storage/ABI handling for structs with a trailing zero-sized field. The change is well-reasoned and the two paths (SSA storage layout via padZeroSizedStructTail and the runtime FFI call type via padFFIZeroSizedStructTail) agree on when to add tail storage.

Verified correct

  • Build tags are exact complements — windows && 386 is the precise negation of !windows || !386 (De Morgan): no overlap, no gap.
  • No out-of-bounds indexing — padZeroSizedStructTail is only reached from the default branch, after the case native || len(fields) == 0: return guard, so fields[len(fields)-1] is always valid. padFFIZeroSizedStructTail short-circuits on len(st.Fields) != 0 before indexing.
  • No uintptr underflow — typ.Size_ - off is only reached when align(off, Align_) < typ.Size_, which (since align(x,n) >= x) implies off < typ.Size_, so the result is strictly positive.
  • SSA/FFI layout consistency — both sides use equivalent predicates: {int64; struct{}} gains a trailing word on both; {float64; float32; struct{}} gains nothing on both (preserving call classification). The no-op Windows/386 FFI variant is consistent with the 386 SSA path, which routes through the field-layout conversion rather than padZeroSizedStructTail.

Note

The main actionable item is missing test coverage for the new default-target path (see inline). No performance concerns and no memory-safety defects were found in the diff.

Comment thread ssa/type_layout.go
// the object. Existing tail padding, as in { float64; float32; struct{} },
// already provides that space; adding a field there could change call ABI
// classification even though the size remains 16.
func (p Program) padZeroSizedStructTail(fields []llvm.Type) []llvm.Type {

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.

[P2] No test covers the new default-target zero-sized-tail path

This is the actual bug fix (the default, non-386/non-wasm-profile path), yet it has no test. All existing struct-layout tests in ssa/abitype_layout_test.go construct NewProgram(&Target{GOOS: "windows", GOARCH: "386"}), which takes the case goarch == "386" branch and never exercises padZeroSizedStructTail. The subtest "final zero-sized field has a distinct address" checks the same property, but only through the 386 path.

Suggest adding a test on e.g. linux/amd64 asserting: (a) {int64; struct{}} has size 16 with the trailing field addressable inside the object, and (b) {float64; float32; struct{}} stays size 16 with no added tail byte — locking in the "do not change call classification" invariant. CLAUDE.md states "All bug fixes and features MUST include tests."

Comment thread ssa/type_layout.go
return p.padZeroSizedStructTail(fields), nil
}

// Both cases above continue through the existing field-layout conversion.

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.

[P3] Switch fall-through comment is subtle

"Both cases above continue through the existing field-layout conversion" is correct but relies on the reader knowing that the empty case goarch == "386": and case goarch == "wasm" ...: bodies simply exit the switch (Go cases don't fall through) and reach the code below. Consider making this explicit, e.g. "The 386 and wasm-profile cases have empty bodies and continue below through the existing field-layout conversion." Readability nit only — the control flow is correct.

)

// padFFIZeroSizedStructTail accounts for storage beyond natural alignment:
// two pointers followed by struct{} need a third word. Ordinary tail padding,

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.

[P3] "third word" example is implicitly 64-bit

This file also builds for 32-bit non-Windows targets (e.g. linux/386, linux/arm), where two pointers are 8 bytes and the struct is bumped to 12 — not a 24-byte "third word". The example is correct for 64-bit but target-specific; consider qualifying it as a 64-bit example. Not a correctness issue — the code (align(off, Align_) < Size_) is size-driven and handles both widths.

"github.com/xgo-dev/llgo/runtime/internal/ffi"
)

// Windows/386 C ABI removes Go field wrappers and their tail padding:

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.

[P3] "removes Go field wrappers" has no operation in this file

The function returns fields unchanged, relying on toFFIStructType having already skipped the zero-sized field; wrapper handling lives in the ssa layout path, not here. The following sentence "Keep the original field description" accurately states what this code does, so the pairing is understandable — but "removes ... wrappers" describes ABI rationale with no corresponding action in this file. Minor wording only.

@codecov

codecov Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

Copy link
Copy Markdown

LLGo baseline benchmarks

259c0194dc3f | workflow run | long-term charts

Program measurements

Platform Workload File size vs base Text size vs base Build vs base Run vs base
Linux cprintf 8544 B 0 B / +0.0% 387 B 0 B / +0.0% 892.133 ms -14.88 ms / -1.6% (better) 1.392 ms +36.18 us / +2.7% (worse)
Linux cprintf-lto 8336 B 0 B / +0.0% 368 B 0 B / +0.0% 898.885 ms -16.11 ms / -1.8% (better) 1.353 ms -68.82 us / -4.8% (better)
Linux fmtprintf 2703568 B +1744 B / +0.1% (worse) 507167 B +270 B / +0.1% (worse) 5.881 s -182.9 ms / -3.0% (better) 4.186 ms -173.5 us / -4.0% (better)
Linux fmtprintf-lto 2195472 B +1704 B / +0.1% (worse) 445059 B +248 B / +0.1% (worse) 15.123 s -162.7 ms / -1.1% (better) 4.106 ms -125.1 us / -3.0% (better)
Linux println 242040 B +80 B / +0.03306% (worse) 17095 B 0 B / +0.0% 912.781 ms +14.63 ms / +1.6% (worse) 1.706 ms -143.8 us / -7.8% (better)
Linux println-lto 105192 B +32 B / +0.03043% (worse) 14484 B 0 B / +0.0% 1.225 s -18.92 ms / -1.5% (better) 1.765 ms +23.29 us / +1.3% (worse)
macOS cprintf 50672 B 0 B / +0.0% 4409 B 0 B / +0.0% 951.904 ms -10.18 ms / -1.1% (better) 2.708 ms -508.8 us / -15.8% (better)
macOS cprintf-lto 50592 B 0 B / +0.0% 161 B 0 B / +0.0% 836.573 ms -2.66 ms / -0.3% (better) 2.601 ms -138.3 us / -5.0% (better)
macOS fmtprintf 1659920 B +112 B / +0.006748% (worse) 884096 B +352 B / +0.03983% (worse) 3.585 s -465.2 ms / -11.5% (better) 31.519 ms +752 us / +2.4% (worse)
macOS fmtprintf-lto 1378752 B +16576 B / +1.2% (worse) 767152 B +324 B / +0.04225% (worse) 7.816 s -275.4 ms / -3.4% (better) 60.619 ms +2.197 ms / +3.8% (worse)
macOS println 96512 B 0 B / +0.0% 24519 B 0 B / +0.0% 858.159 ms -22.92 ms / -2.6% (better) 3.521 ms -413.1 us / -10.5% (better)
macOS println-lto 84112 B -16 B / -0.01902% (better) 21732 B 0 B / +0.0% 1.052 s -137.6 ms / -11.6% (better) 4.607 ms -1.278 ms / -21.7% (better)
Windows MinGW cprintf 676352 B 0 B / +0.0% 4390 B 0 B / +0.0% 1.668 s +72.92 ms / +4.6% (worse) 3.436 ms -403.8 us / -10.5% (better)
Windows MinGW cprintf-lto 44544 B 0 B / +0.0% 4342 B 0 B / +0.0% 1.713 s +89.57 ms / +5.5% (worse) 3.389 ms -450.5 us / -11.7% (better)
Windows MinGW fmtprintf 5476352 B +3072 B / +0.1% (worse) 606214 B +240 B / +0.03961% (worse) 5.533 s +210.7 ms / +4.0% (worse) 11.498 ms +1.032 ms / +9.9% (worse)
Windows MinGW fmtprintf-lto 4162560 B +1536 B / +0.03691% (worse) 553350 B +256 B / +0.04629% (worse) 13.331 s +679.6 ms / +5.4% (worse) 11.063 ms -665 us / -5.7% (better)
Windows MinGW println 733696 B 0 B / +0.0% 25286 B 0 B / +0.0% 1.674 s +65.07 ms / +4.0% (worse) 6.757 ms -349.6 us / -4.9% (better)
Windows MinGW println-lto 210944 B 0 B / +0.0% 22166 B 0 B / +0.0% 1.967 s +117.9 ms / +6.4% (worse) 6.611 ms -127.6 us / -1.9% (better)
Windows MinGW 386 cprintf 627200 B 0 B / +0.0% 5352 B 0 B / +0.0% 1.685 s +33.22 ms / +2.0% (worse) 5.705 ms +399.6 us / +7.5% (worse)
Windows MinGW 386 cprintf-lto 104448 B 0 B / +0.0% 5112 B 0 B / +0.0% 1.675 s -31.05 ms / -1.8% (better) 5.324 ms +227.3 us / +4.5% (worse)
Windows MinGW 386 fmtprintf 4776960 B 0 B / +0.0% 473902 B 0 B / +0.0% 5.689 s +6.988 ms / +0.1% (worse) 13.011 ms +113.4 us / +0.9% (worse)
Windows MinGW 386 fmtprintf-lto 4163072 B 0 B / +0.0% 452294 B 0 B / +0.0% 13.146 s +70.28 ms / +0.5% (worse) 13.180 ms -589.7 us / -4.3% (better)
Windows MinGW 386 println 681472 B 0 B / +0.0% 21694 B 0 B / +0.0% 1.660 s -5.404 ms / -0.3% (better) 9.125 ms -1.157 ms / -11.3% (better)
Windows MinGW 386 println-lto 260608 B 0 B / +0.0% 19514 B 0 B / +0.0% 1.965 s -33.84 ms / -1.7% (better) 9.278 ms +161.5 us / +1.8% (worse)
Windows MinGW ARM64 cprintf 686592 B 0 B / +0.0% 4204 B 0 B / +0.0% 1.764 s -177.6 ms / -9.1% (better) 5.875 ms -784 us / -11.8% (better)
Windows MinGW ARM64 cprintf-lto 44032 B 0 B / +0.0% 4156 B 0 B / +0.0% 1.800 s -181.7 ms / -9.2% (better) 6.092 ms -661.1 us / -9.8% (better)
Windows MinGW ARM64 fmtprintf 5384704 B +2560 B / +0.04756% (worse) 514300 B +240 B / +0.04669% (worse) 5.450 s -5.164 ms / -0.1% (better) 14.837 ms -681.7 us / -4.4% (better)
Windows MinGW ARM64 fmtprintf-lto 4328960 B +2048 B / +0.04733% (worse) 480352 B +232 B / +0.04832% (worse) 12.128 s +148.3 ms / +1.2% (worse) 15.057 ms +331 us / +2.2% (worse)
Windows MinGW ARM64 println 739840 B 0 B / +0.0% 23928 B 0 B / +0.0% 1.778 s -141.4 ms / -7.4% (better) 10.242 ms -1.242 ms / -10.8% (better)
Windows MinGW ARM64 println-lto 218112 B 0 B / +0.0% 21284 B 0 B / +0.0% 2.054 s -126.7 ms / -5.8% (better) 10.274 ms -390.1 us / -3.7% (better)
Windows MSVC cprintf 921088 B 0 B / +0.0% 66003 B 0 B / +0.0% 1.366 s +63.76 ms / +4.9% (worse) 3.440 ms -120.9 us / -3.4% (better)
Windows MSVC cprintf-lto 292352 B 0 B / +0.0% 65971 B 0 B / +0.0% 1.282 s -7.243 ms / -0.6% (better) 3.482 ms -115 us / -3.2% (better)
Windows MSVC fmtprintf 5777408 B +2560 B / +0.04433% (worse) 702118 B +224 B / +0.03191% (worse) 4.472 s -307.8 ms / -6.4% (better) 11.534 ms +1.533 ms / +15.3% (worse)
Windows MSVC fmtprintf-lto 4486656 B +2560 B / +0.1% (worse) 653062 B +256 B / +0.03922% (worse) 10.494 s +418.3 ms / +4.2% (worse) 12.876 ms +1.74 ms / +15.6% (worse)
Windows MSVC println 1044992 B 0 B / +0.0% 121334 B 0 B / +0.0% 1.283 s -12.65 ms / -1.0% (better) 6.956 ms -95.8 us / -1.4% (better)
Windows MSVC println-lto 531968 B +512 B / +0.1% (worse) 118870 B 0 B / +0.0% 1.485 s +20.38 ms / +1.4% (worse) 7.412 ms +57.7 us / +0.8% (worse)
Windows MSVC 386 cprintf 538624 B 0 B / +0.0% 3947 B 0 B / +0.0% 1.511 s +53.21 ms / +3.6% (worse) 5.759 ms -147.1 us / -2.5% (better)
Windows MSVC 386 cprintf-lto 44544 B 0 B / +0.0% 3901 B 0 B / +0.0% 1.541 s +64.92 ms / +4.4% (worse) 5.940 ms -354.4 us / -5.6% (better)
Windows MSVC 386 fmtprintf 4509696 B +1024 B / +0.02271% (worse) 457314 B 0 B / +0.0% 5.323 s +269.4 ms / +5.3% (worse) 13.641 ms +87.7 us / +0.6% (worse)
Windows MSVC 386 fmtprintf-lto 3910656 B 0 B / +0.0% 427681 B 0 B / +0.0% 11.802 s +59.32 ms / +0.5% (worse) 15.165 ms +1.212 ms / +8.7% (worse)
Windows MSVC 386 println 593920 B 0 B / +0.0% 20566 B 0 B / +0.0% 1.487 s +26.29 ms / +1.8% (worse) 9.478 ms -434.9 us / -4.4% (better)
Windows MSVC 386 println-lto 200192 B 0 B / +0.0% 18711 B 0 B / +0.0% 1.730 s +46.48 ms / +2.8% (worse) 9.740 ms -545.3 us / -5.3% (better)
Windows MSVC ARM64 cprintf 687616 B 0 B / +0.0% 4240 B 0 B / +0.0% 1.637 s +40.6 ms / +2.5% (worse) 6.720 ms +247.8 us / +3.8% (worse)
Windows MSVC ARM64 cprintf-lto 49152 B 0 B / +0.0% 4140 B 0 B / +0.0% 1.668 s +52.47 ms / +3.2% (worse) 6.566 ms +68 us / +1.0% (worse)
Windows MSVC ARM64 fmtprintf 5381120 B +2048 B / +0.03807% (worse) 514404 B +240 B / +0.04668% (worse) 5.096 s +101.2 ms / +2.0% (worse) 16.255 ms -137.9 us / -0.8% (better)
Windows MSVC ARM64 fmtprintf-lto 4336128 B +2048 B / +0.04725% (worse) 481184 B +224 B / +0.04657% (worse) 11.454 s -17.77 ms / -0.2% (better) 17.320 ms +882.9 us / +5.4% (worse)
Windows MSVC ARM64 println 741376 B 0 B / +0.0% 24200 B 0 B / +0.0% 1.646 s +70.24 ms / +4.5% (worse) 11.943 ms +847 us / +7.6% (worse)
Windows MSVC ARM64 println-lto 223232 B 0 B / +0.0% 21688 B 0 B / +0.0% 1.858 s +29.21 ms / +1.6% (worse) 12.360 ms +1.631 ms / +15.2% (worse)
Core language and compiler benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkLookupPCRandom 14.710 ns/op +0.02 ns/op / +0.1% (worse)
Linux BenchmarkMergeCompilerFlags 210.500 ns/op +4.6 ns/op / +2.2% (worse)
Linux BenchmarkMergeLinkerFlags 137.400 ns/op +0.8 ns/op / +0.6% (worse)
Linux BenchmarkChannelBuffered 56.650 ns/op +1.2 ns/op / +2.2% (worse)
Linux BenchmarkChannelHandoff 13357 ns/op +600 ns/op / +4.7% (worse)
Linux BenchmarkDefer 51.070 ns/op +2.69 ns/op / +5.6% (worse)
Linux BenchmarkDirectCall 1.164 ns/op 0 ns/op / +0.0%
Linux BenchmarkGlobalRead 1.939 ns/op +0.776 ns/op / +66.7% (worse)
Linux BenchmarkGlobalWrite 7.759 ns/op 0 ns/op / +0.0%
Linux BenchmarkGoroutine 26129 ns/op +310 ns/op / +1.2% (worse)
Linux BenchmarkInterfaceCall 5.819 ns/op -0.403 ns/op / -6.5% (better)
Linux BenchmarkRuntimeGetG 2.919 ns/op -0.094 ns/op / -3.1% (better)
macOS BenchmarkLookupPCRandom 13.210 ns/op -0.81 ns/op / -5.8% (better)
macOS BenchmarkMergeCompilerFlags 120.400 ns/op +5.8 ns/op / +5.1% (worse)
macOS BenchmarkMergeLinkerFlags 78.370 ns/op +7.97 ns/op / +11.3% (worse)
macOS BenchmarkChannelBuffered 25.890 ns/op -3.78 ns/op / -12.7% (better)
macOS BenchmarkChannelHandoff 9961 ns/op +1546 ns/op / +18.4% (worse)
macOS BenchmarkDefer 37.110 ns/op -2.22 ns/op / -5.6% (better)
macOS BenchmarkDirectCall 1.191 ns/op +0.043 ns/op / +3.7% (worse)
macOS BenchmarkGlobalRead 1.122 ns/op -0.022 ns/op / -1.9% (better)
macOS BenchmarkGlobalWrite 1.127 ns/op +0.036 ns/op / +3.3% (worse)
macOS BenchmarkGoroutine 63440 ns/op +23338 ns/op / +58.2% (worse)
macOS BenchmarkInterfaceCall 4.234 ns/op +0.082 ns/op / +2.0% (worse)
macOS BenchmarkRuntimeGetG 2.653 ns/op +0.454 ns/op / +20.6% (worse)
Windows MinGW BenchmarkLookupPCRandom 13.210 ns/op -0.35 ns/op / -2.6% (better)
Windows MinGW BenchmarkMergeCompilerFlags 634 ns/op -116.5 ns/op / -15.5% (better)
Windows MinGW BenchmarkMergeLinkerFlags 550.400 ns/op -161.4 ns/op / -22.7% (better)
Windows MinGW BenchmarkChannelBuffered 30.590 ns/op 0 ns/op / +0.0%
Windows MinGW BenchmarkChannelHandoff 1294 ns/op +56 ns/op / +4.5% (worse)
Windows MinGW BenchmarkDefer 59.350 ns/op +6.03 ns/op / +11.3% (worse)
Windows MinGW BenchmarkDirectCall 1.549 ns/op -0.004 ns/op / -0.3% (better)
Windows MinGW BenchmarkGlobalRead 1.550 ns/op +0.002 ns/op / +0.1% (worse)
Windows MinGW BenchmarkGlobalWrite 2.464 ns/op +0.001 ns/op / +0.0406% (worse)
Windows MinGW BenchmarkGoroutine 94659 ns/op +3498 ns/op / +3.8% (worse)
Windows MinGW BenchmarkInterfaceCall 8.686 ns/op -0.009 ns/op / -0.1% (better)
Windows MinGW BenchmarkRuntimeGetG 2.482 ns/op +0.622 ns/op / +33.4% (worse)
Windows MinGW 386 BenchmarkLookupPCRandom 26.500 ns/op -0.07 ns/op / -0.3% (better)
Windows MinGW 386 BenchmarkMergeCompilerFlags 769 ns/op +36 ns/op / +4.9% (worse)
Windows MinGW 386 BenchmarkMergeLinkerFlags 682 ns/op +1.8 ns/op / +0.3% (worse)
Windows MinGW 386 BenchmarkChannelBuffered 40.170 ns/op -0.04 ns/op / -0.1% (better)
Windows MinGW 386 BenchmarkChannelHandoff 818.600 ns/op -54.2 ns/op / -6.2% (better)
Windows MinGW 386 BenchmarkDefer 43.180 ns/op -0.58 ns/op / -1.3% (better)
Windows MinGW 386 BenchmarkDirectCall 1.550 ns/op -0.001 ns/op / -0.1% (better)
Windows MinGW 386 BenchmarkGlobalRead 1.552 ns/op -0.002 ns/op / -0.1% (better)
Windows MinGW 386 BenchmarkGlobalWrite 7.782 ns/op -0.003 ns/op / -0.03854% (better)
Windows MinGW 386 BenchmarkGoroutine 104754 ns/op -2859 ns/op / -2.7% (better)
Windows MinGW 386 BenchmarkInterfaceCall 8.406 ns/op +0.011 ns/op / +0.1% (worse)
Windows MinGW 386 BenchmarkRuntimeGetG 2.479 ns/op +0.001 ns/op / +0.04036% (worse)
Windows MinGW ARM64 BenchmarkLookupPCRandom 12.090 ns/op -0.07 ns/op / -0.6% (better)
Windows MinGW ARM64 BenchmarkMergeCompilerFlags 570.300 ns/op -5.9 ns/op / -1.0% (better)
Windows MinGW ARM64 BenchmarkMergeLinkerFlags 527.500 ns/op -17.2 ns/op / -3.2% (better)
Windows MinGW ARM64 BenchmarkChannelBuffered 38.350 ns/op +0.69 ns/op / +1.8% (worse)
Windows MinGW ARM64 BenchmarkChannelHandoff 5260 ns/op +1352 ns/op / +34.6% (worse)
Windows MinGW ARM64 BenchmarkDefer 53.870 ns/op -0.06 ns/op / -0.1% (better)
Windows MinGW ARM64 BenchmarkDirectCall 0.590 ns/op +0.0003 ns/op / +0.1% (worse)
Windows MinGW ARM64 BenchmarkGlobalRead 0.663 ns/op -0.0003 ns/op / -0.04521% (better)
Windows MinGW ARM64 BenchmarkGlobalWrite 0.663 ns/op +0.0002 ns/op / +0.03016% (worse)
Windows MinGW ARM64 BenchmarkGoroutine 60000 ns/op -1750 ns/op / -2.8% (better)
Windows MinGW ARM64 BenchmarkInterfaceCall 4.132 ns/op -0.106 ns/op / -2.5% (better)
Windows MinGW ARM64 BenchmarkRuntimeGetG 1.800 ns/op +0.022 ns/op / +1.2% (worse)
Windows MSVC BenchmarkLookupPCRandom 9.160 ns/op -0.171 ns/op / -1.8% (better)
Windows MSVC BenchmarkMergeCompilerFlags 451.200 ns/op +18.3 ns/op / +4.2% (worse)
Windows MSVC BenchmarkMergeLinkerFlags 402.400 ns/op +6 ns/op / +1.5% (worse)
Windows MSVC BenchmarkChannelBuffered 31.890 ns/op -1 ns/op / -3.0% (better)
Windows MSVC BenchmarkChannelHandoff 5148 ns/op -291 ns/op / -5.4% (better)
Windows MSVC BenchmarkDefer 54.420 ns/op -3.05 ns/op / -5.3% (better)
Windows MSVC BenchmarkDirectCall 0.291 ns/op -0.0312 ns/op / -9.7% (better)
Windows MSVC BenchmarkGlobalRead 0.371 ns/op +0.0036 ns/op / +1.0% (worse)
Windows MSVC BenchmarkGlobalWrite 8.046 ns/op -0.035 ns/op / -0.4% (better)
Windows MSVC BenchmarkGoroutine 72428 ns/op -55 ns/op / -0.1% (better)
Windows MSVC BenchmarkInterfaceCall 5.422 ns/op +0.435 ns/op / +8.7% (worse)
Windows MSVC BenchmarkRuntimeGetG 0.997 ns/op -0.03 ns/op / -2.9% (better)
Windows MSVC 386 BenchmarkLookupPCRandom 26.580 ns/op -0.04 ns/op / -0.2% (better)
Windows MSVC 386 BenchmarkMergeCompilerFlags 790.500 ns/op +25.1 ns/op / +3.3% (worse)
Windows MSVC 386 BenchmarkMergeLinkerFlags 707.500 ns/op +49.1 ns/op / +7.5% (worse)
Windows MSVC 386 BenchmarkChannelBuffered 38.920 ns/op +0.01 ns/op / +0.0257% (worse)
Windows MSVC 386 BenchmarkChannelHandoff 1004 ns/op -31 ns/op / -3.0% (better)
Windows MSVC 386 BenchmarkDefer 46.530 ns/op +0.62 ns/op / +1.4% (worse)
Windows MSVC 386 BenchmarkDirectCall 1.553 ns/op +0.003 ns/op / +0.2% (worse)
Windows MSVC 386 BenchmarkGlobalRead 1.550 ns/op +0.001 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkGlobalWrite 7.779 ns/op +0.005 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkGoroutine 110125 ns/op +818 ns/op / +0.7% (worse)
Windows MSVC 386 BenchmarkInterfaceCall 8.146 ns/op -0.015 ns/op / -0.2% (better)
Windows MSVC 386 BenchmarkRuntimeGetG 2.481 ns/op +0.002 ns/op / +0.1% (worse)
Windows MSVC ARM64 BenchmarkLookupPCRandom 12.180 ns/op +0.09 ns/op / +0.7% (worse)
Windows MSVC ARM64 BenchmarkMergeCompilerFlags 574 ns/op -5.9 ns/op / -1.0% (better)
Windows MSVC ARM64 BenchmarkMergeLinkerFlags 544.100 ns/op +4.2 ns/op / +0.8% (worse)
Windows MSVC ARM64 BenchmarkChannelBuffered 37.190 ns/op +0.11 ns/op / +0.3% (worse)
Windows MSVC ARM64 BenchmarkChannelHandoff 2732 ns/op +442 ns/op / +19.3% (worse)
Windows MSVC ARM64 BenchmarkDefer 61.640 ns/op -0.8 ns/op / -1.3% (better)
Windows MSVC ARM64 BenchmarkDirectCall 0.590 ns/op -0.0002 ns/op / -0.03391% (better)
Windows MSVC ARM64 BenchmarkGlobalRead 0.590 ns/op +0.0001 ns/op / +0.01696% (worse)
Windows MSVC ARM64 BenchmarkGlobalWrite 3.755 ns/op -0.004 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkGoroutine 56902 ns/op -2133 ns/op / -3.6% (better)
Windows MSVC ARM64 BenchmarkInterfaceCall 4.232 ns/op +0.095 ns/op / +2.3% (worse)
Windows MSVC ARM64 BenchmarkRuntimeGetG 1.769 ns/op +0.001 ns/op / +0.1% (worse)
Timer runtime benchmarks
Platform Operation and runtime ns/op vs base
Linux AfterFuncZeroDelivery/Go 913 ns/op +9.6 ns/op / +1.1% (worse)
Linux AfterFuncZeroDelivery/LLGo 37777 ns/op -2786 ns/op / -6.9% (better)
Linux CreateStop/Go 301.100 ns/op -0.9 ns/op / -0.3% (better)
Linux CreateStop/LLGo 1959 ns/op +4 ns/op / +0.2% (worse)
Linux RearmStopped/Go 116.100 ns/op +0.3 ns/op / +0.3% (worse)
Linux RearmStopped/LLGo 1262 ns/op +67 ns/op / +5.6% (worse)
Linux ResetActive/Go 68.750 ns/op +0.19 ns/op / +0.3% (worse)
Linux ResetActive/LLGo 778.700 ns/op -216 ns/op / -21.7% (better)
Linux ResetHeap1024/Go 67.080 ns/op +0.09 ns/op / +0.1% (worse)
Linux ResetHeap1024/LLGo 164.100 ns/op +3.6 ns/op / +2.2% (worse)
macOS AfterFuncZeroDelivery/Go 489.400 ns/op +37.3 ns/op / +8.3% (worse)
macOS AfterFuncZeroDelivery/LLGo 35981 ns/op +1230 ns/op / +3.5% (worse)
macOS CreateStop/Go 149.200 ns/op -16.8 ns/op / -10.1% (better)
macOS CreateStop/LLGo 440.700 ns/op -80.3 ns/op / -15.4% (better)
macOS RearmStopped/Go 60.330 ns/op -0.4 ns/op / -0.7% (better)
macOS RearmStopped/LLGo 275.500 ns/op -15.7 ns/op / -5.4% (better)
macOS ResetActive/Go 44.320 ns/op +0.22 ns/op / +0.5% (worse)
macOS ResetActive/LLGo 126.400 ns/op -17.6 ns/op / -12.2% (better)
macOS ResetHeap1024/Go 44.050 ns/op -0.67 ns/op / -1.5% (better)
macOS ResetHeap1024/LLGo 79.390 ns/op -8.28 ns/op / -9.4% (better)
Windows MinGW AfterFuncZeroDelivery/Go 547.200 ns/op -63.3 ns/op / -10.4% (better)
Windows MinGW AfterFuncZeroDelivery/LLGo 184477 ns/op -3462 ns/op / -1.8% (better)
Windows MinGW CreateStop/Go 122.500 ns/op +1.9 ns/op / +1.6% (worse)
Windows MinGW CreateStop/LLGo 488.800 ns/op -72 ns/op / -12.8% (better)
Windows MinGW RearmStopped/Go 31.620 ns/op -0.87 ns/op / -2.7% (better)
Windows MinGW RearmStopped/LLGo 235.700 ns/op -70 ns/op / -22.9% (better)
Windows MinGW ResetActive/Go 20.140 ns/op -1.38 ns/op / -6.4% (better)
Windows MinGW ResetActive/LLGo 140.700 ns/op -140 ns/op / -49.9% (better)
Windows MinGW ResetHeap1024/Go 20.440 ns/op -0.4 ns/op / -1.9% (better)
Windows MinGW ResetHeap1024/LLGo 119.700 ns/op +3.9 ns/op / +3.4% (worse)
Windows MinGW 386 AfterFuncZeroDelivery/Go 982.200 ns/op +7.5 ns/op / +0.8% (worse)
Windows MinGW 386 AfterFuncZeroDelivery/LLGo 204384 ns/op +2028 ns/op / +1.0% (worse)
Windows MinGW 386 CreateStop/Go 192.400 ns/op -0.6 ns/op / -0.3% (better)
Windows MinGW 386 CreateStop/LLGo 492.700 ns/op +15 ns/op / +3.1% (worse)
Windows MinGW 386 RearmStopped/Go 63.290 ns/op -0.39 ns/op / -0.6% (better)
Windows MinGW 386 RearmStopped/LLGo 324.500 ns/op +14.5 ns/op / +4.7% (worse)
Windows MinGW 386 ResetActive/Go 39.110 ns/op -0.01 ns/op / -0.02556% (better)
Windows MinGW 386 ResetActive/LLGo 974.300 ns/op +1.9 ns/op / +0.2% (worse)
Windows MinGW 386 ResetHeap1024/Go 39.380 ns/op -0.02 ns/op / -0.1% (better)
Windows MinGW 386 ResetHeap1024/LLGo 178 ns/op +3.9 ns/op / +2.2% (worse)
Windows MinGW ARM64 AfterFuncZeroDelivery/Go 674.300 ns/op +4.7 ns/op / +0.7% (worse)
Windows MinGW ARM64 AfterFuncZeroDelivery/LLGo 148898 ns/op +411 ns/op / +0.3% (worse)
Windows MinGW ARM64 CreateStop/Go 197.300 ns/op 0 ns/op / +0.0%
Windows MinGW ARM64 CreateStop/LLGo 345.900 ns/op +29.5 ns/op / +9.3% (worse)
Windows MinGW ARM64 RearmStopped/Go 70.610 ns/op +0.04 ns/op / +0.1% (worse)
Windows MinGW ARM64 RearmStopped/LLGo 208.900 ns/op -0.7 ns/op / -0.3% (better)
Windows MinGW ARM64 ResetActive/Go 31.240 ns/op +0.26 ns/op / +0.8% (worse)
Windows MinGW ARM64 ResetActive/LLGo 103.400 ns/op -19.4 ns/op / -15.8% (better)
Windows MinGW ARM64 ResetHeap1024/Go 31.090 ns/op +0.02 ns/op / +0.1% (worse)
Windows MinGW ARM64 ResetHeap1024/LLGo 112.800 ns/op -0.7 ns/op / -0.6% (better)
Windows MSVC AfterFuncZeroDelivery/Go 526.700 ns/op -27.7 ns/op / -5.0% (better)
Windows MSVC AfterFuncZeroDelivery/LLGo 154864 ns/op +18996 ns/op / +14.0% (worse)
Windows MSVC CreateStop/Go 150.800 ns/op -0.2 ns/op / -0.1% (better)
Windows MSVC CreateStop/LLGo 815.500 ns/op -50.6 ns/op / -5.8% (better)
Windows MSVC RearmStopped/Go 55.980 ns/op -1.54 ns/op / -2.7% (better)
Windows MSVC RearmStopped/LLGo 237.900 ns/op +14.7 ns/op / +6.6% (worse)
Windows MSVC ResetActive/Go 24.980 ns/op -0.23 ns/op / -0.9% (better)
Windows MSVC ResetActive/LLGo 271.500 ns/op -15.4 ns/op / -5.4% (better)
Windows MSVC ResetHeap1024/Go 24.980 ns/op -0.7 ns/op / -2.7% (better)
Windows MSVC ResetHeap1024/LLGo 90.880 ns/op -2.56 ns/op / -2.7% (better)
Windows MSVC 386 AfterFuncZeroDelivery/Go 961.300 ns/op -5.4 ns/op / -0.6% (better)
Windows MSVC 386 AfterFuncZeroDelivery/LLGo 203524 ns/op +271 ns/op / +0.1% (worse)
Windows MSVC 386 CreateStop/Go 195.100 ns/op +3.9 ns/op / +2.0% (worse)
Windows MSVC 386 CreateStop/LLGo 436.900 ns/op -8.9 ns/op / -2.0% (better)
Windows MSVC 386 RearmStopped/Go 63.500 ns/op +0.23 ns/op / +0.4% (worse)
Windows MSVC 386 RearmStopped/LLGo 327.800 ns/op +25.5 ns/op / +8.4% (worse)
Windows MSVC 386 ResetActive/Go 39.100 ns/op +0.1 ns/op / +0.3% (worse)
Windows MSVC 386 ResetActive/LLGo 914.100 ns/op -44.3 ns/op / -4.6% (better)
Windows MSVC 386 ResetHeap1024/Go 39.650 ns/op +0.17 ns/op / +0.4% (worse)
Windows MSVC 386 ResetHeap1024/LLGo 161.100 ns/op +0.6 ns/op / +0.4% (worse)
Windows MSVC ARM64 AfterFuncZeroDelivery/Go 667.300 ns/op -4.5 ns/op / -0.7% (better)
Windows MSVC ARM64 AfterFuncZeroDelivery/LLGo 146998 ns/op -901 ns/op / -0.6% (better)
Windows MSVC ARM64 CreateStop/Go 199.700 ns/op +0.1 ns/op / +0.1% (worse)
Windows MSVC ARM64 CreateStop/LLGo 344.600 ns/op -9 ns/op / -2.5% (better)
Windows MSVC ARM64 RearmStopped/Go 70.380 ns/op -0.17 ns/op / -0.2% (better)
Windows MSVC ARM64 RearmStopped/LLGo 226.800 ns/op -0.8 ns/op / -0.4% (better)
Windows MSVC ARM64 ResetActive/Go 31.340 ns/op +0.26 ns/op / +0.8% (worse)
Windows MSVC ARM64 ResetActive/LLGo 115 ns/op +2.2 ns/op / +2.0% (worse)
Windows MSVC ARM64 ResetHeap1024/Go 31.880 ns/op +0.84 ns/op / +2.7% (worse)
Windows MSVC ARM64 ResetHeap1024/LLGo 117 ns/op -0.5 ns/op / -0.4% (better)

Compared with 53a91b998e81 measured in the same runner job.

@github-actions

Copy link
Copy Markdown

LLGo WebAssembly build benchmarks

259c0194dc3f | workflow run | long-term charts

WebAssembly output sizes
Example, profile and compiler Wasm module vs base Generated JS glue vs base
cprintf/j32-emscripten/LLGo 147058 B 0 B / +0.0% 88541 B 0 B / +0.0%
cprintf/j32-goos-js/LLGo 145666 B 0 B / +0.0% 72985 B 0 B / +0.0%
cprintf/j64-emscripten-memory64/LLGo 134527 B 0 B / +0.0% 91712 B 0 B / +0.0%
cprintf/w32-goos-wasip1/LLGo 156385 B 0 B / +0.0% 0 B 0 B / 0.0%
cprintf/w32-wasi/LLGo 157083 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/j32-emscripten/LLGo 2984092 B +113 B / +0.003787% (worse) 120989 B 0 B / +0.0%
fmtprintf/j32-goos-js/Go 2526852 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/j32-goos-js/LLGo 3074847 B +99 B / +0.00322% (worse) 92052 B 0 B / +0.0%
fmtprintf/j64-emscripten-memory64/LLGo 2748629 B -208 B / -0.007567% (better) 125530 B 0 B / +0.0%
fmtprintf/w32-goos-wasip1/Go 2500019 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/w32-goos-wasip1/LLGo 2343698 B +96 B / +0.004096% (worse) 0 B 0 B / 0.0%
fmtprintf/w32-wasi/LLGo 2340394 B +96 B / +0.004102% (worse) 0 B 0 B / 0.0%
j32-emscripten/LLGo 146575 B 0 B / +0.0% 88541 B 0 B / +0.0%
j32-goos-js/Go 1895533 B 0 B / +0.0% 0 B 0 B / 0.0%
j32-goos-js/LLGo 145416 B 0 B / +0.0% 72985 B 0 B / +0.0%
j64-emscripten-memory64/LLGo 134082 B 0 B / +0.0% 91712 B 0 B / +0.0%
reflectcall/j32-emscripten/LLGo 1510238 B +104 B / +0.006887% (worse) 95329 B 0 B / +0.0%
reflectcall/j32-goos-js/Go 2191221 B 0 B / +0.0% 0 B 0 B / 0.0%
reflectcall/j32-goos-js/LLGo 1562407 B +106 B / +0.006785% (worse) 79769 B 0 B / +0.0%
reflectcall/j64-emscripten-memory64/LLGo 1391380 B +121 B / +0.008697% (worse) 99026 B 0 B / +0.0%
reflectcall/w32-goos-wasip1/Go 2205707 B 0 B / +0.0% 0 B 0 B / 0.0%
reflectcall/w32-goos-wasip1/LLGo 1273885 B +96 B / +0.007537% (worse) 0 B 0 B / 0.0%
reflectcall/w32-wasi/LLGo 1271526 B +96 B / +0.007551% (worse) 0 B 0 B / 0.0%
w32-goos-wasip1/Go 1909947 B 0 B / +0.0% 0 B 0 B / 0.0%
w32-goos-wasip1/LLGo 156059 B 0 B / +0.0% 0 B 0 B / 0.0%
w32-wasi/LLGo 156757 B 0 B / +0.0% 0 B 0 B / 0.0%
LLGo WebAssembly build measurements
Example and profile Build vs base
j32-emscripten 7.259 s +152.2 ms / +2.1% (worse)
j32-goos-js 7.078 s -17.21 ms / -0.2% (better)
j64-emscripten-memory64 6.231 s -40.65 ms / -0.6% (better)
reflectcall/w32-wasi 23.407 s +145.7 ms / +0.6% (worse)
w32-goos-wasip1 4.401 s +14.05 ms / +0.3% (worse)
w32-wasi 4.183 s +28.78 ms / +0.7% (worse)

Compared with 0a2ebb890b83 measured in the same runner job.

@MeteorsLiu
MeteorsLiu requested a review from cpunion October 19, 2026 01:51
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.

Missing trailing-zero-field padding corrupts reflection reads, writes and copies

1 participant