Assisted-by: GLM 5.3 Flash
This commit is contained in:
+122
-14
@@ -5,6 +5,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build/constraint"
|
||||
"maps"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -476,8 +477,10 @@ type corpusStats struct {
|
||||
root string
|
||||
files int
|
||||
generic int // files attempted for all four architectures
|
||||
narrowed int // files whose //go:build admits a proper subset of the four
|
||||
excluded int // files whose //go:build admits none of the four: never compiled
|
||||
otherPort int // files named for another Go port: never attempted
|
||||
full int // files that assembled for every target architecture
|
||||
full int // files that assembled for every applicable target architecture
|
||||
targets []corpusTarget
|
||||
tallies []*corpusTally
|
||||
}
|
||||
@@ -573,6 +576,57 @@ func otherGOOSFile(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// buildConstraint returns the file's leading //go:build expression, or nil
|
||||
// when the file carries none. The constraint governs the same header block
|
||||
// go/build reads: blank lines and comments may precede it, and the first
|
||||
// line that is neither ends the block. A constraint that does not parse
|
||||
// narrows nothing, so the file stays in the attempted set: the audit must
|
||||
// never exclude a file the toolchain would compile.
|
||||
func buildConstraint(src string) constraint.Expr {
|
||||
for line := range strings.SplitSeq(src, "\n") {
|
||||
t := strings.TrimSpace(line)
|
||||
switch {
|
||||
case t == "":
|
||||
continue
|
||||
case strings.HasPrefix(t, "//"):
|
||||
if constraint.IsGoBuild(t) {
|
||||
e, err := constraint.Parse(t)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return e
|
||||
}
|
||||
continue
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// unixOS is go/build's unixOS set: the GOOSes the unix build tag admits.
|
||||
var unixOS = map[string]bool{
|
||||
"aix": true, "android": true, "darwin": true, "dragonfly": true,
|
||||
"freebsd": true, "hurd": true, "illumos": true, "ios": true,
|
||||
"linux": true, "netbsd": true, "openbsd": true, "solaris": true,
|
||||
}
|
||||
|
||||
// constraintTags answers the build tags a plain `go build` sets for a
|
||||
// target: the GOOS and GOARCH, gc, and unix on the unix-like GOOSes. No
|
||||
// experiment, sanitiser or cgo tag is ever true: the audit models the
|
||||
// default build, and no GOROOT assembly file's constraint hinges on cgo.
|
||||
func constraintTags(goarch, goos string) func(string) bool {
|
||||
return func(tag string) bool {
|
||||
switch tag {
|
||||
case goarch, goos, "gc":
|
||||
return true
|
||||
case "unix":
|
||||
return unixOS[goos]
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func runCorpusAudit(root string, dirs includeDirs) (*corpusStats, error) {
|
||||
files, err := asmFiles(root)
|
||||
if err != nil {
|
||||
@@ -590,8 +644,8 @@ func runCorpusAudit(root string, dirs includeDirs) (*corpusStats, error) {
|
||||
tallies[i] = &corpusTally{reasons: map[string]int{}, example: map[string]string{}}
|
||||
}
|
||||
// full is the north-star number: a file counts when every architecture
|
||||
// its name allows assembles it.
|
||||
full, generic, otherPort := 0, 0, 0
|
||||
// its build admits assembles it.
|
||||
full, generic, otherPort, narrowedCount, excluded := 0, 0, 0, 0, 0
|
||||
|
||||
// Header generation is created on first use, so a corpus with no
|
||||
// go_asm.h includes never pays for a temp directory.
|
||||
@@ -614,28 +668,78 @@ func runCorpusAudit(root string, dirs includeDirs) (*corpusStats, error) {
|
||||
// invisible to a file-name rule).
|
||||
goos := goosFromFilename(path)
|
||||
|
||||
// The GOOS the header generation type-checks under follows the
|
||||
// file's name when the name carries one; the ambient GOOS is the
|
||||
// honest guess otherwise.
|
||||
namedArch := arch.FromFilename(path)
|
||||
var wanted []int // indexes into targets
|
||||
if a := arch.FromFilename(path); a != arch.Unknown {
|
||||
other := false
|
||||
switch {
|
||||
case namedArch != arch.Unknown:
|
||||
for i, tg := range targets {
|
||||
if tg.a == a {
|
||||
if tg.a == namedArch {
|
||||
wanted = append(wanted, i)
|
||||
}
|
||||
}
|
||||
} else if otherPortFile(path) {
|
||||
case otherPortFile(path):
|
||||
// A file named for a Go port gasm does not support (arm,
|
||||
// 386, s390x, ...) or for another GOOS is compiled by no
|
||||
// supported-arch build, so it is neither generic nor a
|
||||
// per-arch attempt: counting it as generic would make the
|
||||
// headline unreachably low for reasons no supported target
|
||||
// can fix.
|
||||
other = true
|
||||
otherPort++
|
||||
} else {
|
||||
generic++
|
||||
default:
|
||||
for i := range targets {
|
||||
wanted = append(wanted, i)
|
||||
}
|
||||
}
|
||||
|
||||
// A //go:build constraint narrows the set of targets the file is
|
||||
// assembled for, the way the go command compiles the file only for
|
||||
// the targets the expression admits: cpu_x86.s belongs to the x86
|
||||
// build alone, and a file whose constraint admits none of the four
|
||||
// targets (the goexperiment.runtimesecret and msan trees) is
|
||||
// compiled by no supported build. The tags mirror what a plain
|
||||
// `go build` sets: the GOOS and GOARCH, gc, and unix on the
|
||||
// unix-like GOOSes; no experiment, sanitiser or cgo tag is ever
|
||||
// true. The GOOS is the file's own when the name carries one,
|
||||
// else the ambient one.
|
||||
goosForEval := goos
|
||||
if goosForEval == "" {
|
||||
goosForEval = runtime.GOOS
|
||||
}
|
||||
narrowed := false
|
||||
if len(wanted) > 0 {
|
||||
if ce := buildConstraint(src); ce != nil {
|
||||
kept := make([]int, 0, len(wanted))
|
||||
for _, i := range wanted {
|
||||
tg := targets[i]
|
||||
if ce.Eval(constraintTags(goarchName(tg.a), goosForEval)) {
|
||||
kept = append(kept, i)
|
||||
}
|
||||
}
|
||||
if len(kept) < len(wanted) {
|
||||
narrowed = true
|
||||
}
|
||||
wanted = kept
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case other:
|
||||
// already tallied above
|
||||
case len(wanted) == 0:
|
||||
excluded++
|
||||
case namedArch != arch.Unknown:
|
||||
// a per-arch attempt over the constraint's subset
|
||||
case narrowed:
|
||||
narrowedCount++
|
||||
default:
|
||||
generic++
|
||||
}
|
||||
|
||||
// A file that includes go_asm.h parses against a per-target header:
|
||||
// the defines differ per architecture (internal/cpu's layout, for
|
||||
// one) and per GOOS (sys_darwin_arm64.s's trampoline constants,
|
||||
@@ -719,6 +823,8 @@ func runCorpusAudit(root string, dirs includeDirs) (*corpusStats, error) {
|
||||
root: root,
|
||||
files: len(files),
|
||||
generic: generic,
|
||||
narrowed: narrowedCount,
|
||||
excluded: excluded,
|
||||
otherPort: otherPort,
|
||||
full: full,
|
||||
targets: targets,
|
||||
@@ -728,13 +834,15 @@ func runCorpusAudit(root string, dirs includeDirs) (*corpusStats, error) {
|
||||
|
||||
// printCorpusStats renders the corpus audit report.
|
||||
func printCorpusStats(s *corpusStats, list bool) {
|
||||
fmt.Printf("corpus %s: %d files (%d generic, attempted for all architectures; %d named for other Go ports, never attempted)\n", s.root, s.files, s.generic, s.otherPort)
|
||||
fmt.Printf("corpus %s: %d files (%d generic, attempted for all architectures; %d narrowed by //go:build; %d excluded by //go:build; %d named for other Go ports, never attempted)\n",
|
||||
s.root, s.files, s.generic, s.narrowed, s.excluded, s.otherPort)
|
||||
// The rate is over the files a supported build would attempt: the
|
||||
// other ports' files sit in the count for completeness but can never
|
||||
// assemble, so counting them in the denominator would report the gap
|
||||
// of architectures gasm deliberately does not target.
|
||||
attemptable := max(s.files-s.otherPort, 1)
|
||||
fmt.Printf(" assemble for every target architecture: %d of %d attemptable (%.1f%%)\n", s.full, attemptable, 100*float64(s.full)/float64(attemptable))
|
||||
// other ports' files and the ones no supported target compiles sit in
|
||||
// the count for completeness but can never assemble, so counting them
|
||||
// in the denominator would report the gap of platforms gasm
|
||||
// deliberately does not target.
|
||||
attemptable := max(s.files-s.otherPort-s.excluded, 1)
|
||||
fmt.Printf(" assemble for every applicable target: %d of %d attemptable (%.1f%%)\n", s.full, attemptable, 100*float64(s.full)/float64(attemptable))
|
||||
for i, tg := range s.targets {
|
||||
t := s.tallies[i]
|
||||
fmt.Printf(" %s: %d/%d attempted\n", tg.name, t.assembled, t.attempted)
|
||||
|
||||
Reference in New Issue
Block a user