Skip to content

plan9asm: fix ARM64 native JIT entry and resume - #3046

Merged
cpunion merged 6 commits into
xgo-dev:mainfrom
cpunion:fix/2921-arm64-native-tail-bridge
Nov 12, 2026
Merged

cpunion merged 6 commits into
xgo-dev:mainfrom
cpunion:fix/2921-arm64-native-tail-bridge

Conversation

@cpunion

@cpunion cpunion commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2921.

Preserve ARM64 registers and SP/FP/LR across native JIT entry and resume, using a declaration-checked ABI0 bridge on Darwin/Linux. Keep its physical asm out of LTO inlining. BDWGC builds use GC_do_blocking so concurrent GC scans the saved native stack instead of the guest stack; nogc adds no collector dependency.

Supported entries: up to eight word/pointer arguments, no results, NOSPLIT|NOFRAME. Foreign code must restore SP/FP and return before managed Go calls/allocations.

Validated against Go with the original 38-byte wazero guest, host-call resume, reentry, stack/memory growth, traps, multiple values and concurrent GC, including full LTO. Existing-suite probes cover GP/SIMD preservation, a deterministic GC/guest-stack handshake, plain/full-LTO/nogc builds, and ELF/Mach-O object emission. Generated Linux/arm64 bridge code also passes the physical ABI probe under QEMU.

CI: retain official HTTPS mirror fallback in the existing Ubuntu setup helper after repeated archive TLS failures; no new jobs.

@cpunion

cpunion commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

@fennoai Please review this ARM64 physical ABI fix for #2921. The original wazero guest and extended entry/resume/reentry/stack-growth/trap scenarios pass; the checked-in native probe covers stack switching and GP/SIMD preservation with and without full LTO.

@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: ARM64 native tail-transfer lowering

Focused, well-scoped change that introduces lowerNativeTailTransfers to preserve the physical ARM64 ABI across indirect assembly tail transfers, wired into TranslateSourceModuleForPkgWithOptions. The design is carefully reasoned, the guard matrix is comprehensive, and the test coverage is strong — unit tests for both darwin/linux, a thorough negative-path ABI-rejection matrix, and an integration test that exercises LTO Off/Full with a C register-preservation probe. Nice work.

I verified the +8 LR-reservation offset math against the test expectations (MOVD target+0(FP) → ldr x27, [sp, #8]), the argc > 8 cap keeping x18 out of the input range, and the function-replacement sequence. No blocking issues found. The findings below are correctness-hardening and clarity suggestions.

Design notes (not inline, for discussion):

  • FP (x29) preservation is contract-only, not enforced. x29 is intentionally omitted from the clobber list so the guest must preserve it. This matches the documented contract and the probe fixture, but a guest .s that clobbers x29 without restoring it would corrupt the frame pointer LLVM relies on, with no guard rejecting it. Consider noting this as an explicit precondition (or validating it) given the bridge accepts developer-authored assembly.
  • Only the terminal indirect branch is validated. hasIndirectTailTransfer scans all instructions, but the register-bounds / x18 / transfer guards apply only to fn.Instrs[len-1]. A mid-body indirect branch is forwarded verbatim through TranslateNativeSource. Rejecting non-terminal indirect branches explicitly would make the "indivisible region" invariant self-enforcing.
  • Reserved generated-label namespace is unguarded. A guest label literally named Lnative_func_0 or Ltail_done would collide with the names this pass reserves; the failure mode is a broken/ambiguous assemble rather than silent miscompilation, but it is unvalidated.

Comment thread internal/plan9asm/native_tail.go Resolved
Comment thread internal/plan9asm/native_tail.go Resolved
Comment thread internal/plan9asm/native_tail.go Resolved
Comment thread internal/plan9asm/native_tail.go Resolved
Comment thread internal/plan9asm/native_tail.go Resolved
@fennoai

fennoai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Workspace is confirmed at the same head SHA. The diff is unchanged from the review I just completed. In managed mode, I return the review as my final message without publishing a comment, spinner, or completion marker.


Review: ARM64 physical ABI fix for #2921

Thanks for the context on the test scenarios — the native probe covering stack switching plus GP/SIMD preservation with and without full LTO is exactly the kind of coverage this boundary needs. I reviewed the full diff (717fbe4...23f26b5, 8 files, +514) across code quality, performance, security/correctness, and documentation accuracy.

Overall: focused, well-reasoned change. lowerNativeTailTransfers keeps a normal LLVM entry/epilogue around one indivisible native asm region, wired into TranslateSourceModuleForPkgWithOptions. The guard matrix and negative-path test matrix are thorough, and I verified the +8 LR-reservation offset math against the test expectations (MOVD target+0(FP) → ldr x27, [sp, #8]), the argc > 8 cap keeping x18 out of the input/output range, and the noinline + bl/br continuation reasoning. No blocking issues. Findings are correctness-hardening and clarity.

Findings

1. native_tail.go:67 — tail-register bound admits x29/x30 (correctness, worth tightening)
reg > 30 || reg == 18 accepts R29 (FP) and R30 (LR). For a terminal JMP (R30), the emitted br x30 runs after the bl Lnative_func_0${:uid} prefix (line 214) has overwritten LR, so it would branch to the continuation's return address rather than the intended target — a latent miscompile. R29 is similarly special. The clobber loop at line 195 already treats the valid GP range as x0–x28 (minus x18); tightening the branch target to reg > 28 would match it. (If x29/x30 targets are intentionally supported, a comment would help.)

2. native_tail.go:74 — brittle TEXT-flag parse + duplicated error (quality)
strings.Split(fn.Instrs[0].Raw, ",") with len == 3 is positional parsing of the raw directive, and the "requires NOSPLIT|NOFRAME" error at line 76 (malformed/wrong field count) is reused at line 87 for a genuinely different cause (an unrecognized flag). If the parsed asm.Func exposes structured flags (it already surfaces FrameSize/ArgSize), prefer those; otherwise split the two messages for clearer diagnosis.

3. native_tail.go:25 — redundant full re-parse (perf, low)
asm.Parse(asm.ArchARM64, string(src)) re-parses source that TranslateGoModule just parsed at translate.go:119, plus a string(src) whole-buffer copy. Low severity for small build-time .s inputs, but this pass can also be re-entered by the global-init pruning analysis, which amplifies it. If tr can expose the already-parsed asm.File/functions, threading it through removes the duplicate work.

4. native_tail.go:193 — comment inaccuracy (docs)
"Exclude Darwin's reserved x18" — the if i != 18 skip is unconditional and applies on both linux and darwin (no goos guard; the unit test exercises both), so the comment could mislead a reader into thinking x18 is clobbered on Linux. Also "which the guest must restore before returning" fits FP/SP but not x18 (x18 is simply left untouched, not saved/restored). Suggest separating: x18 = reserved, never clobbered on any target; FP/SP = guest-restored.

5. native_tail.go:149 — sentinel collision (hardening, minor)
The uniquifier injects plain ___tail_uid__ then ReplaceAlls it to ${:uid} across the (guest-derived) body. Go asm allows underscores in identifiers, so a guest label containing that token would be rewritten into an unintended substitution. Unlike the $→$$ escaping on line 145, this isn't collision-proof — a non-representable sentinel (or tagging labels during emission) would close it; at minimum, a comment noting the required ordering of the two substitutions.

Design notes (for discussion, not defects)

  • FP (x29) preservation is contract-only, not enforced. x29 is deliberately omitted from the clobber list so the guest must preserve it — consistent with the probe fixture and your trap/reentry scenarios — but no guard rejects a guest .s that clobbers x29 without restoring it. Given the bridge consumes developer-authored assembly, consider making this an explicit, documented precondition (or validating it).
  • Only the terminal indirect branch is validated. hasIndirectTailTransfer scans all instructions, but the register-bounds/x18/transfer guards apply only to fn.Instrs[len-1]; a mid-body indirect branch is forwarded verbatim. Rejecting non-terminal indirect branches would make the "indivisible region" invariant self-enforcing.
  • Reserved generated-label namespace is unguarded. A guest label literally named Lnative_func_0 or Ltail_done collides with names this pass reserves; the failure mode is a broken/ambiguous assemble rather than silent miscompilation, but it's unvalidated.

Test coverage is a real strength here — the dual-LTO integration run plus the C register-preservation probe give good confidence in the physical-ABI contract. None of the above needs to block; items 1 and 4 are the two I'd most recommend addressing.

View session

@cpunion

cpunion commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

@fennoai Updated in de98c01. Addressed the inline findings; also documented the guest FP/SP contract, explicitly reject non-terminal indirect transfers, and test that source labels using the generated names are safely normalized. Unit/object tests and native probes with/without full LTO pass. Please re-review.

@fennoai

fennoai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

This clarifies things. The Flags field I found earlier is on GloblStmt (DATA/GLOBL directives), not on Func for TEXT. The Func struct (parser.go:25) does not carry a parsed TEXT flags field — it only has Sym, FrameSize, ArgSize, and Instrs. And nativeFlags in native_source.go is an internal (lowercase) helper, not exported.

So the PR's raw-TEXT reparse for flags (strings.Split(fn.Instrs[0].Raw, ",")) is in fact the only available way to get the flags — the structured field does not exist on Func. This fully resolves my original Finding 2: the positional parse is justified, and the PR's fix (distinct error message) is the correct and complete response. My earlier suggestion to "use structured flags if available" was speculative and the premise doesn't hold.

I now have everything I need to deliver an accurate re-review. The changes are confirmed on disk; the environment can't build (missing LLVM headers) but the author reports the test suite and native probes pass, and the test diffs show strong new coverage for every fix. Let me deliver the re-review as my final message (managed mode — no publishing).


Re-review: de98c010f — "tighten physical tail-transfer boundaries"

I re-checked out the PR at the new head and diffed 23f26b5..de98c01. The update touches only native_tail.go (+27/-11) and its unit test (+72/-31), and every one of my prior findings is addressed. I also confirmed the one behavior-changing fix (x18 on Linux) against the project's own ABI handling. Looks good.

Findings — all resolved

# Prior finding Resolution Verdict
1 Tail register bound admitted x29/x30 reg > 30 → reg > 28 (line 73); new TestNativeTailTransferRejectsSpecialTargetRegisters asserts R18/R29/R30 are rejected with unsupported tail register ✅ Fixed
2 Duplicated "requires NOSPLIT|NOFRAME" error for two causes Malformed-directive path now returns malformed TEXT directive: %s (line 82), distinct from the flag-validation message ✅ Fixed
3 Redundant full re-parse of src Kept, now justified by a comment (lines 23–24). I confirmed against plan9asm@v0.6.2 that asm.Func exposes no parsed flags/File — only Sym/FrameSize/ArgSize/Instrs — so reparsing really is the only option. My original "use structured flags" premise doesn't hold; this is the right call. ✅ Acknowledged, correctly
4 "Darwin's reserved x18" comment was inaccurate Fixed as a behavior change, not just wording: if i != 18 || goos != "darwin" now clobbers x18 on Linux and excludes it only on Darwin, with a matching comment (lines 200–206). New assertion ~{x18} present iff goos == "linux". ✅ Fixed
5 Plain ___tail_uid__ sentinel could collide with guest labels Replaced the two-step sentinel with ReplaceAllStringFunc appending ${:uid} directly (lines 154–156), eliminating the collision class. TestNativeTailTransferControlFlow now parametrizes over transfer___tail_uid__, Lnative_func_0, Ltail_done and asserts no ___tail_uid__ leaks and labels are uniquified. ✅ Fixed

Design notes — all addressed

  • FP/SP preservation contract is now documented at the function header (line 21: "Guest code must restore the entry FP/SP before returning through the saved LR").
  • Non-terminal indirect transfers are now explicitly rejected: hasIndirectTailTransfer(fn.Instrs[:len-1]) → "requires a single terminal indirect branch" (lines 65–67), covered by the new multiple transfers reject case.
  • Reserved-label normalization is now directly tested (the control-flow test feeds source labels named exactly like the generated families and verifies they're safely uniquified).

Verifying the x18-on-Linux change

This is the only semantic change, so I checked it specifically. ssa/closure_abi.go:56 in this same repo states "Apple, Android, and Windows reserve X18" — Linux userspace does not reserve it (AAPCS64 platform register, free on Linux). So treating x18 as guest-clobberable on Linux and reserved only on Darwin is correct and consistent with LLGo's existing ABI model. The new iff-assertion locks this in.

Note on local verification

I couldn't compile/run the suite here — this sandbox lacks the LLVM C headers (llvm-c/Core.h), which the plan9asm/llvm bindings require — so I verified by reading the diff, the new test assertions, and the external package's actual API. I'm relying on your report that the unit/object tests and the native probes (with and without full LTO) pass; the test changes themselves look well-targeted to each fix.

Verdict: All prior findings resolved cleanly, with a test added for each. No new issues. LGTM from my side.

View task

@codecov

codecov Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.33333% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/plan9asm/native_tail.go 97.19% 6 Missing ⚠️

📢 Thoughts on this report? Let us know!

@cpunion

cpunion commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

@fennoai Added a follow-up fix after an extended concurrent-GC test exposed BDWGC scanning the guest heap stack as a pthread stack. The new collector transition keeps arguments rooted on the saved native stack and runs the foreign region through GC_do_blocking. Added a deterministic entered/GC/release handshake, full-LTO/nogc runtime probes, collector-selection and DATA-entry tests; all pass, as do the extended wazero cases. Please re-review the latest commit.

@fennoai

fennoai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

The probe is well-constructed: gc_guest switches to the guest heap stack (mov sp, x26), signals "entered" via a release store (stlr), spin-waits on the release flag (ldar/cbz), and only then runs GUEST_BODY. The Go side forces runtime.GC() in that window. This deterministically exercises BDWGC scanning while the native thread is on the switched stack — exactly the race the fix addresses. The acquire/release flags use context[5]/context[6] (hence the array grew from [5] to [7]). The handshake is correct and deterministic.

I now have a complete, verified understanding of the follow-up. The environment can't build (missing LLVM headers, as before), but every change is well-covered by new tests and the author reports full-LTO/nogc runtime probes pass. Let me deliver the re-review as my final message (managed mode — no publishing).


Re-review: 811e9e24b — "protect foreign guest stacks during concurrent BDWGC"

I re-checked out at the new head and diffed de98c01..811e9e2. This is a substantive follow-up addressing the concurrent-GC issue the extended test exposed: BDWGC was scanning the interval from the guest heap stack up to the pthread stack top instead of the real Go stack. The fix wraps the native entry so the foreign region runs under GC_do_blocking, with arguments rooted in the live caller frame. I traced the IR-construction logic and cross-checked it against LLGo's existing BDWGC usage. It holds together well.

What the follow-up does

  • wrapNativeTailBDWGC (native_tail.go:51-100) renames the physical function to …$native (internal), creates a public wrapper under the original name, ReplaceAllUsesWith redirects existing references (crucially, any DATA $·Enter(SB) function-address initializer) to the wrapper, spills the args into a caller-frame alloca struct, and calls GC_do_blocking(callback, data); the internal callback reloads the args and calls …$native.
  • Gating (plan9asm.go:18-24): NativeBDWGC is enabled only for arm64 darwin/linux and disabled under nogc/baremetal, checking both conf.Tags and the cross-target targetTags — a good addition for cross-compilation correctness.
  • Plumbed through TranslateOptions.NativeBDWGC at all three call sites (compile, sig-collection, unused-global-init).

Correctness checks I ran

  • GC_do_blocking signature matches. The generated ptr GC_do_blocking(ptr, ptr) with callback ptr(ptr) exactly matches LLGo's own declaration (runtime/internal/clite/bdwgc/_wrap/blocking_unix.c:3: void *GC_do_blocking(void *(*fn)(void *), void *data)). ✅
  • No recursion / correct target binding. callback's CreateCall(native, …) is built after ReplaceAllUsesWith(entry), so it binds the renamed …$native, not the wrapper. ✅
  • Function-address path goes through the transition. Because the rename precedes ReplaceAllUsesWith, a DATA ·entryAddr(SB)/8, $·Enter(SB) initializer is rewritten to the public wrapper — TestNativeTailTransferBDWGC asserts exactly this (initializer must not contain $native). ✅
  • Physical boundary still protected. …$native retains the noinline + full clobber contract from the first-stage lowering; the GC wrapper sits outside it. ✅
  • Args stay scannable. The alloca struct lives in the wrapper's frame (above the saved SP captured by GC_do_blocking), so BDWGC scans the rooted copies — the stated intent. ✅

Test coverage (strong)

  • TestNativeTailTransferBDWGC (darwin/linux): verifies the public entry routes through @GC_do_blocking and the DATA entry references the wrapper.
  • TestNativeTailTransfer: new negative assertion that collector-free translation acquires no BDWGC dependency.
  • TestPlan9AsmNativeCollectorSelection: full gating matrix incl. nogc/baremetal/arch/targetTags.
  • Integration test: adds a nogc build mode and a deterministic concurrent-GC handshake — gc_guest switches to the guest stack, release-stores "entered", spin-waits on release; the Go side forces runtime.GC() in that window (main.go:59-72, probe.c acquire/release helpers). This directly reproduces the race the fix targets.

One minor observation (non-blocking)

wrapNativeTailBDWGC copies visibility/linkage/callconv onto the public wrapper but, unlike the first-stage lowerNativeTailTransfer (which propagated attributes via for i := -1; i <= argc), it does not copy the original entry's parameter/return attributes onto the new public entry. For the current scalar/pointer-word signatures these attributes are optimization hints and dropping them is benign, but if a future signature carried an ABI-affecting param attribute it would silently not reach the public symbol. Worth a one-line note or mirroring the attribute-copy loop if you want the wrapper to be attribute-faithful. Not required for this PR.

Note on local verification

As in prior rounds, I couldn't build/run here — the sandbox lacks the LLVM C headers (llvm-c/Core.h) the bindings require — so I verified by reading the diff, the generated-IR construction, the new test assertions, and LLGo's existing BDWGC declarations. I'm relying on your report that the full-LTO/nogc runtime probes, the entered/GC/release handshake, the collector-selection/DATA-entry tests, and the extended wazero cases all pass.

Verdict: The GC-transition design is sound, correctly gated, and backed by a deterministic concurrent-GC test. No blocking issues; the only note is the optional parameter-attribute propagation on the wrapper. LGTM.

View task

@cpunion

cpunion commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

@fennoai Addressed the optional attribute note: public entry and private forwarding call now preserve return/parameter attributes and the calling convention, while function-effect attributes remain conservative. Also made the pass honor Go-binder filtering of runtime-provided TEXT bodies and added argument-limit/rejection tests. Local package coverage is 97.3%; native GC/full-LTO/nogc probes pass. Please re-review the latest update.

@fennoai

fennoai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Confirmed: the external plan9asm package's native_source.go:201 has nativePseudoRegister matching R18/R18_PLATFORM (among SP/FP/g/R31), so TranslateNativeSource rejects R18 in the body. So the reserved body register test case (MOVD R18, R5) is genuinely rejected by the downstream emitter — the test is valid and will pass.

I've now verified:

  • Change 1 (binder filter): correct and well-tested; skips cleanly when the typed LLVM entry is absent/a declaration. Note this entry local shadows nothing problematic — lowerNativeTailTransfer re-looks-up sig.Name internally. One tiny observation: the sig lookup (which returns a "missing Go declaration" error when absent) now runs after the entry-existence check, so a filtered body short-circuits before the sig check — that's the intended behavior.
  • Change 2 (attribute forwarding): correctly forwards return+param attributes and callconv to both the public entry and the forwarding call-site, keeps function-effects conservative, and preserves the noinline boundary on $native. Directly validated by the new test.

Everything checks out. The environment still can't build (missing LLVM headers), but the author reports 97.3% package coverage and passing native GC/full-LTO/nogc probes, and the new tests precisely cover both changes. Let me deliver the re-review as my final message (managed mode — no publishing).


Re-review: b3f5e8e87 — "preserve forwarding attributes and cover native ABI limits"

Re-checked out at the new head and diffed 811e9e2..b3f5e8e. Small, focused follow-up (native_tail.go +17, test +81) that resolves my prior optional note and adds robustness for runtime-filtered TEXT bodies. Both changes are correct and precisely tested.

Change 1 — attribute/callconv forwarding (resolves my prior note)

The callback's forwarding call now sets the call-site calling convention from native and copies return (index 0) and parameter (indices 1..N) attributes onto both the public entry and the forwarding call-site, deliberately skipping function-effect attributes (index −1) because GC_do_blocking changes the function's effects. The loop for i := 0; i <= len(params) is exactly "return + parameters, not function effects" — the right boundary.

I confirmed the provenance is faithful: native's return/param attributes were themselves copied from the original Go-typed declaration during first-stage lowering, so forwarding them to the public wrapper preserves the real ABI contract. The noinline physical boundary correctly stays on $native and is not propagated to the wrapper. TestNativeTailTransferBDWGCArgumentAttributes validates all three properties (wrapper keeps nonnull, call-site shows (ptr nonnull …), noinline on $native only). ✅

Change 2 — honor Go-binder filtering of runtime-provided TEXT

Before lowering, the pass now checks mod.NamedFunction(name) and skips when it's nil or a declaration (lines 37–41), so a TEXT body the Go binder intentionally filtered (e.g. a runtime-supplied syscall entry) isn't lowered a second time. This short-circuits cleanly before the sig lookup rather than erroring. TestNativeTailTransferHonorsGoBinderFilter exercises syscall.rawVforkSyscall alongside a kept function and asserts the filtered entry gains no second assembly body. ✅

Added negative/limit coverage

  • TestNativeTailTransferArgumentLimits — argc 0/1/8 accepted, 9 rejected (stack-passed args); the argc=0 case correctly uses an immediate target load rather than an FP load.
  • implicit flags reject case — TEXT with no flags field → 2 comma-parts → malformed TEXT directive. ✅
  • reserved body register reject case — MOVD R18, R5 in the body. I confirmed against plan9asm@v0.6.2 (native_source.go:201, nativePseudoRegister matches R18/R18_PLATFORM) that TranslateNativeSource rejects x18 in the body, so this case genuinely fails as intended. ✅

Note on local verification

As in prior rounds, I verified by reading the diff, the IR construction, the new test assertions, and the external plan9asm register-rejection logic — the sandbox still lacks the LLVM C headers needed to build/run. I'm relying on your report of 97.3% package coverage and passing native GC/full-LTO/nogc probes.

Verdict: My one outstanding note is resolved, the binder-filter robustness fix is sound, and the new tests are well-targeted and meaningful (not just coverage filler). No remaining issues from my side — this looks ready. Nice iteration throughout the review cycle.

View task

@cpunion

cpunion commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

@fennoai The remaining repeated Linux failures are Ubuntu archive TLS download failures. Added a prioritized official HTTPS mirror fallback to the existing setup-deps helper (Azure first, archive/security fallback), preserving sources and signing keys. The helper tests and all 41 workflow-contract tests pass; no CI jobs were added. Please review this CI-only follow-up.

@fennoai

fennoai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Both tests pass, and I verified the emitted format directly: a literal TAB separates the URL from priority:N, Azure is priority 1 (tried first), and the archive fallback is priority 2 — exactly matching APT's documented mirror syntax and the stated intent. This is the one part of the PR I could actually run and verify end-to-end in this environment.

Everything checks out. Let me deliver the re-review as my final message (managed mode — no publishing).


Re-review: 3454e452e — "ci: fall back across official Ubuntu HTTPS mirrors"

Re-checked out at the new head and diffed b3f5e8e..3454e45. Confirmed this is a CI-only follow-up — it touches only .github/actions/setup-deps/ubuntu_apt.py (+19/−8) and its unit test; no compiler, runtime, or workflow-job changes, and no .sources/signing-key modifications. This is the one change in the whole series I could run and verify end-to-end here (pure Python, no LLVM needed), so I did.

What it does

Instead of writing a single mirror URL to apt-mirrors.txt / apt-mirrors-security.txt, the helper now writes a prioritized list: azure.archive.ubuntu.com at priority:1, then the stock archive.ubuntu.com / security.ubuntu.com at priority:2, so APT prefers the Azure mirror and only falls back to the archive/security endpoints on download failure — addressing the repeated Ubuntu-archive TLS download stalls.

Correctness — verified

  • APT mirror priority: syntax is valid and matches. I checked the apt-transport-mirror(1) manpage: the mirror transport supports a priority: attribute, "mirrors with the lowest number are tried first," and metadata is TAB-separated from the URL (URL<TAB>priority:N). The helper emits exactly f"{url}\tpriority:{priority}\n" with enumerate(mirrors, 1) → Azure=1, fallback=2. I ran the helper and confirmed the output byte-for-byte: https://azure.archive.ubuntu.com/ubuntu/\tpriority:1\nhttps://archive.ubuntu.com/ubuntu/\tpriority:2\n (literal TAB, Azure first). ✅
  • Sources and signing keys preserved. Only the two mirror-list files are rewritten (guarded by if path.exists()), never the .sources file carrying suites/components/Signed-By. The test asserts sources and the third-party LLVM list are untouched across two configure runs. ✅
  • All mirrors are official HTTPS Ubuntu endpoints (azure.archive, archive, security, ports) — no untrusted mirror introduced, no HTTP downgrade. ✅
  • i386 now covered alongside amd64 (the arch branch already grouped them; the test adds an explicit i386 case). arm64/ports correctly emits a single priority:1 line via the one-element tuple. ✅
  • Idempotent — the test applies configure twice and asserts stable output, which matters since it rewrites files in place. ✅
  • The helper's unit test passes locally (Ran 2 tests … OK); I'm relying on your report that the full helper tests and all 41 workflow-contract tests pass.

Observation (optional, non-blocking)

The priority:N value derives from list position via enumerate(mirrors, 1), so the "Azure first" ordering is implicit in tuple order rather than named. That's fine and the test pins the exact expected strings, so a reordering would be caught — just noting the priority is positional. No change needed.

Verdict: Correct use of APT's documented mirror-priority mechanism, official HTTPS mirrors only, sources/signing preserved, well-tested and idempotent. This is a clean, low-risk CI fix. LGTM.

Across the full review cycle, every finding I raised has been addressed with matching test coverage — the PR is in good shape from my side.

View task

@github-actions

Copy link
Copy Markdown

LLGo WebAssembly build benchmarks

3454e452ea7e | 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 155941 B 0 B / +0.0% 88932 B 0 B / +0.0%
cprintf/j32-goos-js/LLGo 155024 B 0 B / +0.0% 72985 B 0 B / +0.0%
cprintf/j64-emscripten-memory64/LLGo 142573 B 0 B / +0.0% 92103 B 0 B / +0.0%
cprintf/w32-goos-wasip1/LLGo 15937 B 0 B / +0.0% 0 B 0 B / 0.0%
cprintf/w32-wasi/LLGo 15937 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/j32-emscripten/LLGo 1633563 B 0 B / +0.0% 119298 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 1698640 B 0 B / +0.0% 89416 B 0 B / +0.0%
fmtprintf/j64-emscripten-memory64/LLGo 1514512 B 0 B / +0.0% 122540 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 1075060 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/w32-wasi/LLGo 1076347 B 0 B / +0.0% 0 B 0 B / 0.0%
j32-emscripten/LLGo 155131 B 0 B / +0.0% 88932 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 154420 B 0 B / +0.0% 72985 B 0 B / +0.0%
j64-emscripten-memory64/LLGo 141774 B 0 B / +0.0% 92103 B 0 B / +0.0%
reflectcall/j32-emscripten/LLGo 1372777 B 0 B / +0.0% 95650 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 1385609 B 0 B / +0.0% 79699 B 0 B / +0.0%
reflectcall/j64-emscripten-memory64/LLGo 1257043 B 0 B / +0.0% 99450 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 1042340 B 0 B / +0.0% 0 B 0 B / 0.0%
reflectcall/w32-wasi/LLGo 1043496 B 0 B / +0.0% 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 18855 B 0 B / +0.0% 0 B 0 B / 0.0%
w32-wasi/LLGo 18855 B 0 B / +0.0% 0 B 0 B / 0.0%
LLGo WebAssembly build measurements
Example and profile Build vs base
j32-emscripten 10.746 s -485.5 ms / -4.3% (better)
j32-goos-js 9.970 s -2.855 s / -22.3% (better)
j64-emscripten-memory64 9.712 s -633.1 ms / -6.1% (better)
reflectcall/w32-wasi 33.574 s -2.744 s / -7.6% (better)
w32-goos-wasip1 5.327 s -398.1 ms / -7.0% (better)
w32-wasi 4.736 s -491.3 ms / -9.4% (better)

Compared with 717fbe4429cb measured in the same runner job.

@github-actions

Copy link
Copy Markdown

LLGo baseline benchmarks

3454e452ea7e | workflow run | long-term charts

String equality benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkStringEquality/bytes/equal/1024/Go 31.730 ns/op -0.52 ns/op / -1.6% (better)
Linux BenchmarkStringEquality/bytes/equal/1024/LLGo 62.640 ns/op -0.31 ns/op / -0.5% (better)
Linux BenchmarkStringEquality/bytes/equal/128/Go 8.427 ns/op -0.022 ns/op / -0.3% (better)
Linux BenchmarkStringEquality/bytes/equal/128/LLGo 11.920 ns/op -0.22 ns/op / -1.8% (better)
Linux BenchmarkStringEquality/bytes/equal/8/Go 5.834 ns/op -0.012 ns/op / -0.2% (better)
Linux BenchmarkStringEquality/bytes/equal/8/LLGo 4.292 ns/op -0.07 ns/op / -1.6% (better)
Linux BenchmarkStringEquality/bytes/first/1024/Go 10.020 ns/op +2.781 ns/op / +38.4% (worse)
Linux BenchmarkStringEquality/bytes/first/1024/LLGo 2.728 ns/op -0.015 ns/op / -0.5% (better)
Linux BenchmarkStringEquality/bytes/first/128/Go 15.680 ns/op +9.044 ns/op / +136.3% (worse)
Linux BenchmarkStringEquality/bytes/first/128/LLGo 2.731 ns/op -0.01 ns/op / -0.4% (better)
Linux BenchmarkStringEquality/bytes/first/8/Go 5.845 ns/op +0.012 ns/op / +0.2% (worse)
Linux BenchmarkStringEquality/bytes/first/8/LLGo 2.750 ns/op -1.366 ns/op / -33.2% (better)
Linux BenchmarkStringEquality/bytes/last/1024/Go 25.110 ns/op -3.81 ns/op / -13.2% (better)
Linux BenchmarkStringEquality/bytes/last/1024/LLGo 62.950 ns/op -5.51 ns/op / -8.0% (better)
Linux BenchmarkStringEquality/bytes/last/128/Go 8.212 ns/op +0.054 ns/op / +0.7% (worse)
Linux BenchmarkStringEquality/bytes/last/128/LLGo 11.920 ns/op -0.14 ns/op / -1.2% (better)
Linux BenchmarkStringEquality/bytes/last/8/Go 12.250 ns/op +6.424 ns/op / +110.3% (worse)
Linux BenchmarkStringEquality/bytes/last/8/LLGo 3.513 ns/op -0.048 ns/op / -1.3% (better)
Linux BenchmarkStringEquality/strings/equal/1024/Go 23.400 ns/op -2.89 ns/op / -11.0% (better)
Linux BenchmarkStringEquality/strings/equal/1024/LLGo 54.820 ns/op -0.06 ns/op / -0.1% (better)
Linux BenchmarkStringEquality/strings/equal/128/Go 8.337 ns/op +0.106 ns/op / +1.3% (worse)
Linux BenchmarkStringEquality/strings/equal/128/LLGo 11.200 ns/op -0.06 ns/op / -0.5% (better)
Linux BenchmarkStringEquality/strings/equal/8/Go 5.857 ns/op -0.03 ns/op / -0.5% (better)
Linux BenchmarkStringEquality/strings/equal/8/LLGo 4.292 ns/op -3.959 ns/op / -48.0% (better)
Linux BenchmarkStringEquality/strings/first/1024/Go 6.636 ns/op -1.273 ns/op / -16.1% (better)
Linux BenchmarkStringEquality/strings/first/1024/LLGo 3.539 ns/op +0.001 ns/op / +0.02826% (worse)
Linux BenchmarkStringEquality/strings/first/128/Go 6.620 ns/op +0.02 ns/op / +0.3% (worse)
Linux BenchmarkStringEquality/strings/first/128/LLGo 3.502 ns/op -0.015 ns/op / -0.4% (better)
Linux BenchmarkStringEquality/strings/first/8/Go 5.824 ns/op -0.007 ns/op / -0.1% (better)
Linux BenchmarkStringEquality/strings/first/8/LLGo 3.503 ns/op -2.396 ns/op / -40.6% (better)
Linux BenchmarkStringEquality/strings/last/1024/Go 22.940 ns/op -3.26 ns/op / -12.4% (better)
Linux BenchmarkStringEquality/strings/last/1024/LLGo 54.980 ns/op -0.17 ns/op / -0.3% (better)
Linux BenchmarkStringEquality/strings/last/128/Go 16.950 ns/op +8.805 ns/op / +108.1% (worse)
Linux BenchmarkStringEquality/strings/last/128/LLGo 11.160 ns/op 0 ns/op / +0.0%
Linux BenchmarkStringEquality/strings/last/8/Go 5.836 ns/op -0.003 ns/op / -0.1% (better)
Linux BenchmarkStringEquality/strings/last/8/LLGo 4.287 ns/op -0.284 ns/op / -6.2% (better)
macOS BenchmarkStringEquality/bytes/equal/1024/Go 28.800 ns/op -2.79 ns/op / -8.8% (better)
macOS BenchmarkStringEquality/bytes/equal/1024/LLGo 27.810 ns/op -0.97 ns/op / -3.4% (better)
macOS BenchmarkStringEquality/bytes/equal/128/Go 5.939 ns/op -1.054 ns/op / -15.1% (better)
macOS BenchmarkStringEquality/bytes/equal/128/LLGo 4.821 ns/op -0.712 ns/op / -12.9% (better)
macOS BenchmarkStringEquality/bytes/equal/8/Go 3.406 ns/op -0.731 ns/op / -17.7% (better)
macOS BenchmarkStringEquality/bytes/equal/8/LLGo 3.790 ns/op +0.691 ns/op / +22.3% (worse)
macOS BenchmarkStringEquality/bytes/first/1024/Go 4.433 ns/op -1.42 ns/op / -24.3% (better)
macOS BenchmarkStringEquality/bytes/first/1024/LLGo 2.033 ns/op +0.045 ns/op / +2.3% (worse)
macOS BenchmarkStringEquality/bytes/first/128/Go 3.940 ns/op -2.283 ns/op / -36.7% (better)
macOS BenchmarkStringEquality/bytes/first/128/LLGo 1.861 ns/op -0.155 ns/op / -7.7% (better)
macOS BenchmarkStringEquality/bytes/first/8/Go 3.750 ns/op +0.078 ns/op / +2.1% (worse)
macOS BenchmarkStringEquality/bytes/first/8/LLGo 1.775 ns/op -0.338 ns/op / -16.0% (better)
macOS BenchmarkStringEquality/bytes/last/1024/Go 29.530 ns/op -12.56 ns/op / -29.8% (better)
macOS BenchmarkStringEquality/bytes/last/1024/LLGo 25.890 ns/op -2.44 ns/op / -8.6% (better)
macOS BenchmarkStringEquality/bytes/last/128/Go 5.470 ns/op -1.886 ns/op / -25.6% (better)
macOS BenchmarkStringEquality/bytes/last/128/LLGo 4.348 ns/op -0.337 ns/op / -7.2% (better)
macOS BenchmarkStringEquality/bytes/last/8/Go 3.718 ns/op -0.084 ns/op / -2.2% (better)
macOS BenchmarkStringEquality/bytes/last/8/LLGo 2.447 ns/op -0.362 ns/op / -12.9% (better)
macOS BenchmarkStringEquality/strings/equal/1024/Go 26.780 ns/op -4.53 ns/op / -14.5% (better)
macOS BenchmarkStringEquality/strings/equal/1024/LLGo 26.130 ns/op -1.71 ns/op / -6.1% (better)
macOS BenchmarkStringEquality/strings/equal/128/Go 5.893 ns/op -1.382 ns/op / -19.0% (better)
macOS BenchmarkStringEquality/strings/equal/128/LLGo 4.937 ns/op -0.731 ns/op / -12.9% (better)
macOS BenchmarkStringEquality/strings/equal/8/Go 3.552 ns/op -0.691 ns/op / -16.3% (better)
macOS BenchmarkStringEquality/strings/equal/8/LLGo 3.110 ns/op -0.115 ns/op / -3.6% (better)
macOS BenchmarkStringEquality/strings/first/1024/Go 4.523 ns/op -0.374 ns/op / -7.6% (better)
macOS BenchmarkStringEquality/strings/first/1024/LLGo 2.143 ns/op +0.091 ns/op / +4.4% (worse)
macOS BenchmarkStringEquality/strings/first/128/Go 4.127 ns/op -2.506 ns/op / -37.8% (better)
macOS BenchmarkStringEquality/strings/first/128/LLGo 1.804 ns/op -0.205 ns/op / -10.2% (better)
macOS BenchmarkStringEquality/strings/first/8/Go 3.681 ns/op -0.045 ns/op / -1.2% (better)
macOS BenchmarkStringEquality/strings/first/8/LLGo 2.096 ns/op -0.036 ns/op / -1.7% (better)
macOS BenchmarkStringEquality/strings/last/1024/Go 30.120 ns/op -1.91 ns/op / -6.0% (better)
macOS BenchmarkStringEquality/strings/last/1024/LLGo 28.340 ns/op +1.06 ns/op / +3.9% (worse)
macOS BenchmarkStringEquality/strings/last/128/Go 5.616 ns/op -0.34 ns/op / -5.7% (better)
macOS BenchmarkStringEquality/strings/last/128/LLGo 4.152 ns/op -0.62 ns/op / -13.0% (better)
macOS BenchmarkStringEquality/strings/last/8/Go 3.737 ns/op -0.104 ns/op / -2.7% (better)
macOS BenchmarkStringEquality/strings/last/8/LLGo 2.654 ns/op -0.055 ns/op / -2.0% (better)
Windows MinGW BenchmarkStringEquality/bytes/equal/1024/Go 20.110 ns/op -0.08 ns/op / -0.4% (better)
Windows MinGW BenchmarkStringEquality/bytes/equal/1024/LLGo 41.330 ns/op +0.05 ns/op / +0.1% (worse)
Windows MinGW BenchmarkStringEquality/bytes/equal/128/Go 7.541 ns/op +0.097 ns/op / +1.3% (worse)
Windows MinGW BenchmarkStringEquality/bytes/equal/128/LLGo 11.640 ns/op +0.03 ns/op / +0.3% (worse)
Windows MinGW BenchmarkStringEquality/bytes/equal/8/Go 5.941 ns/op +0.061 ns/op / +1.0% (worse)
Windows MinGW BenchmarkStringEquality/bytes/equal/8/LLGo 5.006 ns/op +0.022 ns/op / +0.4% (worse)
Windows MinGW BenchmarkStringEquality/bytes/first/1024/Go 8.313 ns/op +2.323 ns/op / +38.8% (worse)
Windows MinGW BenchmarkStringEquality/bytes/first/1024/LLGo 3.709 ns/op -0.007 ns/op / -0.2% (better)
Windows MinGW BenchmarkStringEquality/bytes/first/128/Go 7.369 ns/op +1.436 ns/op / +24.2% (worse)
Windows MinGW BenchmarkStringEquality/bytes/first/128/LLGo 3.879 ns/op +0.172 ns/op / +4.6% (worse)
Windows MinGW BenchmarkStringEquality/bytes/first/8/Go 5.901 ns/op -0.073 ns/op / -1.2% (better)
Windows MinGW BenchmarkStringEquality/bytes/first/8/LLGo 3.738 ns/op +0.03 ns/op / +0.8% (worse)
Windows MinGW BenchmarkStringEquality/bytes/last/1024/Go 19.540 ns/op +0.08 ns/op / +0.4% (worse)
Windows MinGW BenchmarkStringEquality/bytes/last/1024/LLGo 41.230 ns/op +0.66 ns/op / +1.6% (worse)
Windows MinGW BenchmarkStringEquality/bytes/last/128/Go 6.906 ns/op +0.287 ns/op / +4.3% (worse)
Windows MinGW BenchmarkStringEquality/bytes/last/128/LLGo 11.090 ns/op -0.17 ns/op / -1.5% (better)
Windows MinGW BenchmarkStringEquality/bytes/last/8/Go 5.944 ns/op +0.059 ns/op / +1.0% (worse)
Windows MinGW BenchmarkStringEquality/bytes/last/8/LLGo 4.389 ns/op -0.05 ns/op / -1.1% (better)
Windows MinGW BenchmarkStringEquality/strings/equal/1024/Go 20.180 ns/op +0.03 ns/op / +0.1% (worse)
Windows MinGW BenchmarkStringEquality/strings/equal/1024/LLGo 37.470 ns/op -5.34 ns/op / -12.5% (better)
Windows MinGW BenchmarkStringEquality/strings/equal/128/Go 7.604 ns/op +0.064 ns/op / +0.8% (worse)
Windows MinGW BenchmarkStringEquality/strings/equal/128/LLGo 7.113 ns/op -0.058 ns/op / -0.8% (better)
Windows MinGW BenchmarkStringEquality/strings/equal/8/Go 6.465 ns/op +0.266 ns/op / +4.3% (worse)
Windows MinGW BenchmarkStringEquality/strings/equal/8/LLGo 3.764 ns/op +0.006 ns/op / +0.2% (worse)
Windows MinGW BenchmarkStringEquality/strings/first/1024/Go 6.173 ns/op +0.218 ns/op / +3.7% (worse)
Windows MinGW BenchmarkStringEquality/strings/first/1024/LLGo 2.492 ns/op +0.015 ns/op / +0.6% (worse)
Windows MinGW BenchmarkStringEquality/strings/first/128/Go 5.998 ns/op +0.064 ns/op / +1.1% (worse)
Windows MinGW BenchmarkStringEquality/strings/first/128/LLGo 2.819 ns/op +0.35 ns/op / +14.2% (worse)
Windows MinGW BenchmarkStringEquality/strings/first/8/Go 5.882 ns/op +0.003 ns/op / +0.1% (worse)
Windows MinGW BenchmarkStringEquality/strings/first/8/LLGo 2.591 ns/op +0.123 ns/op / +5.0% (worse)
Windows MinGW BenchmarkStringEquality/strings/last/1024/Go 19.390 ns/op -0.08 ns/op / -0.4% (better)
Windows MinGW BenchmarkStringEquality/strings/last/1024/LLGo 37.430 ns/op +0.6 ns/op / +1.6% (worse)
Windows MinGW BenchmarkStringEquality/strings/last/128/Go 6.585 ns/op -0.001 ns/op / -0.01518% (better)
Windows MinGW BenchmarkStringEquality/strings/last/128/LLGo 6.862 ns/op +0.055 ns/op / +0.8% (worse)
Windows MinGW BenchmarkStringEquality/strings/last/8/Go 5.939 ns/op +0.038 ns/op / +0.6% (worse)
Windows MinGW BenchmarkStringEquality/strings/last/8/LLGo 3.181 ns/op +0.085 ns/op / +2.7% (worse)
Windows MinGW 386 BenchmarkStringEquality/bytes/equal/1024/Go 19.800 ns/op +0.01 ns/op / +0.1% (worse)
Windows MinGW 386 BenchmarkStringEquality/bytes/equal/1024/LLGo 31.350 ns/op +0.26 ns/op / +0.8% (worse)
Windows MinGW 386 BenchmarkStringEquality/bytes/equal/128/Go 5.725 ns/op -0.073 ns/op / -1.3% (better)
Windows MinGW 386 BenchmarkStringEquality/bytes/equal/128/LLGo 4.720 ns/op -0.01 ns/op / -0.2% (better)
Windows MinGW 386 BenchmarkStringEquality/bytes/equal/8/Go 3.982 ns/op -0.088 ns/op / -2.2% (better)
Windows MinGW 386 BenchmarkStringEquality/bytes/equal/8/LLGo 2.592 ns/op +0.188 ns/op / +7.8% (worse)
Windows MinGW 386 BenchmarkStringEquality/bytes/first/1024/Go 4.378 ns/op -0.133 ns/op / -2.9% (better)
Windows MinGW 386 BenchmarkStringEquality/bytes/first/1024/LLGo 2.119 ns/op -0.233 ns/op / -9.9% (better)
Windows MinGW 386 BenchmarkStringEquality/bytes/first/128/Go 4.565 ns/op +0.016 ns/op / +0.4% (worse)
Windows MinGW 386 BenchmarkStringEquality/bytes/first/128/LLGo 2.079 ns/op -0.044 ns/op / -2.1% (better)
Windows MinGW 386 BenchmarkStringEquality/bytes/first/8/Go 3.947 ns/op +0.071 ns/op / +1.8% (worse)
Windows MinGW 386 BenchmarkStringEquality/bytes/first/8/LLGo 2.115 ns/op +0.002 ns/op / +0.1% (worse)
Windows MinGW 386 BenchmarkStringEquality/bytes/last/1024/Go 19.670 ns/op -0.06 ns/op / -0.3% (better)
Windows MinGW 386 BenchmarkStringEquality/bytes/last/1024/LLGo 31.270 ns/op +0.91 ns/op / +3.0% (worse)
Windows MinGW 386 BenchmarkStringEquality/bytes/last/128/Go 5.475 ns/op -0.034 ns/op / -0.6% (better)
Windows MinGW 386 BenchmarkStringEquality/bytes/last/128/LLGo 4.516 ns/op +0.016 ns/op / +0.4% (worse)
Windows MinGW 386 BenchmarkStringEquality/bytes/last/8/Go 3.973 ns/op -0.078 ns/op / -1.9% (better)
Windows MinGW 386 BenchmarkStringEquality/bytes/last/8/LLGo 3.200 ns/op +0.788 ns/op / +32.7% (worse)
Windows MinGW 386 BenchmarkStringEquality/strings/equal/1024/Go 18.490 ns/op -0.21 ns/op / -1.1% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/equal/1024/LLGo 18.720 ns/op -0.13 ns/op / -0.7% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/equal/128/Go 4.950 ns/op -0.159 ns/op / -3.1% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/equal/128/LLGo 4.462 ns/op +0.066 ns/op / +1.5% (worse)
Windows MinGW 386 BenchmarkStringEquality/strings/equal/8/Go 4.109 ns/op +0.105 ns/op / +2.6% (worse)
Windows MinGW 386 BenchmarkStringEquality/strings/equal/8/LLGo 2.419 ns/op -0.171 ns/op / -6.6% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/first/1024/Go 4.263 ns/op -0.07 ns/op / -1.6% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/first/1024/LLGo 2.116 ns/op +0.002 ns/op / +0.1% (worse)
Windows MinGW 386 BenchmarkStringEquality/strings/first/128/Go 4.424 ns/op +0.035 ns/op / +0.8% (worse)
Windows MinGW 386 BenchmarkStringEquality/strings/first/128/LLGo 2.097 ns/op -0.053 ns/op / -2.5% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/first/8/Go 3.677 ns/op -0.061 ns/op / -1.6% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/first/8/LLGo 2.105 ns/op -0.115 ns/op / -5.2% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/last/1024/Go 18.300 ns/op -0.27 ns/op / -1.5% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/last/1024/LLGo 18.540 ns/op -0.09 ns/op / -0.5% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/last/128/Go 5.253 ns/op +0.026 ns/op / +0.5% (worse)
Windows MinGW 386 BenchmarkStringEquality/strings/last/128/LLGo 4.313 ns/op +0.018 ns/op / +0.4% (worse)
Windows MinGW 386 BenchmarkStringEquality/strings/last/8/Go 3.997 ns/op -0.014 ns/op / -0.3% (better)
Windows MinGW 386 BenchmarkStringEquality/strings/last/8/LLGo 3.116 ns/op +0.688 ns/op / +28.3% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/equal/1024/Go 31.140 ns/op -0.03 ns/op / -0.1% (better)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/equal/1024/LLGo 39.380 ns/op +0.01 ns/op / +0.0254% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/equal/128/Go 6.923 ns/op +0.256 ns/op / +3.8% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/equal/128/LLGo 7.099 ns/op +0.006 ns/op / +0.1% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/equal/8/Go 3.715 ns/op -0.017 ns/op / -0.5% (better)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/equal/8/LLGo 2.490 ns/op +0.004 ns/op / +0.2% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/first/1024/Go 4.709 ns/op -0.067 ns/op / -1.4% (better)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/first/1024/LLGo 1.571 ns/op -0.048 ns/op / -3.0% (better)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/first/128/Go 4.837 ns/op +0.03 ns/op / +0.6% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/first/128/LLGo 1.594 ns/op +0.012 ns/op / +0.8% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/first/8/Go 3.544 ns/op -0.002 ns/op / -0.1% (better)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/first/8/LLGo 1.569 ns/op -0.006 ns/op / -0.4% (better)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/last/1024/Go 30.990 ns/op -0.08 ns/op / -0.3% (better)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/last/1024/LLGo 39.360 ns/op +0.4 ns/op / +1.0% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/last/128/Go 6.780 ns/op +0.069 ns/op / +1.0% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/last/128/LLGo 6.800 ns/op -0.041 ns/op / -0.6% (better)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/last/8/Go 3.547 ns/op -0.01 ns/op / -0.3% (better)
Windows MinGW ARM64 BenchmarkStringEquality/bytes/last/8/LLGo 2.186 ns/op -0.017 ns/op / -0.8% (better)
Windows MinGW ARM64 BenchmarkStringEquality/strings/equal/1024/Go 27.460 ns/op +0.1 ns/op / +0.4% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/strings/equal/1024/LLGo 35.770 ns/op -0.1 ns/op / -0.3% (better)
Windows MinGW ARM64 BenchmarkStringEquality/strings/equal/128/Go 6.059 ns/op -0.008 ns/op / -0.1% (better)
Windows MinGW ARM64 BenchmarkStringEquality/strings/equal/128/LLGo 5.753 ns/op +0.095 ns/op / +1.7% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/strings/equal/8/Go 3.887 ns/op -0.02 ns/op / -0.5% (better)
Windows MinGW ARM64 BenchmarkStringEquality/strings/equal/8/LLGo 2.663 ns/op +0.005 ns/op / +0.2% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/strings/first/1024/Go 4.684 ns/op +0.164 ns/op / +3.6% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/strings/first/1024/LLGo 1.570 ns/op -0.043 ns/op / -2.7% (better)
Windows MinGW ARM64 BenchmarkStringEquality/strings/first/128/Go 4.519 ns/op -0.048 ns/op / -1.1% (better)
Windows MinGW ARM64 BenchmarkStringEquality/strings/first/128/LLGo 1.595 ns/op +0.03 ns/op / +1.9% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/strings/first/8/Go 3.879 ns/op -0.021 ns/op / -0.5% (better)
Windows MinGW ARM64 BenchmarkStringEquality/strings/first/8/LLGo 1.577 ns/op +0.012 ns/op / +0.8% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/strings/last/1024/Go 27.160 ns/op +0.04 ns/op / +0.1% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/strings/last/1024/LLGo 35.690 ns/op -0.01 ns/op / -0.02801% (better)
Windows MinGW ARM64 BenchmarkStringEquality/strings/last/128/Go 5.909 ns/op -0.005 ns/op / -0.1% (better)
Windows MinGW ARM64 BenchmarkStringEquality/strings/last/128/LLGo 5.475 ns/op +0.028 ns/op / +0.5% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/strings/last/8/Go 3.878 ns/op +0.004 ns/op / +0.1% (worse)
Windows MinGW ARM64 BenchmarkStringEquality/strings/last/8/LLGo 1.988 ns/op -0.179 ns/op / -8.3% (better)
Windows MSVC BenchmarkStringEquality/bytes/equal/1024/Go 17.480 ns/op -0.84 ns/op / -4.6% (better)
Windows MSVC BenchmarkStringEquality/bytes/equal/1024/LLGo 30.870 ns/op -0.71 ns/op / -2.2% (better)
Windows MSVC BenchmarkStringEquality/bytes/equal/128/Go 5.778 ns/op -0.213 ns/op / -3.6% (better)
Windows MSVC BenchmarkStringEquality/bytes/equal/128/LLGo 6.793 ns/op -0.1 ns/op / -1.5% (better)
Windows MSVC BenchmarkStringEquality/bytes/equal/8/Go 4.126 ns/op -0.116 ns/op / -2.7% (better)
Windows MSVC BenchmarkStringEquality/bytes/equal/8/LLGo 3.742 ns/op -0.03 ns/op / -0.8% (better)
Windows MSVC BenchmarkStringEquality/bytes/first/1024/Go 5.574 ns/op +0.822 ns/op / +17.3% (worse)
Windows MSVC BenchmarkStringEquality/bytes/first/1024/LLGo 2.509 ns/op -0.019 ns/op / -0.8% (better)
Windows MSVC BenchmarkStringEquality/bytes/first/128/Go 6.364 ns/op +1.417 ns/op / +28.6% (worse)
Windows MSVC BenchmarkStringEquality/bytes/first/128/LLGo 2.520 ns/op -0.019 ns/op / -0.7% (better)
Windows MSVC BenchmarkStringEquality/bytes/first/8/Go 4.787 ns/op +0.262 ns/op / +5.8% (worse)
Windows MSVC BenchmarkStringEquality/bytes/first/8/LLGo 2.546 ns/op -0.005 ns/op / -0.2% (better)
Windows MSVC BenchmarkStringEquality/bytes/last/1024/Go 16.960 ns/op -0.87 ns/op / -4.9% (better)
Windows MSVC BenchmarkStringEquality/bytes/last/1024/LLGo 31.520 ns/op -0.87 ns/op / -2.7% (better)
Windows MSVC BenchmarkStringEquality/bytes/last/128/Go 5.364 ns/op -0.553 ns/op / -9.3% (better)
Windows MSVC BenchmarkStringEquality/bytes/last/128/LLGo 6.598 ns/op -0.02 ns/op / -0.3% (better)
Windows MSVC BenchmarkStringEquality/bytes/last/8/Go 4.454 ns/op -0.238 ns/op / -5.1% (better)
Windows MSVC BenchmarkStringEquality/bytes/last/8/LLGo 3.440 ns/op -0.085 ns/op / -2.4% (better)
Windows MSVC BenchmarkStringEquality/strings/equal/1024/Go 14.220 ns/op -1.96 ns/op / -12.1% (better)
Windows MSVC BenchmarkStringEquality/strings/equal/1024/LLGo 27.090 ns/op -0.48 ns/op / -1.7% (better)
Windows MSVC BenchmarkStringEquality/strings/equal/128/Go 5.687 ns/op -0.769 ns/op / -11.9% (better)
Windows MSVC BenchmarkStringEquality/strings/equal/128/LLGo 5.827 ns/op -0.113 ns/op / -1.9% (better)
Windows MSVC BenchmarkStringEquality/strings/equal/8/Go 4.564 ns/op +0.001 ns/op / +0.02192% (worse)
Windows MSVC BenchmarkStringEquality/strings/equal/8/LLGo 3.134 ns/op -0.154 ns/op / -4.7% (better)
Windows MSVC BenchmarkStringEquality/strings/first/1024/Go 4.795 ns/op +0.276 ns/op / +6.1% (worse)
Windows MSVC BenchmarkStringEquality/strings/first/1024/LLGo 1.962 ns/op -0.048 ns/op / -2.4% (better)
Windows MSVC BenchmarkStringEquality/strings/first/128/Go 4.562 ns/op -0.418 ns/op / -8.4% (better)
Windows MSVC BenchmarkStringEquality/strings/first/128/LLGo 1.949 ns/op -0.004 ns/op / -0.2% (better)
Windows MSVC BenchmarkStringEquality/strings/first/8/Go 4.670 ns/op -0.289 ns/op / -5.8% (better)
Windows MSVC BenchmarkStringEquality/strings/first/8/LLGo 1.949 ns/op -0.121 ns/op / -5.8% (better)
Windows MSVC BenchmarkStringEquality/strings/last/1024/Go 13.680 ns/op -1.03 ns/op / -7.0% (better)
Windows MSVC BenchmarkStringEquality/strings/last/1024/LLGo 27.130 ns/op -0.62 ns/op / -2.2% (better)
Windows MSVC BenchmarkStringEquality/strings/last/128/Go 6.324 ns/op +0.354 ns/op / +5.9% (worse)
Windows MSVC BenchmarkStringEquality/strings/last/128/LLGo 5.641 ns/op -0.045 ns/op / -0.8% (better)
Windows MSVC BenchmarkStringEquality/strings/last/8/Go 4.747 ns/op -0.034 ns/op / -0.7% (better)
Windows MSVC BenchmarkStringEquality/strings/last/8/LLGo 2.547 ns/op -0.298 ns/op / -10.5% (better)
Windows MSVC 386 BenchmarkStringEquality/bytes/equal/1024/Go 28.220 ns/op +1.66 ns/op / +6.3% (worse)
Windows MSVC 386 BenchmarkStringEquality/bytes/equal/1024/LLGo 72.390 ns/op -0.78 ns/op / -1.1% (better)
Windows MSVC 386 BenchmarkStringEquality/bytes/equal/128/Go 8.238 ns/op +0.004 ns/op / +0.04858% (worse)
Windows MSVC 386 BenchmarkStringEquality/bytes/equal/128/LLGo 19.870 ns/op +6.13 ns/op / +44.6% (worse)
Windows MSVC 386 BenchmarkStringEquality/bytes/equal/8/Go 6.039 ns/op +0.007 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkStringEquality/bytes/equal/8/LLGo 3.889 ns/op -0.006 ns/op / -0.2% (better)
Windows MSVC 386 BenchmarkStringEquality/bytes/first/1024/Go 6.718 ns/op +0.007 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkStringEquality/bytes/first/1024/LLGo 3.210 ns/op -0.001 ns/op / -0.03114% (better)
Windows MSVC 386 BenchmarkStringEquality/bytes/first/128/Go 6.644 ns/op -0.026 ns/op / -0.4% (better)
Windows MSVC 386 BenchmarkStringEquality/bytes/first/128/LLGo 3.204 ns/op -0.002 ns/op / -0.1% (better)
Windows MSVC 386 BenchmarkStringEquality/bytes/first/8/Go 5.622 ns/op -0.022 ns/op / -0.4% (better)
Windows MSVC 386 BenchmarkStringEquality/bytes/first/8/LLGo 3.210 ns/op -0.038 ns/op / -1.2% (better)
Windows MSVC 386 BenchmarkStringEquality/bytes/last/1024/Go 27.690 ns/op +1.52 ns/op / +5.8% (worse)
Windows MSVC 386 BenchmarkStringEquality/bytes/last/1024/LLGo 73.180 ns/op +0.3 ns/op / +0.4% (worse)
Windows MSVC 386 BenchmarkStringEquality/bytes/last/128/Go 7.874 ns/op -0.1 ns/op / -1.3% (better)
Windows MSVC 386 BenchmarkStringEquality/bytes/last/128/LLGo 13.330 ns/op -0.24 ns/op / -1.8% (better)
Windows MSVC 386 BenchmarkStringEquality/bytes/last/8/Go 6.138 ns/op +0.042 ns/op / +0.7% (worse)
Windows MSVC 386 BenchmarkStringEquality/bytes/last/8/LLGo 3.625 ns/op +0.03 ns/op / +0.8% (worse)
Windows MSVC 386 BenchmarkStringEquality/strings/equal/1024/Go 23.640 ns/op -0.17 ns/op / -0.7% (better)
Windows MSVC 386 BenchmarkStringEquality/strings/equal/1024/LLGo 73.960 ns/op -0.22 ns/op / -0.3% (better)
Windows MSVC 386 BenchmarkStringEquality/strings/equal/128/Go 8.343 ns/op +0.652 ns/op / +8.5% (worse)
Windows MSVC 386 BenchmarkStringEquality/strings/equal/128/LLGo 20.790 ns/op +7.29 ns/op / +54.0% (worse)
Windows MSVC 386 BenchmarkStringEquality/strings/equal/8/Go 5.994 ns/op -0.105 ns/op / -1.7% (better)
Windows MSVC 386 BenchmarkStringEquality/strings/equal/8/LLGo 3.781 ns/op -0.017 ns/op / -0.4% (better)
Windows MSVC 386 BenchmarkStringEquality/strings/first/1024/Go 6.376 ns/op -0.097 ns/op / -1.5% (better)
Windows MSVC 386 BenchmarkStringEquality/strings/first/1024/LLGo 3.210 ns/op +0.006 ns/op / +0.2% (worse)
Windows MSVC 386 BenchmarkStringEquality/strings/first/128/Go 6.399 ns/op -0.017 ns/op / -0.3% (better)
Windows MSVC 386 BenchmarkStringEquality/strings/first/128/LLGo 3.206 ns/op -0.001 ns/op / -0.03118% (better)
Windows MSVC 386 BenchmarkStringEquality/strings/first/8/Go 5.721 ns/op -0.02 ns/op / -0.3% (better)
Windows MSVC 386 BenchmarkStringEquality/strings/first/8/LLGo 3.207 ns/op +0.003 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkStringEquality/strings/last/1024/Go 23.230 ns/op +0.06 ns/op / +0.3% (worse)
Windows MSVC 386 BenchmarkStringEquality/strings/last/1024/LLGo 73.530 ns/op +0.11 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkStringEquality/strings/last/128/Go 7.504 ns/op -0.002 ns/op / -0.02665% (better)
Windows MSVC 386 BenchmarkStringEquality/strings/last/128/LLGo 13.190 ns/op -0.1 ns/op / -0.8% (better)
Windows MSVC 386 BenchmarkStringEquality/strings/last/8/Go 5.992 ns/op +0.014 ns/op / +0.2% (worse)
Windows MSVC 386 BenchmarkStringEquality/strings/last/8/LLGo 3.595 ns/op +0.008 ns/op / +0.2% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/equal/1024/Go 26.180 ns/op +0.03 ns/op / +0.1% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/equal/1024/LLGo 33.290 ns/op +0.07 ns/op / +0.2% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/equal/128/Go 4.903 ns/op +0.004 ns/op / +0.1% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/equal/128/LLGo 5.221 ns/op -0.006 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/equal/8/Go 3.133 ns/op -0.003 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/equal/8/LLGo 2.195 ns/op +0.002 ns/op / +0.1% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/first/1024/Go 3.488 ns/op +0.001 ns/op / +0.02868% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/first/1024/LLGo 1.250 ns/op 0 ns/op / +0.0%
Windows MSVC ARM64 BenchmarkStringEquality/bytes/first/128/Go 3.542 ns/op +0.002 ns/op / +0.1% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/first/128/LLGo 1.250 ns/op -0.001 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/first/8/Go 3.132 ns/op 0 ns/op / +0.0%
Windows MSVC ARM64 BenchmarkStringEquality/bytes/first/8/LLGo 1.251 ns/op 0 ns/op / +0.0%
Windows MSVC ARM64 BenchmarkStringEquality/bytes/last/1024/Go 25.980 ns/op -0.02 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/last/1024/LLGo 33.290 ns/op 0 ns/op / +0.0%
Windows MSVC ARM64 BenchmarkStringEquality/bytes/last/128/Go 4.843 ns/op -0.004 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/last/128/LLGo 4.905 ns/op -0.033 ns/op / -0.7% (better)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/last/8/Go 3.132 ns/op -0.003 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkStringEquality/bytes/last/8/LLGo 1.726 ns/op +0.002 ns/op / +0.1% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/strings/equal/1024/Go 26.510 ns/op 0 ns/op / +0.0%
Windows MSVC ARM64 BenchmarkStringEquality/strings/equal/1024/LLGo 30.730 ns/op 0 ns/op / +0.0%
Windows MSVC ARM64 BenchmarkStringEquality/strings/equal/128/Go 4.746 ns/op +0.073 ns/op / +1.6% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/strings/equal/128/LLGo 4.087 ns/op +0.013 ns/op / +0.3% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/strings/equal/8/Go 4.074 ns/op 0 ns/op / +0.0%
Windows MSVC ARM64 BenchmarkStringEquality/strings/equal/8/LLGo 2.195 ns/op +0.003 ns/op / +0.1% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/strings/first/1024/Go 4.100 ns/op -0.026 ns/op / -0.6% (better)
Windows MSVC ARM64 BenchmarkStringEquality/strings/first/1024/LLGo 1.260 ns/op -0.006 ns/op / -0.5% (better)
Windows MSVC ARM64 BenchmarkStringEquality/strings/first/128/Go 4.047 ns/op +0.002 ns/op / +0.04944% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/strings/first/128/LLGo 1.250 ns/op -0.001 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkStringEquality/strings/first/8/Go 4.090 ns/op -0.018 ns/op / -0.4% (better)
Windows MSVC ARM64 BenchmarkStringEquality/strings/first/8/LLGo 1.252 ns/op -0.001 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkStringEquality/strings/last/1024/Go 26.320 ns/op -0.04 ns/op / -0.2% (better)
Windows MSVC ARM64 BenchmarkStringEquality/strings/last/1024/LLGo 30.520 ns/op -0.03 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkStringEquality/strings/last/128/Go 4.671 ns/op +0.062 ns/op / +1.3% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/strings/last/128/LLGo 3.846 ns/op +0.068 ns/op / +1.8% (worse)
Windows MSVC ARM64 BenchmarkStringEquality/strings/last/8/Go 4.045 ns/op -0.012 ns/op / -0.3% (better)
Windows MSVC ARM64 BenchmarkStringEquality/strings/last/8/LLGo 1.879 ns/op -0.001 ns/op / -0.1% (better)

Program measurements

Platform Workload File size vs base Text size vs base Build vs base Run vs base
Linux cprintf 8576 B 0 B / +0.0% 387 B 0 B / +0.0% 1.217 s -94.25 ms / -7.2% (better) 1.368 ms -894.8 us / -39.5% (better)
Linux cprintf-lto 8240 B 0 B / +0.0% 368 B 0 B / +0.0% 1.263 s -413.5 ms / -24.7% (better) 1.275 ms -829.9 us / -39.4% (better)
Linux fmtprintf 1943824 B +64 B / +0.003293% (worse) 269976 B 0 B / +0.0% 7.667 s -1.593 s / -17.2% (better) 3.842 ms -1.415 ms / -26.9% (better)
Linux fmtprintf-lto 1019880 B +8 B / +0.0007844% (worse) 210891 B 0 B / +0.0% 17.876 s -3.885 s / -17.9% (better) 4.210 ms -1.789 ms / -29.8% (better)
Linux println 260528 B -128 B / -0.04911% (better) 19172 B 0 B / +0.0% 1.225 s -547.4 ms / -30.9% (better) 1.783 ms -57.48 us / -3.1% (better)
Linux println-lto 102688 B +8 B / +0.007791% (worse) 15652 B 0 B / +0.0% 1.984 s -335.2 ms / -14.5% (better) 1.831 ms -456 us / -19.9% (better)
macOS cprintf 50944 B 0 B / +0.0% 4409 B 0 B / +0.0% 1.147 s -222.3 ms / -16.2% (better) 3.800 ms +662.6 us / +21.1% (worse)
macOS cprintf-lto 50608 B 0 B / +0.0% 161 B 0 B / +0.0% 1.156 s -96.64 ms / -7.7% (better) 3.445 ms -6.959 us / -0.2% (better)
macOS fmtprintf 1233696 B 0 B / +0.0% 676093 B 0 B / +0.0% 5.901 s -733 ms / -11.0% (better) 8.468 ms -1.689 ms / -16.6% (better)
macOS fmtprintf-lto 871600 B 0 B / +0.0% 521789 B 0 B / +0.0% 8.452 s -2.488 s / -22.7% (better) 6.485 ms +117.5 us / +1.8% (worse)
macOS println 100592 B 0 B / +0.0% 26375 B 0 B / +0.0% 1.327 s +74.94 ms / +6.0% (worse) 5.250 ms +92.58 us / +1.8% (worse)
macOS println-lto 85632 B 0 B / +0.0% 22491 B 0 B / +0.0% 1.542 s +12.91 ms / +0.8% (worse) 5.587 ms +39.71 us / +0.7% (worse)
Windows MinGW cprintf 745984 B 0 B / +0.0% 4230 B 0 B / +0.0% 1.957 s -30.29 ms / -1.5% (better) 3.382 ms -152 us / -4.3% (better)
Windows MinGW cprintf-lto 60928 B 0 B / +0.0% 4182 B 0 B / +0.0% 2.166 s +134.3 ms / +6.6% (worse) 3.823 ms +493.2 us / +14.8% (worse)
Windows MinGW fmtprintf 5156864 B 0 B / +0.0% 362134 B 0 B / +0.0% 6.750 s +60.35 ms / +0.9% (worse) 9.562 ms -30.8 us / -0.3% (better)
Windows MinGW fmtprintf-lto 2764288 B 0 B / +0.0% 308102 B 0 B / +0.0% 10.860 s -23.13 ms / -0.2% (better) 9.302 ms +77.9 us / +0.8% (worse)
Windows MinGW println 807936 B 0 B / +0.0% 27414 B 0 B / +0.0% 2.033 s +22.28 ms / +1.1% (worse) 6.389 ms -34.3 us / -0.5% (better)
Windows MinGW println-lto 233984 B 0 B / +0.0% 22598 B 0 B / +0.0% 2.315 s -30.6 ms / -1.3% (better) 6.659 ms +56.1 us / +0.8% (worse)
Windows MinGW 386 cprintf 752128 B 0 B / +0.0% 22726 B 0 B / +0.0% 1.314 s +61.84 ms / +4.9% (worse) 5.635 ms +147 us / +2.7% (worse)
Windows MinGW 386 cprintf-lto 282112 B 0 B / +0.0% 19504 B 0 B / +0.0% 1.472 s +20.3 ms / +1.4% (worse) 5.702 ms +183.1 us / +3.3% (worse)
Windows MinGW 386 fmtprintf 4507648 B 0 B / +0.0% 284864 B 0 B / +0.0% 4.457 s +55.59 ms / +1.3% (worse) 7.561 ms -552.4 us / -6.8% (better)
Windows MinGW 386 fmtprintf-lto 2890752 B 0 B / +0.0% 257486 B 0 B / +0.0% 7.232 s -24.09 ms / -0.3% (better) 7.961 ms +229 us / +3.0% (worse)
Windows MinGW 386 println 751104 B 0 B / +0.0% 22672 B 0 B / +0.0% 1.266 s +8.338 ms / +0.7% (worse) 5.688 ms +41.4 us / +0.7% (worse)
Windows MinGW 386 println-lto 281088 B 0 B / +0.0% 19438 B 0 B / +0.0% 1.454 s +6.814 ms / +0.5% (worse) 5.747 ms +148.1 us / +2.6% (worse)
Windows MinGW ARM64 cprintf 751616 B 0 B / +0.0% 4028 B 0 B / +0.0% 2.209 s -71.99 ms / -3.2% (better) 6.476 ms -489.4 us / -7.0% (better)
Windows MinGW ARM64 cprintf-lto 60416 B 0 B / +0.0% 3984 B 0 B / +0.0% 2.278 s -25.37 ms / -1.1% (better) 6.458 ms -11.8 us / -0.2% (better)
Windows MinGW ARM64 fmtprintf 5096448 B 0 B / +0.0% 302168 B 0 B / +0.0% 6.647 s -30.01 ms / -0.4% (better) 14.176 ms -775.1 us / -5.2% (better)
Windows MinGW ARM64 fmtprintf-lto 2818048 B 0 B / +0.0% 258284 B 0 B / +0.0% 10.080 s -183.4 ms / -1.8% (better) 13.820 ms -797.1 us / -5.5% (better)
Windows MinGW ARM64 println 813056 B 0 B / +0.0% 25604 B 0 B / +0.0% 2.204 s -23.55 ms / -1.1% (better) 11.173 ms -485.3 us / -4.2% (better)
Windows MinGW ARM64 println-lto 237056 B 0 B / +0.0% 21824 B 0 B / +0.0% 2.478 s -69.02 ms / -2.7% (better) 10.686 ms -915.2 us / -7.9% (better)
Windows MSVC cprintf 990720 B 0 B / +0.0% 66003 B 0 B / +0.0% 1.711 s -107.8 ms / -5.9% (better) 4.473 ms +1.123 ms / +33.5% (worse)
Windows MSVC cprintf-lto 308736 B 0 B / +0.0% 65971 B 0 B / +0.0% 1.760 s -38.8 ms / -2.2% (better) 4.124 ms +506.7 us / +14.0% (worse)
Windows MSVC fmtprintf 5455872 B 0 B / +0.0% 458230 B 0 B / +0.0% 5.957 s -125.7 ms / -2.1% (better) 10.717 ms -1.225 ms / -10.3% (better)
Windows MSVC fmtprintf-lto 3087872 B 0 B / +0.0% 406662 B 0 B / +0.0% 9.559 s -208.2 ms / -2.1% (better) 11.160 ms -310.6 us / -2.7% (better)
Windows MSVC println 1122304 B 0 B / +0.0% 123574 B 0 B / +0.0% 1.725 s -38.26 ms / -2.2% (better) 8.419 ms +1.086 ms / +14.8% (worse)
Windows MSVC println-lto 553984 B 0 B / +0.0% 119414 B 0 B / +0.0% 2.006 s -18.4 ms / -0.9% (better) 8.057 ms +376.6 us / +4.9% (worse)
Windows MSVC 386 cprintf 661504 B 0 B / +0.0% 21378 B 0 B / +0.0% 1.625 s -34.88 ms / -2.1% (better) 7.107 ms -1.949 ms / -21.5% (better)
Windows MSVC 386 cprintf-lto 221184 B 0 B / +0.0% 18857 B 0 B / +0.0% 1.677 s -213.5 ms / -11.3% (better) 7.308 ms -698.8 us / -8.7% (better)
Windows MSVC 386 fmtprintf 4235264 B 0 B / +0.0% 268326 B 0 B / +0.0% 5.215 s -427.6 ms / -7.6% (better) 9.780 ms -1.742 ms / -15.1% (better)
Windows MSVC 386 fmtprintf-lto 2704384 B 0 B / +0.0% 236961 B 0 B / +0.0% 8.369 s -657.4 ms / -7.3% (better) 9.579 ms -1.934 ms / -16.8% (better)
Windows MSVC 386 println 658432 B 0 B / +0.0% 21308 B 0 B / +0.0% 1.440 s -246.4 ms / -14.6% (better) 7.188 ms -2.122 ms / -22.8% (better)
Windows MSVC 386 println-lto 219648 B 0 B / +0.0% 18787 B 0 B / +0.0% 1.661 s -187.8 ms / -10.2% (better) 7.313 ms -1.851 ms / -20.2% (better)
Windows MSVC ARM64 cprintf 754688 B 0 B / +0.0% 4240 B 0 B / +0.0% 1.365 s +23.58 ms / +1.8% (worse) 4.662 ms -119.1 us / -2.5% (better)
Windows MSVC ARM64 cprintf-lto 66048 B 0 B / +0.0% 4140 B 0 B / +0.0% 1.406 s +54.47 ms / +4.0% (worse) 4.666 ms -11.8 us / -0.3% (better)
Windows MSVC ARM64 fmtprintf 5092352 B 0 B / +0.0% 302492 B 0 B / +0.0% 4.561 s +25.43 ms / +0.6% (worse) 10.290 ms -927.6 us / -8.3% (better)
Windows MSVC ARM64 fmtprintf-lto 2826752 B 0 B / +0.0% 259232 B 0 B / +0.0% 6.667 s -202.8 ms / -3.0% (better) 10.918 ms -344.9 us / -3.1% (better)
Windows MSVC ARM64 println 815616 B 0 B / +0.0% 26084 B 0 B / +0.0% 1.415 s +38.84 ms / +2.8% (worse) 8.446 ms -43.7 us / -0.5% (better)
Windows MSVC ARM64 println-lto 243200 B 0 B / +0.0% 22384 B 0 B / +0.0% 1.567 s +32.95 ms / +2.1% (worse) 8.444 ms +179.6 us / +2.2% (worse)
Core language and compiler benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkLookupPCRandom 14.440 ns/op -0.27 ns/op / -1.8% (better)
Linux BenchmarkMergeCompilerFlags 226.500 ns/op +22.8 ns/op / +11.2% (worse)
Linux BenchmarkMergeLinkerFlags 147.500 ns/op +9.2 ns/op / +6.7% (worse)
Linux BenchmarkChannelBuffered 72.050 ns/op -0.63 ns/op / -0.9% (better)
Linux BenchmarkChannelHandoff 14371 ns/op +683 ns/op / +5.0% (worse)
Linux BenchmarkDefer 16.680 ns/op -0.59 ns/op / -3.4% (better)
Linux BenchmarkDirectCall 1.595 ns/op +0.036 ns/op / +2.3% (worse)
Linux BenchmarkGlobalRead 1.186 ns/op +0.015 ns/op / +1.3% (worse)
Linux BenchmarkGlobalWrite 7.952 ns/op +0.147 ns/op / +1.9% (worse)
Linux BenchmarkGoroutine 33634 ns/op +9057 ns/op / +36.9% (worse)
Linux BenchmarkInterfaceCall 5.374 ns/op +0.288 ns/op / +5.7% (worse)
Linux BenchmarkRuntimeGetG 2.521 ns/op +0.066 ns/op / +2.7% (worse)
macOS BenchmarkLookupPCRandom 14.270 ns/op -3.38 ns/op / -19.2% (better)
macOS BenchmarkMergeCompilerFlags 137.300 ns/op -15.7 ns/op / -10.3% (better)
macOS BenchmarkMergeLinkerFlags 87.950 ns/op -12.65 ns/op / -12.6% (better)
macOS BenchmarkChannelBuffered 31.770 ns/op +1.88 ns/op / +6.3% (worse)
macOS BenchmarkChannelHandoff 8372 ns/op +340 ns/op / +4.2% (worse)
macOS BenchmarkDefer 12.360 ns/op +0.18 ns/op / +1.5% (worse)
macOS BenchmarkDirectCall 1.119 ns/op -0.06 ns/op / -5.1% (better)
macOS BenchmarkGlobalRead 1.130 ns/op -0.138 ns/op / -10.9% (better)
macOS BenchmarkGlobalWrite 1.146 ns/op -0.067 ns/op / -5.5% (better)
macOS BenchmarkGoroutine 81624 ns/op -6498 ns/op / -7.4% (better)
macOS BenchmarkInterfaceCall 4.705 ns/op +0.184 ns/op / +4.1% (worse)
macOS BenchmarkRuntimeGetG 2.199 ns/op -0.477 ns/op / -17.8% (better)
Windows MinGW BenchmarkLookupPCRandom 13.200 ns/op +0.13 ns/op / +1.0% (worse)
Windows MinGW BenchmarkMergeCompilerFlags 616.500 ns/op -3.4 ns/op / -0.5% (better)
Windows MinGW BenchmarkMergeLinkerFlags 546.300 ns/op +32 ns/op / +6.2% (worse)
Windows MinGW BenchmarkChannelBuffered 35.960 ns/op +0.13 ns/op / +0.4% (worse)
Windows MinGW BenchmarkChannelHandoff 609.100 ns/op +59.1 ns/op / +10.7% (worse)
Windows MinGW BenchmarkDefer 14.860 ns/op +0.67 ns/op / +4.7% (worse)
Windows MinGW BenchmarkDirectCall 1.548 ns/op 0 ns/op / +0.0%
Windows MinGW BenchmarkGlobalRead 1.548 ns/op -0.003 ns/op / -0.2% (better)
Windows MinGW BenchmarkGlobalWrite 2.473 ns/op +0.006 ns/op / +0.2% (worse)
Windows MinGW BenchmarkGoroutine 94805 ns/op +907 ns/op / +1.0% (worse)
Windows MinGW BenchmarkInterfaceCall 7.445 ns/op -0.014 ns/op / -0.2% (better)
Windows MinGW BenchmarkRuntimeGetG 1.862 ns/op +0.003 ns/op / +0.2% (worse)
Windows MinGW 386 BenchmarkLookupPCRandom 15.580 ns/op -0.56 ns/op / -3.5% (better)
Windows MinGW 386 BenchmarkMergeCompilerFlags 389.300 ns/op +2.2 ns/op / +0.6% (worse)
Windows MinGW 386 BenchmarkMergeLinkerFlags 377.500 ns/op -4.1 ns/op / -1.1% (better)
Windows MinGW 386 BenchmarkChannelBuffered 50.040 ns/op +1.9 ns/op / +3.9% (worse)
Windows MinGW 386 BenchmarkChannelHandoff 720.400 ns/op +134.8 ns/op / +23.0% (worse)
Windows MinGW 386 BenchmarkDefer 8.863 ns/op +0.312 ns/op / +3.6% (worse)
Windows MinGW 386 BenchmarkDirectCall 0.951 ns/op -0.0071 ns/op / -0.7% (better)
Windows MinGW 386 BenchmarkGlobalRead 0.961 ns/op +0.0053 ns/op / +0.6% (worse)
Windows MinGW 386 BenchmarkGlobalWrite 8.655 ns/op +0.21 ns/op / +2.5% (worse)
Windows MinGW 386 BenchmarkGoroutine 57268 ns/op +226 ns/op / +0.4% (worse)
Windows MinGW 386 BenchmarkInterfaceCall 4.041 ns/op +0.235 ns/op / +6.2% (worse)
Windows MinGW 386 BenchmarkRuntimeGetG 1.023 ns/op +0.011 ns/op / +1.1% (worse)
Windows MinGW ARM64 BenchmarkLookupPCRandom 12.130 ns/op -0.02 ns/op / -0.2% (better)
Windows MinGW ARM64 BenchmarkMergeCompilerFlags 582.600 ns/op -32 ns/op / -5.2% (better)
Windows MinGW ARM64 BenchmarkMergeLinkerFlags 538.800 ns/op -28 ns/op / -4.9% (better)
Windows MinGW ARM64 BenchmarkChannelBuffered 43.010 ns/op 0 ns/op / +0.0%
Windows MinGW ARM64 BenchmarkChannelHandoff 1885 ns/op +62 ns/op / +3.4% (worse)
Windows MinGW ARM64 BenchmarkDefer 12.280 ns/op +0.47 ns/op / +4.0% (worse)
Windows MinGW ARM64 BenchmarkDirectCall 0.590 ns/op -0.0002 ns/op / -0.03392% (better)
Windows MinGW ARM64 BenchmarkGlobalRead 0.663 ns/op +0.0001 ns/op / +0.01508% (worse)
Windows MinGW ARM64 BenchmarkGlobalWrite 0.663 ns/op -0.0003 ns/op / -0.04522% (better)
Windows MinGW ARM64 BenchmarkGoroutine 59591 ns/op -4767 ns/op / -7.4% (better)
Windows MinGW ARM64 BenchmarkInterfaceCall 3.847 ns/op 0 ns/op / +0.0%
Windows MinGW ARM64 BenchmarkRuntimeGetG 1.769 ns/op -0.034 ns/op / -1.9% (better)
Windows MSVC BenchmarkLookupPCRandom 9.839 ns/op -0.491 ns/op / -4.8% (better)
Windows MSVC BenchmarkMergeCompilerFlags 507.300 ns/op -25.8 ns/op / -4.8% (better)
Windows MSVC BenchmarkMergeLinkerFlags 442.700 ns/op -20.8 ns/op / -4.5% (better)
Windows MSVC BenchmarkChannelBuffered 49.410 ns/op -1.38 ns/op / -2.7% (better)
Windows MSVC BenchmarkChannelHandoff 1545 ns/op +134 ns/op / +9.5% (worse)
Windows MSVC BenchmarkDefer 11.260 ns/op -0.02 ns/op / -0.2% (better)
Windows MSVC BenchmarkDirectCall 0.935 ns/op -0.018 ns/op / -1.9% (better)
Windows MSVC BenchmarkGlobalRead 1.143 ns/op -0.007 ns/op / -0.6% (better)
Windows MSVC BenchmarkGlobalWrite 7.256 ns/op -0.183 ns/op / -2.5% (better)
Windows MSVC BenchmarkGoroutine 67585 ns/op -8290 ns/op / -10.9% (better)
Windows MSVC BenchmarkInterfaceCall 4.805 ns/op -0.059 ns/op / -1.2% (better)
Windows MSVC BenchmarkRuntimeGetG 1.372 ns/op -0.053 ns/op / -3.7% (better)
Windows MSVC 386 BenchmarkLookupPCRandom 21.620 ns/op +0.05 ns/op / +0.2% (worse)
Windows MSVC 386 BenchmarkMergeCompilerFlags 562.800 ns/op +9 ns/op / +1.6% (worse)
Windows MSVC 386 BenchmarkMergeLinkerFlags 521.200 ns/op +2.3 ns/op / +0.4% (worse)
Windows MSVC 386 BenchmarkChannelBuffered 36.660 ns/op -0.03 ns/op / -0.1% (better)
Windows MSVC 386 BenchmarkChannelHandoff 649.500 ns/op +12.6 ns/op / +2.0% (worse)
Windows MSVC 386 BenchmarkDefer 14.120 ns/op +0.02 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkDirectCall 1.357 ns/op 0 ns/op / +0.0%
Windows MSVC 386 BenchmarkGlobalRead 1.631 ns/op +0.001 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkGlobalWrite 6.986 ns/op -0.002 ns/op / -0.02862% (better)
Windows MSVC 386 BenchmarkGoroutine 72920 ns/op +195 ns/op / +0.3% (worse)
Windows MSVC 386 BenchmarkInterfaceCall 6.525 ns/op +0.008 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkRuntimeGetG 1.633 ns/op +0.002 ns/op / +0.1% (worse)
Windows MSVC ARM64 BenchmarkLookupPCRandom 8.882 ns/op -0.005 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkMergeCompilerFlags 446.300 ns/op -16.7 ns/op / -3.6% (better)
Windows MSVC ARM64 BenchmarkMergeLinkerFlags 432.800 ns/op -9.6 ns/op / -2.2% (better)
Windows MSVC ARM64 BenchmarkChannelBuffered 48.660 ns/op -0.96 ns/op / -1.9% (better)
Windows MSVC ARM64 BenchmarkChannelHandoff 1404 ns/op +25 ns/op / +1.8% (worse)
Windows MSVC ARM64 BenchmarkDefer 10.480 ns/op +1.153 ns/op / +12.4% (worse)
Windows MSVC ARM64 BenchmarkDirectCall 0.626 ns/op +0.0002 ns/op / +0.03194% (worse)
Windows MSVC ARM64 BenchmarkGlobalRead 0.626 ns/op -0.0001 ns/op / -0.01596% (better)
Windows MSVC ARM64 BenchmarkGlobalWrite 3.986 ns/op -0.01 ns/op / -0.3% (better)
Windows MSVC ARM64 BenchmarkGoroutine 37368 ns/op +402 ns/op / +1.1% (worse)
Windows MSVC ARM64 BenchmarkInterfaceCall 3.170 ns/op -0.001 ns/op / -0.03154% (better)
Windows MSVC ARM64 BenchmarkRuntimeGetG 1.895 ns/op -0.005 ns/op / -0.3% (better)
Timer runtime benchmarks
Platform Operation and runtime ns/op vs base
Linux AfterFuncZeroDelivery/Go 991.300 ns/op +71.4 ns/op / +7.8% (worse)
Linux AfterFuncZeroDelivery/LLGo 45554 ns/op +4737 ns/op / +11.6% (worse)
Linux CreateStop/Go 302.200 ns/op -1.9 ns/op / -0.6% (better)
Linux CreateStop/LLGo 1377 ns/op -876 ns/op / -38.9% (better)
Linux RearmStopped/Go 115.700 ns/op -1.5 ns/op / -1.3% (better)
Linux RearmStopped/LLGo 1020 ns/op +37.1 ns/op / +3.8% (worse)
Linux ResetActive/Go 67.590 ns/op -1.45 ns/op / -2.1% (better)
Linux ResetActive/LLGo 661.400 ns/op +62.5 ns/op / +10.4% (worse)
Linux ResetHeap1024/Go 71.750 ns/op +3.83 ns/op / +5.6% (worse)
Linux ResetHeap1024/LLGo 133.600 ns/op -90.1 ns/op / -40.3% (better)
macOS AfterFuncZeroDelivery/Go 540.200 ns/op -190.6 ns/op / -26.1% (better)
macOS AfterFuncZeroDelivery/LLGo 71333 ns/op +572 ns/op / +0.8% (worse)
macOS CreateStop/Go 146.200 ns/op -42 ns/op / -22.3% (better)
macOS CreateStop/LLGo 454.900 ns/op -564.1 ns/op / -55.4% (better)
macOS RearmStopped/Go 63.560 ns/op -16.01 ns/op / -20.1% (better)
macOS RearmStopped/LLGo 225.200 ns/op -138.2 ns/op / -38.0% (better)
macOS ResetActive/Go 48.440 ns/op -8.63 ns/op / -15.1% (better)
macOS ResetActive/LLGo 130.900 ns/op -64 ns/op / -32.8% (better)
macOS ResetHeap1024/Go 47.500 ns/op -11.76 ns/op / -19.8% (better)
macOS ResetHeap1024/LLGo 74.510 ns/op -63.19 ns/op / -45.9% (better)
Windows MinGW AfterFuncZeroDelivery/Go 582.100 ns/op +32.2 ns/op / +5.9% (worse)
Windows MinGW AfterFuncZeroDelivery/LLGo 185575 ns/op +2970 ns/op / +1.6% (worse)
Windows MinGW CreateStop/Go 116.500 ns/op +0.3 ns/op / +0.3% (worse)
Windows MinGW CreateStop/LLGo 676.500 ns/op -15.5 ns/op / -2.2% (better)
Windows MinGW RearmStopped/Go 31.410 ns/op -0.23 ns/op / -0.7% (better)
Windows MinGW RearmStopped/LLGo 207.400 ns/op -16.1 ns/op / -7.2% (better)
Windows MinGW ResetActive/Go 19.980 ns/op -0.13 ns/op / -0.6% (better)
Windows MinGW ResetActive/LLGo 177.700 ns/op -47.1 ns/op / -21.0% (better)
Windows MinGW ResetHeap1024/Go 20.460 ns/op -0.04 ns/op / -0.2% (better)
Windows MinGW ResetHeap1024/LLGo 104.400 ns/op +1.5 ns/op / +1.5% (worse)
Windows MinGW 386 AfterFuncZeroDelivery/Go 624.900 ns/op -16 ns/op / -2.5% (better)
Windows MinGW 386 AfterFuncZeroDelivery/LLGo 105242 ns/op -4270 ns/op / -3.9% (better)
Windows MinGW 386 CreateStop/Go 163.500 ns/op -0.5 ns/op / -0.3% (better)
Windows MinGW 386 CreateStop/LLGo 489.800 ns/op +52.2 ns/op / +11.9% (worse)
Windows MinGW 386 RearmStopped/Go 63.250 ns/op +0.38 ns/op / +0.6% (worse)
Windows MinGW 386 RearmStopped/LLGo 292.400 ns/op -113.8 ns/op / -28.0% (better)
Windows MinGW 386 ResetActive/Go 30.180 ns/op +0.08 ns/op / +0.3% (worse)
Windows MinGW 386 ResetActive/LLGo 781.600 ns/op +17.5 ns/op / +2.3% (worse)
Windows MinGW 386 ResetHeap1024/Go 29.700 ns/op -0.54 ns/op / -1.8% (better)
Windows MinGW 386 ResetHeap1024/LLGo 97.610 ns/op -1.61 ns/op / -1.6% (better)
Windows MinGW ARM64 AfterFuncZeroDelivery/Go 665.500 ns/op +6.5 ns/op / +1.0% (worse)
Windows MinGW ARM64 AfterFuncZeroDelivery/LLGo 145478 ns/op -2648 ns/op / -1.8% (better)
Windows MinGW ARM64 CreateStop/Go 194.300 ns/op -4 ns/op / -2.0% (better)
Windows MinGW ARM64 CreateStop/LLGo 426 ns/op +7.5 ns/op / +1.8% (worse)
Windows MinGW ARM64 RearmStopped/Go 70.570 ns/op -0.02 ns/op / -0.02833% (better)
Windows MinGW ARM64 RearmStopped/LLGo 167.600 ns/op -12.4 ns/op / -6.9% (better)
Windows MinGW ARM64 ResetActive/Go 31 ns/op -0.04 ns/op / -0.1% (better)
Windows MinGW ARM64 ResetActive/LLGo 101.100 ns/op -0.7 ns/op / -0.7% (better)
Windows MinGW ARM64 ResetHeap1024/Go 31.070 ns/op -0.03 ns/op / -0.1% (better)
Windows MinGW ARM64 ResetHeap1024/LLGo 92.470 ns/op +0.11 ns/op / +0.1% (worse)
Windows MSVC AfterFuncZeroDelivery/Go 596.100 ns/op -36.2 ns/op / -5.7% (better)
Windows MSVC AfterFuncZeroDelivery/LLGo 137195 ns/op -7994 ns/op / -5.5% (better)
Windows MSVC CreateStop/Go 161.200 ns/op -12.8 ns/op / -7.4% (better)
Windows MSVC CreateStop/LLGo 587.300 ns/op -172.6 ns/op / -22.7% (better)
Windows MSVC RearmStopped/Go 59.840 ns/op -3.57 ns/op / -5.6% (better)
Windows MSVC RearmStopped/LLGo 214.600 ns/op -3.7 ns/op / -1.7% (better)
Windows MSVC ResetActive/Go 26.510 ns/op -2.25 ns/op / -7.8% (better)
Windows MSVC ResetActive/LLGo 625.100 ns/op +79.1 ns/op / +14.5% (worse)
Windows MSVC ResetHeap1024/Go 27.030 ns/op -1.41 ns/op / -5.0% (better)
Windows MSVC ResetHeap1024/LLGo 86.450 ns/op -2.3 ns/op / -2.6% (better)
Windows MSVC 386 AfterFuncZeroDelivery/Go 778.400 ns/op +14 ns/op / +1.8% (worse)
Windows MSVC 386 AfterFuncZeroDelivery/LLGo 133328 ns/op -1581 ns/op / -1.2% (better)
Windows MSVC 386 CreateStop/Go 169.300 ns/op +0.5 ns/op / +0.3% (worse)
Windows MSVC 386 CreateStop/LLGo 354 ns/op -16.8 ns/op / -4.5% (better)
Windows MSVC 386 RearmStopped/Go 56.830 ns/op +0.05 ns/op / +0.1% (worse)
Windows MSVC 386 RearmStopped/LLGo 315.400 ns/op +57.3 ns/op / +22.2% (worse)
Windows MSVC 386 ResetActive/Go 32.640 ns/op +0.06 ns/op / +0.2% (worse)
Windows MSVC 386 ResetActive/LLGo 857 ns/op -0.9 ns/op / -0.1% (better)
Windows MSVC 386 ResetHeap1024/Go 32.810 ns/op -0.01 ns/op / -0.03047% (better)
Windows MSVC 386 ResetHeap1024/LLGo 122.500 ns/op -0.9 ns/op / -0.7% (better)
Windows MSVC ARM64 AfterFuncZeroDelivery/Go 625.300 ns/op -18.8 ns/op / -2.9% (better)
Windows MSVC ARM64 AfterFuncZeroDelivery/LLGo 84744 ns/op +3594 ns/op / +4.4% (worse)
Windows MSVC ARM64 CreateStop/Go 182.600 ns/op -2.6 ns/op / -1.4% (better)
Windows MSVC ARM64 CreateStop/LLGo 290.400 ns/op +4.2 ns/op / +1.5% (worse)
Windows MSVC ARM64 RearmStopped/Go 72.620 ns/op -0.05 ns/op / -0.1% (better)
Windows MSVC ARM64 RearmStopped/LLGo 158.300 ns/op -6.1 ns/op / -3.7% (better)
Windows MSVC ARM64 ResetActive/Go 33.670 ns/op 0 ns/op / +0.0%
Windows MSVC ARM64 ResetActive/LLGo 110.300 ns/op -23.3 ns/op / -17.4% (better)
Windows MSVC ARM64 ResetHeap1024/Go 33.410 ns/op -0.01 ns/op / -0.02992% (better)
Windows MSVC ARM64 ResetHeap1024/LLGo 90.080 ns/op -0.12 ns/op / -0.1% (better)

Compared with 717fbe4429cb measured in the same runner job.

@zhouguangyuan0718 zhouguangyuan0718 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Two non-blocking maintainability suggestions for the native tail bridge.

Comment thread internal/plan9asm/native_tail.go Resolved
Comment thread internal/plan9asm/native_tail.go Resolved
@cpunion
cpunion force-pushed the fix/2921-arm64-native-tail-bridge branch from 3454e45 to f77c9fd Compare November 11, 2026 01:33
@cpunion

cpunion commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator Author

@fennoai Addressed both new maintainability comments in f77c9fd and rebased onto current main. Split bridge validation/emission/LLVM replacement and isolated the emitter-format contract with real Darwin/Linux and rejection tests. Full plan9asm and ordinary/full-LTO/nogc native execution probes pass. Please re-review.

@fennoai

fennoai Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

All prior-approved invariants are intact after the rebase, and the mirror-helper test still passes. The only new content in this round is the f77c9fdb4 refactor, which I've verified is behavior-preserving plus a net safety improvement (new len < 2 guard and the emitter-format contract).

Everything checks out. Let me deliver the re-review as my final message (managed mode — no publishing).


Re-review: f77c9fdb4 — "plan9asm: separate native tail bridge stages" (+ rebase onto current main)

The PR was rebased onto current main (new base e2cca2c); the five previously-reviewed commits came along unchanged, and one new commit sits on top. I diffed the new commit against its parent and spot-checked that the rebase preserved everything I'd already approved. Only native_tail.go (+117/−36) and its test (+32) changed in the new work.

What the refactor does

lowerNativeTailTransfer is split into three focused stages, which reads much better:

  • validateNativeTailTransfer → all ABI/guard checks, returns the tail register.
  • emitNativeTailAssembly → builds the bridge source and runs the native emitter.
  • replaceNativeTailEntry → the LLVM function-replacement + inline-asm construction.
  • adaptNativeTailAssembly → isolated emitter-output-format contract.

Behavior preservation — verified

  • The ABI0 FP-access / stackTouched state machine moved from emission into validation. I checked the ordering carefully: within each instruction's arg loop, the FP-reject check still reads stackTouched before the same-instruction stackTouched = true assignment, and the pseudo-SP MatchString check stays at the top of the instruction loop — identical semantics to the pre-split code. Emission now walks the already-validated range without re-checking, which is sound. ✅
  • All error strings/guards are preserved verbatim (reg > 28 || reg == 18, the zero-frame/argc≤8 guard, malformed TEXT directive, NOSPLIT|NOFRAME, per-arg slot checks). ✅
  • New safety guard: if len(fn.Instrs) < 2 up front closes a latent out-of-range on the fn.Instrs[1:len-1] slice / Instrs[len-1] access for a degenerate single-instruction function. Good hardening. ✅

New emitter-format contract (adaptNativeTailAssembly) — the substantive addition

Instead of silently stripping a hardcoded set of object directives, it now rejects anything outside the supported text contract: it requires exactly one Lnative_func_0 entry label, allows only .text / .section .note.GNU-stack / .type|.size Lnative_func_0, / .p2align 2 / blank lines, rejects any other .-directive, and rejects labels not matching the Lnative_* family (including empty :). This converts "emitter changed its output shape" from a potential silent mis-embed into a loud build error — a good defensive move against an external dependency.

I confirmed it doesn't over-reject: TestNativeTailEmitterContract runs the real asm.TranslateNativeSource for both darwin and linux and asserts the live output passes adaptNativeTailAssembly (keeps .p2align 2, uniquifies labels with ${:uid}, strips object directives), alongside negative cases (missing/duplicate/mis-indexed entry label, unknown label, empty label, unexpected .section/.globl) and the $→$$ escaping. Strong, targeted coverage. ✅

Rebase integrity

Spot-checked that the earlier commits' logic survived intact in the final tree: BDWGC wrapping + GC_do_blocking, the binder IsDeclaration() filter, attribute/callconv forwarding (AddCallSiteAttribute/SetInstructionCallConv), the reg > 28 bound, the Darwin-only x18 exclusion, and the mirror priority: fix are all present. File is gofmt-clean and parses; the pure-Python mirror test still passes locally.

Note on local verification

As before, I can't run the Go build/tests here (missing LLVM C headers); I verified by reading the diff, tracing the moved state machine, and checking the new test's assertions. I'm relying on your report that the full plan9asm suite and the ordinary/full-LTO/nogc native execution probes pass.

Verdict: Clean structural split that preserves behavior, adds a sensible out-of-range guard, and hardens the emitter-format boundary with real cross-OS + rejection tests. No new issues. LGTM — this has been a thorough, well-tested iteration cycle and the change looks ready from my side.

View task

@cpunion
cpunion merged commit 14691d8 into xgo-dev:main Nov 12, 2026
172 of 174 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

Development

Successfully merging this pull request may close these issues.

darwin/arm64: wazero native backend faults on first call after runtime hook fix

2 participants