From 4598a8d3651b3543ea323b9fc6bf8dd954dc3a5d Mon Sep 17 00:00:00 2001 From: thesyncim Date: Sat, 31 Oct 2026 19:08:12 +0000 Subject: [PATCH 1/4] ci: install qemu-user on ubuntu-26.04 runners ubuntu-latest is now ubuntu-26.04, which has no qemu-user-static package, so every run fails at the install step and skips the arm64 tsvc run, the golden check, fmt and lint. qemu-user ships the static emulators there; link qemu-aarch64-static to it when the name is missing, as the Makefile runs that name. --- .github/workflows/test.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ba31cc9..efe0baa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -61,8 +61,13 @@ jobs: - name: Test tsvc (amd64, SIMD) run: make tsvc-test - - name: Install qemu-user-static - run: sudo apt-get update && sudo apt-get install -y qemu-user-static + # ubuntu-26.04 has no qemu-user-static: qemu-user ships the static + # emulators there, without the -static names the Makefile runs. + - name: Install qemu-user + run: | + sudo apt-get update && sudo apt-get install -y qemu-user + command -v qemu-aarch64-static || sudo ln -s "$(command -v qemu-aarch64)" /usr/local/bin/qemu-aarch64-static + qemu-aarch64-static --version - name: Test tsvc (arm64, qemu) run: make tsvc-test-qemu-arm64 From c5557360f5e080f9bdf5ca1c52272089b81b61dd Mon Sep 17 00:00:00 2001 From: thesyncim Date: Sat, 31 Oct 2026 20:49:40 +0000 Subject: [PATCH 2/4] go.mod: update golang.org/x/tools to read Go tip's export data Go tip writes export data in iexport version 4, which encodes float constants exactly. x/tools v0.51.0, and the v0.52.0 release, read only up to version 3, so on tip go/packages fails for every package: cannot import "math" (unstable iexport format version 4, just rebuild compiler and std library), export data is newer version - update tool and every script that runs loopvec fails in the tip job. x/tools master reads version 4 (golang/tools@966056e2637c). Update to it until a release includes it. The pinned toolchain is unaffected. --- go.mod | 10 +++++----- go.sum | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index ed04302..9457290 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/mauri870/loopvec go 1.27.1 require ( - golang.org/x/tools v0.51.0 + golang.org/x/tools v0.52.1-0.20261030190145-0f433775b36d rsc.io/script v0.0.2 ) @@ -207,10 +207,10 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect golang.org/x/exp/typeparams v0.0.0-20260811152304-ee035b5b010f // indirect - golang.org/x/mod v0.41.0 // indirect - golang.org/x/sync v0.23.0 // indirect - golang.org/x/sys v0.48.0 // indirect - golang.org/x/telemetry v0.0.0-20260924152758-ed294f943157 // indirect + golang.org/x/mod v0.42.0 // indirect + golang.org/x/sync v0.24.0 // indirect + golang.org/x/sys v0.49.0 // indirect + golang.org/x/telemetry v0.0.0-20261009151841-97e8ea77aa2a // indirect golang.org/x/text v0.41.0 // indirect google.golang.org/protobuf v1.36.12 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 04c2946..bb2b241 100644 --- a/go.sum +++ b/go.sum @@ -688,8 +688,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c= -golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o= +golang.org/x/mod v0.42.0 h1:ICeL3t2L30ljSPHHxDnR4fqVcBt/zR2zJAb9juavmQg= +golang.org/x/mod v0.42.0/go.mod h1:u5fzIrRInkL8MaO1cbRkUHT64v303YIT5KEqpNr7jRs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -724,8 +724,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues= -golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= +golang.org/x/net v0.61.0 h1:RR+6j/BTBCrggOLugxa+66R8FvoN6MHlzDlZIbN9YFw= +golang.org/x/net v0.61.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -745,8 +745,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= -golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= +golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA= +golang.org/x/sync v0.24.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -790,10 +790,10 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= -golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= -golang.org/x/telemetry v0.0.0-20260924152758-ed294f943157 h1:DftxASHKl6JolFPqoN+2WrFO53JvkHwRXvFqf8gsivA= -golang.org/x/telemetry v0.0.0-20260924152758-ed294f943157/go.mod h1:i+ivNqjDnTF3WTElsdk5g9V5DTSBYgdNo7xTU9SDwYA= +golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA= +golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= +golang.org/x/telemetry v0.0.0-20261009151841-97e8ea77aa2a h1:wnveMBKHwx8/nIb8WYT5P9vtefdXOvIWxzycCkc5n6Q= +golang.org/x/telemetry v0.0.0-20261009151841-97e8ea77aa2a/go.mod h1:i+ivNqjDnTF3WTElsdk5g9V5DTSBYgdNo7xTU9SDwYA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -857,8 +857,8 @@ golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0t golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.51.0 h1:k4Xc/1Om9jwkBJBo4NVLMSARBoWtK10mx+W5BnXCeAI= -golang.org/x/tools v0.51.0/go.mod h1:9eEncMayCV6zRMGhR5eZEC2iBx98qWcF1HZ9Z7wJOoA= +golang.org/x/tools v0.52.1-0.20261030190145-0f433775b36d h1:F5ot9G6RM6pgx3TTdKF6IZa2nocit4tcsrVQlq4Zh5w= +golang.org/x/tools v0.52.1-0.20261030190145-0f433775b36d/go.mod h1:ItcP5UNaVGG+Yc4eIYmaFLNJ4soEopkx5Y2d4lcEurs= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= From 808d0ec4dfb3fa2b94f079c1002d1a7b07efacd1 Mon Sep 17 00:00:00 2001 From: thesyncim Date: Sat, 31 Oct 2026 21:29:58 +0000 Subject: [PATCH 3/4] Makefile: test against go1.27.3 go1.27.3 is the latest 1.27 release. Its simd package is the same as go1.27.1's, so the capability table only changes in its header, and the -methods crash (golang/go#80657) is still there, as flag_methods_ice.txt checks. go.mod keeps go 1.27.1: that is the first release whose simd package loopvec's output compiles against (go1.27.0's ShiftAllRight takes a uint8). --- BUGS.md | 6 +++--- Makefile | 2 +- internal/loopir/caps_gen.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/BUGS.md b/BUGS.md index 843087e..55231c5 100644 --- a/BUGS.md +++ b/BUGS.md @@ -2,11 +2,11 @@ loopvec rewrites code to use `GOEXPERIMENT=simd`, which is new, so most of what it hits is in the Go toolchain. This file lists the Go issues that affect loopvec. "tip" means -gotip, "1.27.1" is the release toolchain loopvec is tested against. +gotip, "1.27.3" is the release toolchain loopvec is tested against. | Issue | Status | Affects | loopvec's answer | |---|---|---|---| -| [#80657](https://github.com/golang/go/issues/80657) simd in a method: internal compiler error | fixed on tip (CL 839405), still crashes on 1.27.1 | `-methods` | methods are skipped unless `-methods` is passed | +| [#80657](https://github.com/golang/go/issues/80657) simd in a method: internal compiler error | fixed on tip (CL 839405), still crashes on 1.27.3 | `-methods` | methods are skipped unless `-methods` is passed | | [#80835](https://github.com/golang/go/issues/80835) legacy SSE encodings in functions using simd cause AVX-SSE transition penalties | open, fix pending (CLs 825145, 825146, in tip) | speed of any scalar float code that runs after a rewritten loop, in the same function or another | none; the portable `simd` package has no `ClearAVXUpperBits` | | [#81844](https://github.com/golang/go/issues/81844) blank identifier parameters rejected | fixed on tip (CL 841145) | every rewrite of a function with a `_` parameter | the generated file renames them `_p0`, `_p1`, ... | | [#81845](https://github.com/golang/go/issues/81845) calls left unresolved when inlined into a package initializer | closed as a duplicate of [#80689](https://github.com/golang/go/issues/80689), which is open | loops in package-level `var x = func() {...}()` | not rewritten (the generated initializer fails to link), see `package_initializer_no_rewrite.txt` and `toolexec_package_initializer.txt` | @@ -19,7 +19,7 @@ gotip, "1.27.1" is the release toolchain loopvec is tested against. A function with a receiver that contains simd code failed to compile with `internal compiler error: missing Types entry`. loopvec does not rewrite loops in methods -by default; `-methods` turns it on. The fix is on tip. On 1.27.1 the crash is still there, +by default; `-methods` turns it on. The fix is on tip. On 1.27.3 the crash is still there, and `flag_methods_ice.txt` pins it, so that test starts failing when the pinned toolchain gets the fix. Reported by someone else; the fix is [CL 839405](https://go.dev/cl/839405). diff --git a/Makefile b/Makefile index b4226b3..3804653 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -export GOTOOLCHAIN ?= go1.27.1 +export GOTOOLCHAIN ?= go1.27.3 .DEFAULT_GOAL := build diff --git a/internal/loopir/caps_gen.go b/internal/loopir/caps_gen.go index bccacfa..ba7ddff 100644 --- a/internal/loopir/caps_gen.go +++ b/internal/loopir/caps_gen.go @@ -1,4 +1,4 @@ -// Code generated by capsgen from the simd package of go1.27.1. DO NOT EDIT. +// Code generated by capsgen from the simd package of go1.27.3. DO NOT EDIT. package loopir From 7f2af166ce6cf28adcaf355456b5344948c689e4 Mon Sep 17 00:00:00 2001 From: thesyncim Date: Sat, 31 Oct 2026 19:55:19 +0000 Subject: [PATCH 4/4] cmd/loopvec-toolexec: rewrite default builds on darwin, ios, android and windows The wrapper leaves a package alone when its compile has -shared, since the nested build of simd and its dependencies would not match its objects. But -shared is also how the go command compiles a position-independent executable, the default build mode on darwin, ios, android and windows. There every default build was left alone, so loopvec-toolexec rewrote nothing on macOS, and seven of the toolexec scripts failed there. On those targets the nested build is position-independent by default too, so -shared is accepted. Elsewhere, where -buildmode=pie must be asked for, it still leaves the package alone, as toolexec_buildmode_pie.txt checks on linux. The go command sets GOOS for the tools it runs. --- cmd/loopvec-toolexec/compile.go | 26 +++++++++++- testdata/toolexec_buildmode_pie.txt | 64 +++++++++++++++++++++++++++++ toolexec.md | 4 +- 3 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 testdata/toolexec_buildmode_pie.txt diff --git a/cmd/loopvec-toolexec/compile.go b/cmd/loopvec-toolexec/compile.go index 13f0d91..42099dc 100644 --- a/cmd/loopvec-toolexec/compile.go +++ b/cmd/loopvec-toolexec/compile.go @@ -34,10 +34,30 @@ type compileArgs struct { importcfg int // index in args of the importcfg path, or -1 files []int // indexes in args of the Go source files // unsupported is set for build modes whose objects the nested simd build - // would not match (race, msan, asan, shared, dynlink, -trimpath). + // would not match (race, msan, asan, shared, dynlink, -trimpath). -shared + // is also what the go command passes for a position-independent + // executable, the default build mode on some targets (see defaultPIE); + // there the nested build uses the same default and matches. unsupported bool } +// defaultPIE reports whether the target builds position-independent +// executables by default (internal/platform.DefaultPIE), so that the go command +// passes -shared to every compile of a default build. The go command sets GOOS +// for the tools it runs. On windows -race turns the default off, but -race is +// unsupported here on its own. +func defaultPIE() bool { + goos := os.Getenv("GOOS") + if goos == "" { + goos = runtime.GOOS + } + switch goos { + case "android", "darwin", "ios", "windows": + return true + } + return false +} + func parseCompileArgs(args []string) compileArgs { c := compileArgs{importcfg: -1} first := len(args) @@ -59,8 +79,10 @@ func parseCompileArgs(args []string) compileArgs { c.lang = args[i+1] case strings.HasPrefix(arg, "-lang="): c.lang = strings.TrimPrefix(arg, "-lang=") - case arg == "-race", arg == "-msan", arg == "-asan", arg == "-shared", arg == "-dynlink": + case arg == "-race", arg == "-msan", arg == "-asan", arg == "-dynlink": c.unsupported = true + case arg == "-shared": + c.unsupported = !defaultPIE() case arg == "-trimpath" && hasValue && strings.Contains(args[i+1], ";"): c.unsupported = true } diff --git a/testdata/toolexec_buildmode_pie.txt b/testdata/toolexec_buildmode_pie.txt new file mode 100644 index 0000000..b088de5 --- /dev/null +++ b/testdata/toolexec_buildmode_pie.txt @@ -0,0 +1,64 @@ +# The go command compiles a position-independent executable with -shared. It is the +# default build mode on darwin, ios, android and windows, where the nested simd build +# is one too, so a default build is rewritten there. Asking for one where it is not +# the default (-buildmode=pie on linux) still leaves the package alone: the nested +# build would not match it. + +# Reference: the scalar program. +exec go run . +cmp stdout want.out + +env GOEXPERIMENT=simd +env GOCACHE=$WORK/gocache +env LOOPVEC_TOOLEXEC_LOG=$WORK/log +env LOOPVEC_TOOLEXEC_LOG_PKGS=example.com/app/vec + +[GOOS:darwin] exec go build -toolexec=$LOOPVEC_TOOLEXEC -o app . +[GOOS:darwin] cmp log rewrote.want + +[GOOS:linux] env LOOPVEC_TOOLEXEC_DEBUG=1 +[GOOS:linux] exec go build -buildmode=pie -toolexec=$LOOPVEC_TOOLEXEC -o app . +[GOOS:linux] cmp log skipped.want + +[GOOS:darwin] exec ./app +[GOOS:darwin] cmp stdout want.out +[GOOS:linux] exec ./app +[GOOS:linux] cmp stdout want.out + +-- go.mod -- +module example.com/app + +go 1.27.1 +-- vec/vec.go -- +package vec + +func AddInt32s(dst, a, b []int32) { + for i := range dst { + dst[i] = a[i] + b[i] + } +} +-- main.go -- +package main + +import ( + "fmt" + + "example.com/app/vec" +) + +func main() { + dst := make([]int32, 21) + a := make([]int32, 21) + b := make([]int32, 21) + for i := range a { + a[i], b[i] = int32(i), int32(2*i) + } + vec.AddInt32s(dst, a, b) + fmt.Println(dst) +} +-- want.out -- +[0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60] +-- rewrote.want -- +rewrote 1 loop(s) in example.com/app/vec +-- skipped.want -- +skipped example.com/app/vec: simd unavailable or unsupported build mode diff --git a/toolexec.md b/toolexec.md index a46931d..35cd46f 100644 --- a/toolexec.md +++ b/toolexec.md @@ -28,7 +28,9 @@ Packages are left alone when: `os`, `strconv`, `sync`, `sync/atomic`, `math`, and more). Rewritten code imports `simd`, so rewriting these would create an import cycle. - They use cgo, or the build uses `-race`, `-msan`, `-asan`, `-shared`, - `-dynlink` or `-trimpath`. + `-dynlink` or `-trimpath`. `-shared` is accepted where a position-independent + executable is the default build (darwin, ios, android, windows), since the + nested simd build is one there too. - They are cryptographic: `crypto/...` and `golang.org/x/crypto/...`, vendored copies included. Constant-time code is written so that its running time does not depend on secret data, and a rewrite adds a runtime overlap check, a length