From ac059878bcf58c4369fa7bef05bf34fb163b43e0 Mon Sep 17 00:00:00 2001 From: Mark Freeman Date: Thu, 3 Sep 2026 13:48:44 +0700 Subject: [PATCH 1/4] cmd/compile/internal/types2: point types2 tests to testimporter.Importer Change-Id: I77bfba05f0c390ec8262e709193af7a9cec41f21 Reviewed-on: https://go-review.googlesource.com/c/go/+/827064 Auto-Submit: Mark Freeman LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Alan Donovan --- .../compile/internal/types2/importer_test.go | 28 +++---------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/src/cmd/compile/internal/types2/importer_test.go b/src/cmd/compile/internal/types2/importer_test.go index ee4d978639bc33..381aed0329d4bd 100644 --- a/src/cmd/compile/internal/types2/importer_test.go +++ b/src/cmd/compile/internal/types2/importer_test.go @@ -2,35 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file implements the plumbing to get importing to work. - package types2_test import ( - "cmd/compile/internal/importer" + "cmd/compile/internal/testimporter" "cmd/compile/internal/types2" - "io" ) -// TODO(mark): Switch to use new types2 importer. -func defaultImporter() types2.Importer { - return &gcimports{ - packages: make(map[string]*types2.Package), - } -} - -type gcimports struct { - packages map[string]*types2.Package - lookup func(path string) (io.ReadCloser, error) -} - -func (m *gcimports) Import(path string) (*types2.Package, error) { - return m.ImportFrom(path, "" /* no vendoring */, 0) -} +var imp = testimporter.NewImporter() -func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*types2.Package, error) { - if mode != 0 { - panic("mode must be 0") - } - return importer.Import(m.packages, path, srcDir, m.lookup) +func defaultImporter() types2.Importer { + return imp } From 2d04c9d8b6267772f8c683c5f2e577bc16653a14 Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Tue, 1 Sep 2026 18:18:50 -0400 Subject: [PATCH 2/4] runtime: don't add the itabs of a plugin twice CL 729201 removed itablinks. The runtime now walks the itab section of a module when it starts and when it loads a plugin. A plugin has its own copy of the itabs that the main program also has. Before CL 729201, dynamic symbol resolution pointed the itablinks entries of the plugin at the itabs of the main program, so add skipped them. Now add puts the copies of the plugin into the table as second entries for the same interface/type pairs. Type switches and type assertions compare the itab pointer of a value with the itab that the linker put into the module. In the plugin, that itab also resolves to the copy of the main program. After the itab table grows and rehashes its entries, find can return the copy of the plugin, and type switches in the main program take the default case. With Go 1.27, golangci-lint panics in go/ast.Walk with "unexpected node type *ast.DeferStmt" after it loads its third linter plugin (kubernetes/kubernetes#141663). Make add skip an itab when the table already has one for the same interface/type pair. Fixes #81303 Change-Id: Ia78e597fff9fd870924c1ebc94453523f3e7578b Reviewed-on: https://go-review.googlesource.com/c/go/+/826244 Reviewed-by: Cherry Mui Reviewed-by: Jordan Liggitt LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor --- .../cgo/internal/testplugin/plugin_test.go | 11 +++++ .../testplugin/testdata/issue81303/main.go | 39 +++++++++++++++ .../testplugin/testdata/issue81303/p/p.go | 48 +++++++++++++++++++ .../testplugin/testdata/issue81303/plugin1.go | 11 +++++ .../testplugin/testdata/issue81303/plugin2.go | 11 +++++ .../testplugin/testdata/issue81303/plugin3.go | 11 +++++ src/runtime/iface.go | 10 ++-- 7 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 src/cmd/cgo/internal/testplugin/testdata/issue81303/main.go create mode 100644 src/cmd/cgo/internal/testplugin/testdata/issue81303/p/p.go create mode 100644 src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin1.go create mode 100644 src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin2.go create mode 100644 src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin3.go diff --git a/src/cmd/cgo/internal/testplugin/plugin_test.go b/src/cmd/cgo/internal/testplugin/plugin_test.go index 3216073edbcb2d..4f0458b7dee472 100644 --- a/src/cmd/cgo/internal/testplugin/plugin_test.go +++ b/src/cmd/cgo/internal/testplugin/plugin_test.go @@ -430,3 +430,14 @@ func TestIssue75102(t *testing.T) { goCmd(t, "build", "-o", "issue75102.exe", "./issue75102/main.go") run(t, "./issue75102.exe") } + +func TestIssue81303(t *testing.T) { + // Issue 81303: the itab copies of a plugin must not hide the itabs + // of the host for the same interface/type pairs. + globalSkip(t) + goCmd(t, "build", "-buildmode=plugin", "-o", "issue81303p1.so", "./issue81303/plugin1.go") + goCmd(t, "build", "-buildmode=plugin", "-o", "issue81303p2.so", "./issue81303/plugin2.go") + goCmd(t, "build", "-buildmode=plugin", "-o", "issue81303p3.so", "./issue81303/plugin3.go") + goCmd(t, "build", "-o", "issue81303.exe", "./issue81303/main.go") + run(t, "./issue81303.exe") +} diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue81303/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue81303/main.go new file mode 100644 index 00000000000000..7b2ea1595f18ac --- /dev/null +++ b/src/cmd/cgo/internal/testplugin/testdata/issue81303/main.go @@ -0,0 +1,39 @@ +// 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. + +// Issue 81303: a plugin has its own copies of the itabs of the host. +// The runtime added these copies to the itab table as second entries +// for the same interface/type pairs. After the table grew, a lookup +// could return the copy from the plugin. A type switch compares the +// itab with the itab of the host, so it took the default case. +// +// Each plugin imports package p, which uses go/ast, so each plugin +// adds a copy of every go/ast itab of the host. The host walks a +// syntax tree before and after each plugin loads. The three plugins +// are the same because plugin.Open loads a plugin path only once. + +package main + +import ( + "log" + "plugin" + + "testplugin/issue81303/p" +) + +func main() { + p.Walk() + for _, name := range []string{"issue81303p1.so", "issue81303p2.so", "issue81303p3.so"} { + pl, err := plugin.Open(name) + if err != nil { + log.Fatal(err) + } + f, err := pl.Lookup("F") + if err != nil { + log.Fatal(err) + } + f.(func())() + p.Walk() + } +} diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue81303/p/p.go b/src/cmd/cgo/internal/testplugin/testdata/issue81303/p/p.go new file mode 100644 index 00000000000000..960d35e4376d5d --- /dev/null +++ b/src/cmd/cgo/internal/testplugin/testdata/issue81303/p/p.go @@ -0,0 +1,48 @@ +// 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 p + +import ( + "go/ast" + "go/parser" + "go/token" + "log" +) + +const src = `package p + +import "fmt" + +type T struct{ x int } + +func (t *T) M(n int) (r int) { + defer func() { r++ }() + go fmt.Println(n) + if n > 0 { + r = n + } else { + r = -n + } + for i := 0; i < n; i++ { + r += t.x + } + switch v := any(n).(type) { + case int: + r = v + } + return +} +` + +// Walk parses src and walks the syntax tree. ast.Walk converts each +// node to ast.Node, which looks up the itab in the itab table, and +// then compares that itab with the itab of the host in a type switch. +func Walk() { + f, err := parser.ParseFile(token.NewFileSet(), "src.go", src, parser.SkipObjectResolution) + if err != nil { + log.Fatal(err) + } + ast.Inspect(f, func(ast.Node) bool { return true }) +} diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin1.go b/src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin1.go new file mode 100644 index 00000000000000..c97a98583684ea --- /dev/null +++ b/src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin1.go @@ -0,0 +1,11 @@ +// 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 "testplugin/issue81303/p" + +func main() {} + +func F() { p.Walk() } diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin2.go b/src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin2.go new file mode 100644 index 00000000000000..c97a98583684ea --- /dev/null +++ b/src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin2.go @@ -0,0 +1,11 @@ +// 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 "testplugin/issue81303/p" + +func main() {} + +func F() { p.Walk() } diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin3.go b/src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin3.go new file mode 100644 index 00000000000000..c97a98583684ea --- /dev/null +++ b/src/cmd/cgo/internal/testplugin/testdata/issue81303/plugin3.go @@ -0,0 +1,11 @@ +// 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 "testplugin/issue81303/p" + +func main() {} + +func F() { p.Walk() } diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 6385d1c9d055b1..9f1914372e7194 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -174,11 +174,11 @@ func (t *itabTableType) add(m *itab) { for i := uintptr(1); ; i++ { p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize)) m2 := *p - if m2 == m { - // A given itab may be used in more than one module - // and thanks to the way global symbol resolution works, the - // pointed-to itab may already have been inserted into the - // global 'hash'. + if m2 != nil && m2.Inter == m.Inter && m2.Type == m.Type { + // A plugin has its own copy of the itabs that the main program + // also has. Type switches and type assertions compare against + // the itab that is already in the table, so don't add a second + // itab for the same interface/type pair. return } if m2 == nil { From 7ae2269d4850505324c48e710b02768f14e10419 Mon Sep 17 00:00:00 2001 From: Junyang Shao Date: Thu, 27 Aug 2026 15:25:33 -0400 Subject: [PATCH 3/4] simd/archsimd: add SVE AndNot Lower to ZBIC (x &^ y), width-agnostic bitwise like ZAND and the first non-commutative one: the merging form is pinned resultInArg0 with no MOVPRFX-prefixed rule. For #79781. Change-Id: Ibcdd6b7449410205486fb4cd63f7584935c64b8d Reviewed-on: https://go-review.googlesource.com/c/go/+/822940 Auto-Submit: Junyang Shao Reviewed-by: Junyang Shao Reviewed-by: David Chase LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/cmd/compile/internal/arm64/simdssa_sve.go | 5 + .../internal/ssa/_gen/simdARM64SVE.rules | 12 ++ .../internal/ssa/_gen/simdARM64SVEops.go | 5 + .../internal/ssa/_gen/simdgenericOps.go | 8 ++ src/cmd/compile/internal/ssa/ssaop/opGen.go | 131 ++++++++++++++++++ .../internal/ssagen/simdARM64SVEintrinsics.go | 8 ++ .../ssarewrite/rewritearm64/rewriteARM64.go | 88 ++++++++++++ .../_gen/simdgen/ops/BitwiseLogic/go_sve.yaml | 17 +++ .../simd_test/binary_sve_arm64_test.go | 14 ++ src/simd/archsimd/ops_sve.go | 42 ++++++ 10 files changed, 330 insertions(+) diff --git a/src/cmd/compile/internal/arm64/simdssa_sve.go b/src/cmd/compile/internal/arm64/simdssa_sve.go index a2b9ff30e2a30f..da1dff09f7f56d 100644 --- a/src/cmd/compile/internal/arm64/simdssa_sve.go +++ b/src/cmd/compile/internal/arm64/simdssa_sve.go @@ -56,6 +56,7 @@ func ssaGenSIMDSVEValue(s *ssagen.State, v *ssa.Value) bool { ssaop.OpARM64ZSQADDD, ssaop.OpARM64ZUQADDD, ssaop.OpARM64ZANDD, + ssaop.OpARM64ZBICD, ssaop.OpARM64ZORRD, ssaop.OpARM64ZFSUBD, ssaop.OpARM64ZSUBD, @@ -126,6 +127,7 @@ func ssaGenSIMDSVEValue(s *ssagen.State, v *ssa.Value) bool { ssaop.OpARM64ZSQADDMergingB, ssaop.OpARM64ZUQADDMergingB, ssaop.OpARM64ZANDMergingB, + ssaop.OpARM64ZBICMergingB, ssaop.OpARM64ZORRMergingB, ssaop.OpARM64ZSUBMergingB, ssaop.OpARM64ZSQSUBMergingB, @@ -138,6 +140,7 @@ func ssaGenSIMDSVEValue(s *ssagen.State, v *ssa.Value) bool { ssaop.OpARM64ZSQADDMergingD, ssaop.OpARM64ZUQADDMergingD, ssaop.OpARM64ZANDMergingD, + ssaop.OpARM64ZBICMergingD, ssaop.OpARM64ZORRMergingD, ssaop.OpARM64ZFSUBMergingD, ssaop.OpARM64ZSUBMergingD, @@ -150,6 +153,7 @@ func ssaGenSIMDSVEValue(s *ssagen.State, v *ssa.Value) bool { ssaop.OpARM64ZSQADDMergingH, ssaop.OpARM64ZUQADDMergingH, ssaop.OpARM64ZANDMergingH, + ssaop.OpARM64ZBICMergingH, ssaop.OpARM64ZORRMergingH, ssaop.OpARM64ZSUBMergingH, ssaop.OpARM64ZSQSUBMergingH, @@ -162,6 +166,7 @@ func ssaGenSIMDSVEValue(s *ssagen.State, v *ssa.Value) bool { ssaop.OpARM64ZSQADDMergingS, ssaop.OpARM64ZUQADDMergingS, ssaop.OpARM64ZANDMergingS, + ssaop.OpARM64ZBICMergingS, ssaop.OpARM64ZORRMergingS, ssaop.OpARM64ZFSUBMergingS, ssaop.OpARM64ZSUBMergingS, diff --git a/src/cmd/compile/internal/ssa/_gen/simdARM64SVE.rules b/src/cmd/compile/internal/ssa/_gen/simdARM64SVE.rules index ea1571e7d523d4..75dfc96eab978d 100644 --- a/src/cmd/compile/internal/ssa/_gen/simdARM64SVE.rules +++ b/src/cmd/compile/internal/ssa/_gen/simdARM64SVE.rules @@ -26,6 +26,14 @@ (AndUint16s ...) => (ZANDD ...) // pureVreg (AndUint32s ...) => (ZANDD ...) // pureVreg (AndUint64s ...) => (ZANDD ...) // pureVreg +(AndNotInt8s ...) => (ZBICD ...) // pureVreg +(AndNotInt16s ...) => (ZBICD ...) // pureVreg +(AndNotInt32s ...) => (ZBICD ...) // pureVreg +(AndNotInt64s ...) => (ZBICD ...) // pureVreg +(AndNotUint8s ...) => (ZBICD ...) // pureVreg +(AndNotUint16s ...) => (ZBICD ...) // pureVreg +(AndNotUint32s ...) => (ZBICD ...) // pureVreg +(AndNotUint64s ...) => (ZBICD ...) // pureVreg (OrInt8s ...) => (ZORRD ...) // pureVreg (OrInt16s ...) => (ZORRD ...) // pureVreg (OrInt32s ...) => (ZORRD ...) // pureVreg @@ -129,6 +137,7 @@ (ZSELB (ZANDD x y) x mask) => (ZANDMergingB x y mask) (ZSELB (ZANDD x y) y mask) => (ZANDMergingB y x mask) (ZSELB (ZANDD x y) z mask) => (ZANDMergingPrefixedB z x y mask) +(ZSELB (ZBICD x y) x mask) => (ZBICMergingB x y mask) (ZSELB (ZEORD x y) x mask) => (ZEORMergingB x y mask) (ZSELB (ZEORD x y) y mask) => (ZEORMergingB y x mask) (ZSELB (ZEORD x y) z mask) => (ZEORMergingPrefixedB z x y mask) @@ -152,6 +161,7 @@ (ZSELD (ZANDD x y) x mask) => (ZANDMergingD x y mask) (ZSELD (ZANDD x y) y mask) => (ZANDMergingD y x mask) (ZSELD (ZANDD x y) z mask) => (ZANDMergingPrefixedD z x y mask) +(ZSELD (ZBICD x y) x mask) => (ZBICMergingD x y mask) (ZSELD (ZEORD x y) x mask) => (ZEORMergingD x y mask) (ZSELD (ZEORD x y) y mask) => (ZEORMergingD y x mask) (ZSELD (ZEORD x y) z mask) => (ZEORMergingPrefixedD z x y mask) @@ -182,6 +192,7 @@ (ZSELH (ZANDD x y) x mask) => (ZANDMergingH x y mask) (ZSELH (ZANDD x y) y mask) => (ZANDMergingH y x mask) (ZSELH (ZANDD x y) z mask) => (ZANDMergingPrefixedH z x y mask) +(ZSELH (ZBICD x y) x mask) => (ZBICMergingH x y mask) (ZSELH (ZEORD x y) x mask) => (ZEORMergingH x y mask) (ZSELH (ZEORD x y) y mask) => (ZEORMergingH y x mask) (ZSELH (ZEORD x y) z mask) => (ZEORMergingPrefixedH z x y mask) @@ -205,6 +216,7 @@ (ZSELS (ZANDD x y) x mask) => (ZANDMergingS x y mask) (ZSELS (ZANDD x y) y mask) => (ZANDMergingS y x mask) (ZSELS (ZANDD x y) z mask) => (ZANDMergingPrefixedS z x y mask) +(ZSELS (ZBICD x y) x mask) => (ZBICMergingS x y mask) (ZSELS (ZEORD x y) x mask) => (ZEORMergingS x y mask) (ZSELS (ZEORD x y) y mask) => (ZEORMergingS y x mask) (ZSELS (ZEORD x y) z mask) => (ZEORMergingPrefixedS z x y mask) diff --git a/src/cmd/compile/internal/ssa/_gen/simdARM64SVEops.go b/src/cmd/compile/internal/ssa/_gen/simdARM64SVEops.go index 1f33449b23ceec..87dd20e3ce44df 100644 --- a/src/cmd/compile/internal/ssa/_gen/simdARM64SVEops.go +++ b/src/cmd/compile/internal/ssa/_gen/simdARM64SVEops.go @@ -33,6 +33,11 @@ func simdARM64SVEOps(z11, z21, zkv, z2kk, z2kv, z2kvPred, z3kvPred regInfo) []op {name: "ZANDMergingPrefixedH", argLength: 4, reg: z3kvPred, asm: "ZAND", typ: "Vec256", resultInArg0: true}, {name: "ZANDMergingPrefixedS", argLength: 4, reg: z3kvPred, asm: "ZAND", typ: "Vec256", resultInArg0: true}, {name: "ZANDMergingS", argLength: 3, reg: z2kvPred, asm: "ZAND", commutative: true, typ: "Vec256"}, + {name: "ZBICD", argLength: 2, reg: z21, asm: "ZBIC", typ: "Vec256"}, + {name: "ZBICMergingB", argLength: 3, reg: z2kvPred, asm: "ZBIC", typ: "Vec256", resultInArg0: true}, + {name: "ZBICMergingD", argLength: 3, reg: z2kvPred, asm: "ZBIC", typ: "Vec256", resultInArg0: true}, + {name: "ZBICMergingH", argLength: 3, reg: z2kvPred, asm: "ZBIC", typ: "Vec256", resultInArg0: true}, + {name: "ZBICMergingS", argLength: 3, reg: z2kvPred, asm: "ZBIC", typ: "Vec256", resultInArg0: true}, {name: "ZCMPEQB", argLength: 3, reg: z2kk, asm: "ZCMPEQ", commutative: true, typ: "Mask"}, {name: "ZCMPEQD", argLength: 3, reg: z2kk, asm: "ZCMPEQ", commutative: true, typ: "Mask"}, {name: "ZCMPEQH", argLength: 3, reg: z2kk, asm: "ZCMPEQ", commutative: true, typ: "Mask"}, diff --git a/src/cmd/compile/internal/ssa/_gen/simdgenericOps.go b/src/cmd/compile/internal/ssa/_gen/simdgenericOps.go index 0a1253a0aa5573..81d205033c28d8 100644 --- a/src/cmd/compile/internal/ssa/_gen/simdgenericOps.go +++ b/src/cmd/compile/internal/ssa/_gen/simdgenericOps.go @@ -121,27 +121,35 @@ func simdGenericOps() []opData { {name: "AndInt64x2", argLength: 2, commutative: true}, // ARCH:amd64,arm64,wasm {name: "AndInt64x4", argLength: 2, commutative: true}, // ARCH:amd64 {name: "AndInt64x8", argLength: 2, commutative: true}, // ARCH:amd64 + {name: "AndNotInt8s", argLength: 2}, // ARCH:sve {name: "AndNotInt8x16", argLength: 2}, // ARCH:amd64,arm64,wasm {name: "AndNotInt8x32", argLength: 2}, // ARCH:amd64 {name: "AndNotInt8x64", argLength: 2}, // ARCH:amd64 + {name: "AndNotInt16s", argLength: 2}, // ARCH:sve {name: "AndNotInt16x8", argLength: 2}, // ARCH:amd64,arm64,wasm {name: "AndNotInt16x16", argLength: 2}, // ARCH:amd64 {name: "AndNotInt16x32", argLength: 2}, // ARCH:amd64 + {name: "AndNotInt32s", argLength: 2}, // ARCH:sve {name: "AndNotInt32x4", argLength: 2}, // ARCH:amd64,arm64,wasm {name: "AndNotInt32x8", argLength: 2}, // ARCH:amd64 {name: "AndNotInt32x16", argLength: 2}, // ARCH:amd64 + {name: "AndNotInt64s", argLength: 2}, // ARCH:sve {name: "AndNotInt64x2", argLength: 2}, // ARCH:amd64,arm64,wasm {name: "AndNotInt64x4", argLength: 2}, // ARCH:amd64 {name: "AndNotInt64x8", argLength: 2}, // ARCH:amd64 + {name: "AndNotUint8s", argLength: 2}, // ARCH:sve {name: "AndNotUint8x16", argLength: 2}, // ARCH:amd64,arm64,wasm {name: "AndNotUint8x32", argLength: 2}, // ARCH:amd64 {name: "AndNotUint8x64", argLength: 2}, // ARCH:amd64 + {name: "AndNotUint16s", argLength: 2}, // ARCH:sve {name: "AndNotUint16x8", argLength: 2}, // ARCH:amd64,arm64,wasm {name: "AndNotUint16x16", argLength: 2}, // ARCH:amd64 {name: "AndNotUint16x32", argLength: 2}, // ARCH:amd64 + {name: "AndNotUint32s", argLength: 2}, // ARCH:sve {name: "AndNotUint32x4", argLength: 2}, // ARCH:amd64,arm64,wasm {name: "AndNotUint32x8", argLength: 2}, // ARCH:amd64 {name: "AndNotUint32x16", argLength: 2}, // ARCH:amd64 + {name: "AndNotUint64s", argLength: 2}, // ARCH:sve {name: "AndNotUint64x2", argLength: 2}, // ARCH:amd64,arm64,wasm {name: "AndNotUint64x4", argLength: 2}, // ARCH:amd64 {name: "AndNotUint64x8", argLength: 2}, // ARCH:amd64 diff --git a/src/cmd/compile/internal/ssa/ssaop/opGen.go b/src/cmd/compile/internal/ssa/ssaop/opGen.go index 7336d86acbf7ad..f5055e6fa72772 100644 --- a/src/cmd/compile/internal/ssa/ssaop/opGen.go +++ b/src/cmd/compile/internal/ssa/ssaop/opGen.go @@ -5069,6 +5069,11 @@ const ( OpARM64ZANDMergingPrefixedH OpARM64ZANDMergingPrefixedS OpARM64ZANDMergingS + OpARM64ZBICD + OpARM64ZBICMergingB + OpARM64ZBICMergingD + OpARM64ZBICMergingH + OpARM64ZBICMergingS OpARM64ZCMPEQB OpARM64ZCMPEQD OpARM64ZCMPEQH @@ -7241,27 +7246,35 @@ const ( OpAndInt8x16 OpAndInt8x32 OpAndInt8x64 + OpAndNotInt16s OpAndNotInt16x16 OpAndNotInt16x32 OpAndNotInt16x8 + OpAndNotInt32s OpAndNotInt32x16 OpAndNotInt32x4 OpAndNotInt32x8 + OpAndNotInt64s OpAndNotInt64x2 OpAndNotInt64x4 OpAndNotInt64x8 + OpAndNotInt8s OpAndNotInt8x16 OpAndNotInt8x32 OpAndNotInt8x64 + OpAndNotUint16s OpAndNotUint16x16 OpAndNotUint16x32 OpAndNotUint16x8 + OpAndNotUint32s OpAndNotUint32x16 OpAndNotUint32x4 OpAndNotUint32x8 + OpAndNotUint64s OpAndNotUint64x2 OpAndNotUint64x4 OpAndNotUint64x8 + OpAndNotUint8s OpAndNotUint8x16 OpAndNotUint8x32 OpAndNotUint8x64 @@ -86356,6 +86369,84 @@ var OpcodeTable = [...]OpInfo{ }, }, }, + { + Name: "ZBICD", + ArgLen: 2, + asm: arm64.AZBIC, + Reg: RegInfo{ + Inputs: []InputInfo{ + {0, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {1, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + Outputs: []OutputInfo{ + {0, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, + { + Name: "ZBICMergingB", + ArgLen: 3, + ResultInArg0: true, + asm: arm64.AZBIC, + Reg: RegInfo{ + Inputs: []InputInfo{ + {2, RegMask{V1: 9223372036854775808, V2: 32767}}, // P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 P10 P11 P12 P13 P14 P15 + {0, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {1, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + Outputs: []OutputInfo{ + {0, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, + { + Name: "ZBICMergingD", + ArgLen: 3, + ResultInArg0: true, + asm: arm64.AZBIC, + Reg: RegInfo{ + Inputs: []InputInfo{ + {2, RegMask{V1: 9223372036854775808, V2: 32767}}, // P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 P10 P11 P12 P13 P14 P15 + {0, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {1, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + Outputs: []OutputInfo{ + {0, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, + { + Name: "ZBICMergingH", + ArgLen: 3, + ResultInArg0: true, + asm: arm64.AZBIC, + Reg: RegInfo{ + Inputs: []InputInfo{ + {2, RegMask{V1: 9223372036854775808, V2: 32767}}, // P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 P10 P11 P12 P13 P14 P15 + {0, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {1, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + Outputs: []OutputInfo{ + {0, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, + { + Name: "ZBICMergingS", + ArgLen: 3, + ResultInArg0: true, + asm: arm64.AZBIC, + Reg: RegInfo{ + Inputs: []InputInfo{ + {2, RegMask{V1: 9223372036854775808, V2: 32767}}, // P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 P10 P11 P12 P13 P14 P15 + {0, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {1, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + Outputs: []OutputInfo{ + {0, RegMask{V1: 9223372034707292160, V2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, { Name: "ZCMPEQB", ArgLen: 3, @@ -112604,6 +112695,11 @@ var OpcodeTable = [...]OpInfo{ Commutative: true, Generic: true, }, + { + Name: "AndNotInt16s", + ArgLen: 2, + Generic: true, + }, { Name: "AndNotInt16x16", ArgLen: 2, @@ -112619,6 +112715,11 @@ var OpcodeTable = [...]OpInfo{ ArgLen: 2, Generic: true, }, + { + Name: "AndNotInt32s", + ArgLen: 2, + Generic: true, + }, { Name: "AndNotInt32x16", ArgLen: 2, @@ -112634,6 +112735,11 @@ var OpcodeTable = [...]OpInfo{ ArgLen: 2, Generic: true, }, + { + Name: "AndNotInt64s", + ArgLen: 2, + Generic: true, + }, { Name: "AndNotInt64x2", ArgLen: 2, @@ -112649,6 +112755,11 @@ var OpcodeTable = [...]OpInfo{ ArgLen: 2, Generic: true, }, + { + Name: "AndNotInt8s", + ArgLen: 2, + Generic: true, + }, { Name: "AndNotInt8x16", ArgLen: 2, @@ -112664,6 +112775,11 @@ var OpcodeTable = [...]OpInfo{ ArgLen: 2, Generic: true, }, + { + Name: "AndNotUint16s", + ArgLen: 2, + Generic: true, + }, { Name: "AndNotUint16x16", ArgLen: 2, @@ -112679,6 +112795,11 @@ var OpcodeTable = [...]OpInfo{ ArgLen: 2, Generic: true, }, + { + Name: "AndNotUint32s", + ArgLen: 2, + Generic: true, + }, { Name: "AndNotUint32x16", ArgLen: 2, @@ -112694,6 +112815,11 @@ var OpcodeTable = [...]OpInfo{ ArgLen: 2, Generic: true, }, + { + Name: "AndNotUint64s", + ArgLen: 2, + Generic: true, + }, { Name: "AndNotUint64x2", ArgLen: 2, @@ -112709,6 +112835,11 @@ var OpcodeTable = [...]OpInfo{ ArgLen: 2, Generic: true, }, + { + Name: "AndNotUint8s", + ArgLen: 2, + Generic: true, + }, { Name: "AndNotUint8x16", ArgLen: 2, diff --git a/src/cmd/compile/internal/ssagen/simdARM64SVEintrinsics.go b/src/cmd/compile/internal/ssagen/simdARM64SVEintrinsics.go index d742bda5e3961a..06b0c3a0645226 100644 --- a/src/cmd/compile/internal/ssagen/simdARM64SVEintrinsics.go +++ b/src/cmd/compile/internal/ssagen/simdARM64SVEintrinsics.go @@ -43,6 +43,14 @@ func simdARM64SVEIntrinsics(addF func(pkg, fn string, b intrinsicBuilder, archFa addF(simdPackage, "Uint16s.And", opLen2(ssaop.OpAndUint16s, types.TypeVec256), sys.ARM64) addF(simdPackage, "Uint32s.And", opLen2(ssaop.OpAndUint32s, types.TypeVec256), sys.ARM64) addF(simdPackage, "Uint64s.And", opLen2(ssaop.OpAndUint64s, types.TypeVec256), sys.ARM64) + addF(simdPackage, "Int8s.AndNot", opLen2(ssaop.OpAndNotInt8s, types.TypeVec256), sys.ARM64) + addF(simdPackage, "Int16s.AndNot", opLen2(ssaop.OpAndNotInt16s, types.TypeVec256), sys.ARM64) + addF(simdPackage, "Int32s.AndNot", opLen2(ssaop.OpAndNotInt32s, types.TypeVec256), sys.ARM64) + addF(simdPackage, "Int64s.AndNot", opLen2(ssaop.OpAndNotInt64s, types.TypeVec256), sys.ARM64) + addF(simdPackage, "Uint8s.AndNot", opLen2(ssaop.OpAndNotUint8s, types.TypeVec256), sys.ARM64) + addF(simdPackage, "Uint16s.AndNot", opLen2(ssaop.OpAndNotUint16s, types.TypeVec256), sys.ARM64) + addF(simdPackage, "Uint32s.AndNot", opLen2(ssaop.OpAndNotUint32s, types.TypeVec256), sys.ARM64) + addF(simdPackage, "Uint64s.AndNot", opLen2(ssaop.OpAndNotUint64s, types.TypeVec256), sys.ARM64) addF(simdPackage, "Float32s.Ceil", opLen1(ssaop.OpCeilFloat32s, types.TypeVec256), sys.ARM64) addF(simdPackage, "Float64s.Ceil", opLen1(ssaop.OpCeilFloat64s, types.TypeVec256), sys.ARM64) addF(simdPackage, "Float32s.Equal", opLen2(ssaop.OpEqualFloat32s, types.TypeMask), sys.ARM64) diff --git a/src/cmd/compile/internal/ssarewrite/rewritearm64/rewriteARM64.go b/src/cmd/compile/internal/ssarewrite/rewritearm64/rewriteARM64.go index 3f7aa57bc22fb2..f56d229d482fe6 100644 --- a/src/cmd/compile/internal/ssarewrite/rewritearm64/rewriteARM64.go +++ b/src/cmd/compile/internal/ssarewrite/rewritearm64/rewriteARM64.go @@ -730,27 +730,51 @@ func RewriteValue(v *ssa.Value) bool { case ssaop.OpAndInt8x16: v.Op = ssaop.OpARM64VAND16B return true + case ssaop.OpAndNotInt16s: + v.Op = ssaop.OpARM64ZBICD + return true case ssaop.OpAndNotInt16x8: v.Op = ssaop.OpARM64VBIC16B return true + case ssaop.OpAndNotInt32s: + v.Op = ssaop.OpARM64ZBICD + return true case ssaop.OpAndNotInt32x4: v.Op = ssaop.OpARM64VBIC16B return true + case ssaop.OpAndNotInt64s: + v.Op = ssaop.OpARM64ZBICD + return true case ssaop.OpAndNotInt64x2: v.Op = ssaop.OpARM64VBIC16B return true + case ssaop.OpAndNotInt8s: + v.Op = ssaop.OpARM64ZBICD + return true case ssaop.OpAndNotInt8x16: v.Op = ssaop.OpARM64VBIC16B return true + case ssaop.OpAndNotUint16s: + v.Op = ssaop.OpARM64ZBICD + return true case ssaop.OpAndNotUint16x8: v.Op = ssaop.OpARM64VBIC16B return true + case ssaop.OpAndNotUint32s: + v.Op = ssaop.OpARM64ZBICD + return true case ssaop.OpAndNotUint32x4: v.Op = ssaop.OpARM64VBIC16B return true + case ssaop.OpAndNotUint64s: + v.Op = ssaop.OpARM64ZBICD + return true case ssaop.OpAndNotUint64x2: v.Op = ssaop.OpARM64VBIC16B return true + case ssaop.OpAndNotUint8s: + v.Op = ssaop.OpARM64ZBICD + return true case ssaop.OpAndNotUint8x16: v.Op = ssaop.OpARM64VBIC16B return true @@ -20233,6 +20257,22 @@ func rewriteValue_OpARM64ZSELB(v *ssa.Value) bool { v.AddArg4(z, x, y, mask) return true } + // match: (ZSELB (ZBICD x y) x mask) + // result: (ZBICMergingB x y mask) + for { + if v_0.Op != ssaop.OpARM64ZBICD { + break + } + y := v_0.Args[1] + x := v_0.Args[0] + if x != v_1 { + break + } + mask := v_2 + v.Reset(ssaop.OpARM64ZBICMergingB) + v.AddArg3(x, y, mask) + return true + } // match: (ZSELB (ZEORD x y) x mask) // result: (ZEORMergingB x y mask) for { @@ -20697,6 +20737,22 @@ func rewriteValue_OpARM64ZSELD(v *ssa.Value) bool { v.AddArg4(z, x, y, mask) return true } + // match: (ZSELD (ZBICD x y) x mask) + // result: (ZBICMergingD x y mask) + for { + if v_0.Op != ssaop.OpARM64ZBICD { + break + } + y := v_0.Args[1] + x := v_0.Args[0] + if x != v_1 { + break + } + mask := v_2 + v.Reset(ssaop.OpARM64ZBICMergingD) + v.AddArg3(x, y, mask) + return true + } // match: (ZSELD (ZEORD x y) x mask) // result: (ZEORMergingD x y mask) for { @@ -21328,6 +21384,22 @@ func rewriteValue_OpARM64ZSELH(v *ssa.Value) bool { v.AddArg4(z, x, y, mask) return true } + // match: (ZSELH (ZBICD x y) x mask) + // result: (ZBICMergingH x y mask) + for { + if v_0.Op != ssaop.OpARM64ZBICD { + break + } + y := v_0.Args[1] + x := v_0.Args[0] + if x != v_1 { + break + } + mask := v_2 + v.Reset(ssaop.OpARM64ZBICMergingH) + v.AddArg3(x, y, mask) + return true + } // match: (ZSELH (ZEORD x y) x mask) // result: (ZEORMergingH x y mask) for { @@ -21792,6 +21864,22 @@ func rewriteValue_OpARM64ZSELS(v *ssa.Value) bool { v.AddArg4(z, x, y, mask) return true } + // match: (ZSELS (ZBICD x y) x mask) + // result: (ZBICMergingS x y mask) + for { + if v_0.Op != ssaop.OpARM64ZBICD { + break + } + y := v_0.Args[1] + x := v_0.Args[0] + if x != v_1 { + break + } + mask := v_2 + v.Reset(ssaop.OpARM64ZBICMergingS) + v.AddArg3(x, y, mask) + return true + } // match: (ZSELS (ZEORD x y) x mask) // result: (ZEORMergingS x y mask) for { diff --git a/src/simd/archsimd/_gen/simdgen/ops/BitwiseLogic/go_sve.yaml b/src/simd/archsimd/_gen/simdgen/ops/BitwiseLogic/go_sve.yaml index db866f54d5d967..302386562b57ba 100644 --- a/src/simd/archsimd/_gen/simdgen/ops/BitwiseLogic/go_sve.yaml +++ b/src/simd/archsimd/_gen/simdgen/ops/BitwiseLogic/go_sve.yaml @@ -55,3 +55,20 @@ - *uint out: - *uint + +# AndNot — bitwise x &^ y, ZBIC. Width-agnostic like ZAND. +- go: AndNot + asm: "ZBIC" + in: + - *int + - *int + out: + - *int + +- go: AndNot + asm: "ZBIC" + in: + - *uint + - *uint + out: + - *uint diff --git a/src/simd/archsimd/internal/simd_test/binary_sve_arm64_test.go b/src/simd/archsimd/internal/simd_test/binary_sve_arm64_test.go index 40dd55e4f67b26..d4e3cf14a8a406 100644 --- a/src/simd/archsimd/internal/simd_test/binary_sve_arm64_test.go +++ b/src/simd/archsimd/internal/simd_test/binary_sve_arm64_test.go @@ -321,3 +321,17 @@ func TestXorSVE(t *testing.T) { } testInt8sBinary(t, archsimd.Int8s.Xor, xorInt8) } + +func TestAndNotSVE(t *testing.T) { + if !archsimd.ARM64.SVE() { + t.Skip("no SVE") + } + andNotInt8 := func(x, y []int8) []int8 { + r := make([]int8, len(x)) + for i := range x { + r[i] = x[i] &^ y[i] + } + return r + } + testInt8sBinary(t, archsimd.Int8s.AndNot, andNotInt8) +} diff --git a/src/simd/archsimd/ops_sve.go b/src/simd/archsimd/ops_sve.go index 1a5f75d18eabb6..9004f6ac2b2f97 100644 --- a/src/simd/archsimd/ops_sve.go +++ b/src/simd/archsimd/ops_sve.go @@ -172,6 +172,48 @@ func (x Uint32s) And(y Uint32s) Uint32s // Asm: ZAND, CPU Feature: SVE func (x Uint64s) And(y Uint64s) Uint64s +/* AndNot */ + +// AndNot performs a bitwise x &^ y. +// +// Asm: ZBIC, CPU Feature: SVE +func (x Int8s) AndNot(y Int8s) Int8s + +// AndNot performs a bitwise x &^ y. +// +// Asm: ZBIC, CPU Feature: SVE +func (x Int16s) AndNot(y Int16s) Int16s + +// AndNot performs a bitwise x &^ y. +// +// Asm: ZBIC, CPU Feature: SVE +func (x Int32s) AndNot(y Int32s) Int32s + +// AndNot performs a bitwise x &^ y. +// +// Asm: ZBIC, CPU Feature: SVE +func (x Int64s) AndNot(y Int64s) Int64s + +// AndNot performs a bitwise x &^ y. +// +// Asm: ZBIC, CPU Feature: SVE +func (x Uint8s) AndNot(y Uint8s) Uint8s + +// AndNot performs a bitwise x &^ y. +// +// Asm: ZBIC, CPU Feature: SVE +func (x Uint16s) AndNot(y Uint16s) Uint16s + +// AndNot performs a bitwise x &^ y. +// +// Asm: ZBIC, CPU Feature: SVE +func (x Uint32s) AndNot(y Uint32s) Uint32s + +// AndNot performs a bitwise x &^ y. +// +// Asm: ZBIC, CPU Feature: SVE +func (x Uint64s) AndNot(y Uint64s) Uint64s + /* Ceil */ // Ceil rounds elements up to the nearest integer. From e077557cfb885f95c7587a6051b72a54cf961c81 Mon Sep 17 00:00:00 2001 From: Junyang Shao Date: Thu, 27 Aug 2026 15:27:32 -0400 Subject: [PATCH 4/4] runtime, internal/cpu, simd/archsimd: add SVE2 detection on linux/arm64 Capture AT_HWCAP2 in archauxv and expose HWCAP2_SVE2 as cpu.ARM64.HasSVE2 and archsimd.ARM64.SVE2(). The upcoming SVE Mul and MulHigh lower to SVE2-only unpredicated encodings, so their tests need the gate. For #79781. Change-Id: I8a8692e100e2ecdcbcaa66a1aa9b55bdf6e89a75 Reviewed-on: https://go-review.googlesource.com/c/go/+/822941 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: David Chase Auto-Submit: Junyang Shao Reviewed-by: Junyang Shao --- src/internal/cpu/cpu.go | 1 + src/internal/cpu/cpu_arm64_hwcap.go | 7 +++++++ src/runtime/os_linux_arm64.go | 2 ++ src/simd/archsimd/cpu_other.go | 5 +++++ 4 files changed, 15 insertions(+) diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go index cf2d580b71b7b2..56e41a398b0622 100644 --- a/src/internal/cpu/cpu.go +++ b/src/internal/cpu/cpu.go @@ -88,6 +88,7 @@ var ARM64 struct { HasSB bool IsNeoverse bool HasSVE bool + HasSVE2 bool _ CacheLinePad } diff --git a/src/internal/cpu/cpu_arm64_hwcap.go b/src/internal/cpu/cpu_arm64_hwcap.go index a0ef5ec68f70d3..869335884d0745 100644 --- a/src/internal/cpu/cpu_arm64_hwcap.go +++ b/src/internal/cpu/cpu_arm64_hwcap.go @@ -21,6 +21,10 @@ import _ "unsafe" // for linkname //go:linkname HWCap var HWCap uint +// HWCap2 may be initialized by archauxv and +// should not be changed after it was initialized. +var HWCap2 uint + // HWCAP bits. These are exposed by Linux. // See arch/arm64/include/uapi/asm/hwcap.h. const ( @@ -36,6 +40,8 @@ const ( hwcap_SVE = 1 << 22 hwcap_DIT = 1 << 24 hwcap_SB = 1 << 29 + + hwcap2_SVE2 = 1 << 1 ) func hwcapInit(os string) { @@ -54,6 +60,7 @@ func hwcapInit(os string) { ARM64.HasDIT = isSet(HWCap, hwcap_DIT) ARM64.HasSB = isSet(HWCap, hwcap_SB) ARM64.HasSVE = isSet(HWCap, hwcap_SVE) + ARM64.HasSVE2 = isSet(HWCap2, hwcap2_SVE2) // The Samsung S9+ kernel reports support for atomics, but not all cores // actually support them, resulting in SIGILL. See issue #28431. diff --git a/src/runtime/os_linux_arm64.go b/src/runtime/os_linux_arm64.go index ccfb92f8ebdacd..44d5e6f0e16d8a 100644 --- a/src/runtime/os_linux_arm64.go +++ b/src/runtime/os_linux_arm64.go @@ -12,6 +12,8 @@ func archauxv(tag, val uintptr) { switch tag { case _AT_HWCAP: cpu.HWCap = uint(val) + case _AT_HWCAP2: + cpu.HWCap2 = uint(val) } } diff --git a/src/simd/archsimd/cpu_other.go b/src/simd/archsimd/cpu_other.go index ae98fa3d1f54ca..cc68df709389fc 100644 --- a/src/simd/archsimd/cpu_other.go +++ b/src/simd/archsimd/cpu_other.go @@ -23,3 +23,8 @@ func (ARM64Features) PMULL() bool { func (ARM64Features) SVE() bool { return cpu.ARM64.HasSVE } + +// SVE2 returns whether the CPU supports the SVE2 extension. +func (ARM64Features) SVE2() bool { + return cpu.ARM64.HasSVE2 +}