// Copyright 2026 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main import ( "bytes" "fmt" "strings" ) func (m *metrics) report(w *bytes.Buffer) { fmt.Fprintf(w, "SIMD spec transition progress\n\n") fmt.Fprintf(w, "Generated by archsimd/_gen/cmd/specstats; do not edit.\n") fmt.Fprintf(w, "Regenerate with: go run ./cmd/specstats -w\n\n") fmt.Fprintf(w, "Every fraction heads for 100%%; every count heads for zero. Bracketed\n") fmt.Fprintf(w, "names are SPEC-TRANSITION.md tasks that move the figure. Indented,\n") fmt.Fprintf(w, "untagged numbers are context breaking down the figure above them.\n") fmt.Fprintf(w, "String, Len, ToArch, and FromArch are excluded throughout (§2.7).\n") m.summary(w) m.coverage(w) m.signatures(w) m.documentation(w) m.retirement(w) m.disagreement(w) } func (m *metrics) summary(w *bytes.Buffer) { section(w, "Summary", "") note(w, "Heading for 100%:") frac(w, "spec coverage, by (receiver, name) (§1)", m.covPair.result(), "spec-common, spec-all") frac(w, "docs sourced from spec (§3)", m.fromSpec.result(), "gen-docs, comments-yaml, handwritten-fill, template-docs") note(w, "\nHeading for zero:") count(w, "type mismatches with spec (§2)", m.typeOK.result().miss(), "fill-enforce") count(w, "type divergence across targets (§2)", m.typeSame.result().miss(), "fill-enforce") count(w, "spec coverage gaps in defined names (§5)", m.apiOnly, "spec-all, convert-lo, mask-bits") count(w, "hand-written doc conflicts with spec (§3)", m.handConflict, "doc-triage") count(w, "simd mirror drift (§3)", m.mirror.result().miss(), "comments-yaml") count(w, "categories.yaml entries (§4)", m.catEntries, "cat-rehome, compiler-ops-impl, cat-delete") count(w, "midway/comments.yaml entries spec covers (§4)", m.commentsSpecCovered, "comments-yaml, spec-all") } func (m *metrics) coverage(w *bytes.Buffer) { section(w, "1. Spec coverage of API", "spec-common, spec-all") frac(w, "by (target, receiver, name)", m.covTriple.result(), "") frac(w, "by (receiver, name)", m.covPair.result(), "") frac(w, "by name", m.covName.result(), "") note(w, "\nBy build configuration:") for _, bc := range buildConfigs { frac(w, " "+bc.name, m.covTarget.result(bc.name), "") } note(w, "\nBy generator (declarations per tool, counted once per tool per pair):") for _, g := range m.covGen.dims() { if strings.Contains(g, "/") { continue } frac(w, " "+g, m.covGen.result(g), "") } note(w, "\nHigh-drift-risk names (emitted by >1 generator):") frac(w, " covered", m.covMulti.result(), "spec-all") frac(w, " portable core (comments.yaml .common_methods)", m.covCommon.result(), "spec-common") fmt.Fprintf(w, "\n") kv(w, "spec operations written so far", len(m.ops)) kv(w, " expanding to distinct names", m.specNames) kv(w, " expanding to (receiver, name) pairs", m.specPairs) } func (m *metrics) signatures(w *bytes.Buffer) { section(w, "2. Signatures and names", "named-results, fill-enforce") note(w, `Spec/API disagreement, for declarations spec covers. As in specdoc.Fill, a named argument whose name differs from spec's is a mismatch; an unnamed one (or _) is not, and is counted below as a name Fill fills in instead:`) count(w, " type mismatches", m.typeOK.result().miss(), "fill-enforce") count(w, " parameter-name mismatches", m.paramNameOK.result().miss(), "named-results") count(w, " result-name mismatches", m.resultNameOK.result().miss(), "named-results") note(w, "\nNames spec gives that the API leaves unnamed, for declarations spec covers:") count(w, " declarations with unnamed parameters", m.paramsFilled.result().miss(), "named-results") count(w, " declarations with unnamed results", m.resultsFilled.result().miss(), "named-results") note(w, ` API consistency across targets (the "one meaning" invariant), for (receiver, name) pairs declared for more than one target. An unnamed argument agrees with any name:`) count(w, " divergent parameter or result types", m.typeSame.result().miss(), "fill-enforce") count(w, " divergent parameter names", m.paramNameSame.result().miss(), "fill-enforce, spec-all") count(w, " divergent result names", m.resultNameSame.result().miss(), "named-results") } func (m *metrics) documentation(w *bytes.Buffer) { section(w, "3. Documentation", "gen-docs, comments-yaml, handwritten-fill, template-docs") note(w, `A declaration counts as sourced from spec when its doc comment begins with spec's text (a prefix test, because Fill leaves generator notes below).`) frac(w, "covered declarations whose doc comes from spec", m.fromSpec.result(), "gen-docs, comments-yaml, handwritten-fill, template-docs") fmt.Fprintf(w, "\n") frac(w, "simd ∩ archsimd methods with matching docs", m.crossPkg.result(), "gen-docs, comments-yaml") fmt.Fprintf(w, "\n") count(w, "hand-written doc conflicts with spec", m.handConflict, "doc-triage") for _, fc := range m.handConflictByFile { count(w, " "+fc.file, fc.n, "doc-triage") } count(w, "drifted docs in simd mirror (stubs vs emulated)", m.mirror.result().miss(), "comments-yaml") kv(w, " mirrored declarations", m.mirror.result().d) } func (m *metrics) retirement(w *bytes.Buffer) { section(w, "4. Retiring the old inputs", "comments-yaml, cat-rehome, compiler-ops-impl, cat-delete") note(w, `categories.yaml's exported entries are emptied field by field: template-docs removes documentation, cat-rehome removes the rest, sig-from-spec removes commutative, and cat-delete removes the file. Compiler-only entries are handled wholesale by compiler-ops-impl.`) count(w, "categories.yaml entries", m.catEntries, "cat-rehome, compiler-ops-impl, cat-delete") sub(w, "unique operation names", m.catUniq) sub(w, " exported", m.catExported) count(w, "compiler-only categories.yaml entries", m.catCompilerOnly, "compiler-ops-impl") fmt.Fprintf(w, "\n exported entries, by field:\n") for _, k := range sortedKeys(m.catExportedFields) { if k != "go" { tag := "cat-rehome" if k == "commutative" { tag = "sig-from-spec" } countIndented(w, k, m.catExportedFields[k], tag) } } fmt.Fprintf(w, "\n") count(w, "midway/comments.yaml entries spec covers", m.commentsSpecCovered, "comments-yaml, spec-all") fmt.Fprintf(w, "\n") count(w, "commutativity disagreements, spec vs categories.yaml", m.commutDrift, "spec-all") } func (m *metrics) disagreement(w *bytes.Buffer) { section(w, "5. Spec/API coverage disagreement detail", "spec-all, convert-lo, mask-bits") note(w, `Where both sides define a name, receivers only the API declares are spec bugs (a constraint is wrong or a sibling function is missing). Receivers only spec generates are a review queue -- spec is deliberately maximal.`) count(w, "spec misses receivers of a name it defines", m.apiOnly, "spec-all, convert-lo, mask-bits") count(w, " declarations affected, counting each target", m.apiOnlyDecls, "spec-all, convert-lo, mask-bits") count(w, "spec operations implemented nowhere", len(m.specOnly), "spec-all") emptyList(w, len(m.specOnly)) for _, n := range m.specOnly { fmt.Fprintf(w, " %s\n", n) } fmt.Fprintf(w, "\nEvery name either side defines, less the %d spec has never defined at all\n", m.rel[relAPIOnly].names) fmt.Fprintf(w, "(%d receivers, counted as coverage in §1 rather than disagreement):\n\n", m.rel[relAPIOnly].apiOnly) fmt.Fprintf(w, " %-14s %7s %14s %14s\n", "relation", "names", "Σ|api - spec|", "Σ|spec - api|") fmt.Fprintf(w, " %-14s %7s %14s %14s\n", "", "", "(-> 0)", "(review)") var total relTotal for r := relEqual; r <= relSpecOnly; r++ { t := m.rel[r] fmt.Fprintf(w, " %-14s %7d %14d %14d\n", relationName[r], t.names, t.apiOnly, t.specOnly) total.names, total.apiOnly, total.specOnly = total.names+t.names, total.apiOnly+t.apiOnly, total.specOnly+t.specOnly } fmt.Fprintf(w, " %-14s %7d %14d %14d\n", "total", total.names, total.apiOnly, total.specOnly) note(w, "\nNames that disagree, with api - spec receivers (the defects):") fmt.Fprintf(w, " %-26s %-11s %5s %6s %12s %12s\n", "name", "relation", "|api|", "|spec|", "|api - spec|", "|spec - api|") n := 0 for _, r := range m.names { if r.rel == relEqual || r.rel == relAPIOnly { continue } n++ fmt.Fprintf(w, " %-26s %-11s %5d %6d %12d %12d\n", r.name, relationName[r.rel], r.api, r.spec, len(r.apiOnly), r.specOnly) wrap(w, " ", "api - spec = ", r.apiOnly) } emptyList(w, n) }