Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions BUGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
Expand All @@ -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).

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export GOTOOLCHAIN ?= go1.27.1
export GOTOOLCHAIN ?= go1.27.3

.DEFAULT_GOAL := build

Expand Down
2 changes: 1 addition & 1 deletion cmd/loopvec-toolexec/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func tryRewrite(tool string, args []string) (out []string, ok bool) {
debugf(c.pkg, "skipped %s: simd unavailable or unsupported build mode", c.pkg)
return nil, false
}
if want := toolchainRelease(); want != builtRelease() {
if want := toolchainRelease(); want == "" || want != builtRelease() {
// go/types can only read export data written by the Go release it was
// built with.
debugf(c.pkg, "skipped %s: loopvec-toolexec was built with %s but the toolchain is %s", c.pkg, builtRelease(), want)
Expand Down
29 changes: 23 additions & 6 deletions cmd/loopvec-toolexec/simd.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,31 @@ func simdOn(tool string) bool {
return simdEnabled
}

var releaseRE = regexp.MustCompile(`go1\.[0-9]+`)
// releaseRE matches a Go version as a whole word: a release and its patch
// (go1.27.3), a prerelease (go1.28rc1), a development build (go1.28-6ae0b1f8a9)
// or a vendor's build (go1.27.3-acme).
var releaseRE = regexp.MustCompile(`go1\.[^\s]+`)

// release returns the Go version in s, a compiler's -V=full output or a
// runtime.Version, without the experiments: the compiler separates them with a
// space (go1.27.3 X:simd), but a program built with an experiment reports its
// version with a dash when the version has none (go1.27.3-X:simd).
func release(s string) string {
v, _, _ := strings.Cut(releaseRE.FindString(s), "-X:")
return v
}

// toolchainRelease returns the Go release (such as go1.28) of the compiler
// toolchainRelease returns the Go version (such as go1.27.3) of the compiler
// probed by simdOn.
func toolchainRelease() string { return releaseRE.FindString(toolVersion) }

// builtRelease returns the Go release this program was built with.
func builtRelease() string { return releaseRE.FindString(runtime.Version()) }
func toolchainRelease() string { return release(toolVersion) }

// builtRelease returns the Go version this program was built with. It must be
// the toolchain's exact version, patch included: the simd package can change
// in a patch release without go/types seeing it (go1.27.0 declares
// ShiftAllRight(uint64) but compiles it as taking a uint8; go1.27.1 takes a
// uint64), and then the rewritten package type-checks here but does not
// compile.
func builtRelease() string { return release(runtime.Version()) }

// build holds the per-build state shared by the wrapper processes of one go
// command invocation. It lives in the go command's work directory, so it is
Expand Down
25 changes: 25 additions & 0 deletions cmd/loopvec-toolexec/simd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import "testing"

func TestRelease(t *testing.T) {
for _, tt := range []struct{ in, want string }{
{"go1.27.3", "go1.27.3"},
{"go1.27.3-X:simd", "go1.27.3"},
{"go1.27.3-X:simd,fieldtrack", "go1.27.3"},
{"compile version go1.27.3", "go1.27.3"},
{"compile version go1.27.3 X:simd\n", "go1.27.3"},
{"go1.28rc1-X:simd", "go1.28rc1"},
{"compile version go1.28rc1 X:simd", "go1.28rc1"},
{"devel go1.28-6ae0b1f8a9 Tue Oct 27 10:00:00 2026 -0700 X:simd", "go1.28-6ae0b1f8a9"},
{"compile version devel go1.28-6ae0b1f8a9 Tue Oct 27 10:00:00 2026 -0700 X:simd buildID=x/y", "go1.28-6ae0b1f8a9"},
{"go1.27.3-acme X:simd", "go1.27.3-acme"},
{"compile version go1.27.3-acme X:simd", "go1.27.3-acme"},
{"", ""},
{"devel +6ae0b1f8a9", ""},
} {
if got := release(tt.in); got != tt.want {
t.Errorf("release(%q) = %q, want %q", tt.in, got, tt.want)
}
}
}
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand Down Expand Up @@ -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
Expand Down
24 changes: 12 additions & 12 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand All @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down
2 changes: 1 addition & 1 deletion internal/loopir/caps_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 20 additions & 5 deletions testdata/toolexec_toolchain_mismatch.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
# go/types can only read export data written by the Go release it was built
# with. When loopvec-toolexec was built with a different release than the
# toolchain running the build, packages are compiled unchanged, and the log
# (with LOOPVEC_TOOLEXEC_DEBUG) says why.
# with, and the simd package can change in a patch release without go/types
# seeing it (go1.27.0 compiles ShiftAllRight as taking a uint8). When
# loopvec-toolexec was built with a different Go version than the toolchain
# running the build, patch included, packages are compiled unchanged, and the
# log (with LOOPVEC_TOOLEXEC_DEBUG) says why.

chmod 0755 compile
chmod 0755 compile patch/compile
env LOOPVEC_TOOLEXEC_DEBUG=1
env LOOPVEC_TOOLEXEC_LOG=$WORK/log
exec $LOOPVEC_TOOLEXEC $WORK/compile -p example.com/x -importcfg $WORK/b001/importcfg x.go
cmpenv stdout stdout.want
! stderr .
stdout -count=1 '^fake compile: '
grep -count=1 '^skipped example\.com/x: loopvec-toolexec was built with go1\.[0-9]+ but the toolchain is go1\.1$' log
grep -count=1 '^skipped example\.com/x: loopvec-toolexec was built with go1\.[^ ]+ but the toolchain is go1\.1$' log

# Same release, another patch.
exec $LOOPVEC_TOOLEXEC $WORK/patch/compile -p example.com/y -importcfg $WORK/b001/importcfg x.go
stdout -count=1 '^fake compile: -p example\.com/y '
! stderr .
grep -count=1 '^skipped example\.com/y: loopvec-toolexec was built with go1\.[^ ]+ but the toolchain is go1\.27\.0$' log

-- compile --
#!/bin/sh
Expand All @@ -19,6 +27,13 @@ if [ "$1" = "-V=full" ]; then
exit 0
fi
echo "fake compile: $@"
-- patch/compile --
#!/bin/sh
if [ "$1" = "-V=full" ]; then
echo "compile version go1.27.0 X:simd"
exit 0
fi
echo "fake compile: $@"
-- x.go --
package x
-- stdout.want --
Expand Down
Loading