[go] simd/archsimd: simdgen for sve

4 views
Skip to first unread message

Junyang Shao (Gerrit)

unread,
Aug 4, 2026, 4:50:37 PM (3 days ago) Aug 4
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Junyang Shao has uploaded the change for review

Commit message

simd/archsimd: simdgen for sve

WIP

Updates #79781
Change-Id: I4a5416fe794346482edde1d46975ffe2bcf5b31b

Change diff

diff --git a/src/simd/archsimd/_gen/simdgen/arch.go b/src/simd/archsimd/_gen/simdgen/arch.go
index a6498bd..7c8562f 100644
--- a/src/simd/archsimd/_gen/simdgen/arch.go
+++ b/src/simd/archsimd/_gen/simdgen/arch.go
@@ -124,6 +124,10 @@
"8B", "16B", "1D", "4H", "8H", "2S", "4S", "2D", "1Q", "B", "H", "S", "D",
}

+// sveArrangements contains the per-element arrangement letters for ARM64 SVE.
+// SVE vectors are scalable, so the arrangement only encodes the element width.
+var sveArrangements = []string{"B", "H", "S", "D"}
+
const amd64RegInfoParams = "v11, v21, v2k, vkv, v2kv, v2kk, v31, v3kv, vgpv, vgp, vfpv, vfpkv, w11, w21, w2k, wkw, w2kw, w2kk, w31, w3kw, wgpw, wgp, wfpw, wfpkw,\n\twkwload, v21load, v31load, v11load, w21load, w31load, w2kload, w2kwload, w11load, w3kwload, w2kkload, v31x0AtIn2 regInfo"

const arm64RegInfoParams = "v11, v21, v31, vgp, vgpv, vfpv regInfo"
@@ -158,6 +162,21 @@
GeneratedHeader: arm64GeneratedHeader,
Arrangements: arm64Arrangements,
}, nil
+ case "sve":
+ // SVE is not a distinct GOARCH: it targets arm64. This entry exists so
+ // CurrentArch() does not panic during -o yaml runs. godefs generation
+ // for SVE (scalable regInfo shapes, internal/arm64 SSA lowering,
+ // scalable Go types) is not yet wired up.
+ return ArchInfo{
+ Arch: "arm64",
+ ArchUpper: "ARM64",
+ ObjArch: "arm64",
+ RegInfoKeys: arm64RegInfoKeys,
+ RegInfoSet: arm64RegInfoSet,
+ RegInfoParams: arm64RegInfoParams,
+ GeneratedHeader: arm64GeneratedHeader,
+ Arrangements: sveArrangements,
+ }, nil
default:
return ArchInfo{}, fmt.Errorf("unsupported architecture: %s", arch)
}
diff --git a/src/simd/archsimd/_gen/simdgen/go_sve.yaml b/src/simd/archsimd/_gen/simdgen/go_sve.yaml
new file mode 100644
index 0000000..8b9bb63
--- /dev/null
+++ b/src/simd/archsimd/_gen/simdgen/go_sve.yaml
@@ -0,0 +1 @@
+!import ops/*/go_sve.yaml
diff --git a/src/simd/archsimd/_gen/simdgen/main.go b/src/simd/archsimd/_gen/simdgen/main.go
index b1be09e..be672fe 100644
--- a/src/simd/archsimd/_gen/simdgen/main.go
+++ b/src/simd/archsimd/_gen/simdgen/main.go
@@ -4,17 +4,24 @@

// simdgen is an experiment in generating Go <-> asm SIMD mappings.
//
-// Usage: simdgen [-xedPath=path | -arm64Path=path] [-q=query] input.yaml...
+// Usage: simdgen [-xedPath=path | -arm64Path=path | -svePath=path] [-q=query] input.yaml...
//
-// Only one of -xedPath or -arm64Path may be specified.
+// Only one of -xedPath, -arm64Path or -svePath may be specified.
//
// If -xedPath is provided, one of the inputs is a sum of op-code definitions
// generated from the Intel XED data at path.
//
-// If -arm64Path is provided, one of the inputs is a set of instruction
-// definitions parsed from ARM64 ISA XML files at path (obtained from
+// If -arm64Path is provided, one of the inputs is a set of NEON (advsimd)
+// instruction definitions parsed from ARM64 ISA XML files at path (obtained from
// https://developer.arm.com/-/cdn-downloads/permalink/Exploration-Tools-A64-ISA/ISA_A64/ISA_A64_xml_A_profile-2025-12.tar.gz).
//
+// If -svePath is provided, one of the inputs is a set of SVE / SVE2 instruction
+// definitions parsed from the same ARM64 ISA XML files. SVE registers are
+// scalable, so these definitions carry no fixed vector length; see the sve
+// package. Use -arch sve with -svePath. Note: SVE godefs generation is not yet
+// wired up; -svePath is currently intended for -o yaml inspection and for
+// unifying against the SVE op definitions (go_sve.yaml, types_sve.yaml).
+//
// If input YAML files are provided, each file is read as an input value. See
// [unify.Closure.UnmarshalYAML] or "go doc unify.Closure.UnmarshalYAML" for the
// format of these files.
@@ -107,6 +114,7 @@
"strings"

"simd/archsimd/_gen/simdgen/arm64"
+ "simd/archsimd/_gen/simdgen/sve"
"simd/archsimd/_gen/unify"

"gopkg.in/yaml.v3"
@@ -115,6 +123,7 @@
var (
xedPath = flag.String("xedPath", "", "load XED datafiles from `path`")
arm64Path = flag.String("arm64Path", "", "load ARM64 instruction xml definitions from `path`")
+ svePath = flag.String("svePath", "", "load ARM64 SVE instruction xml definitions from `path`")
flagQ = flag.String("q", "", "query: read `def` as another input (skips final validation)")
flagO = flag.String("o", "yaml", "output type: yaml, godefs (generate definitions into a Go source tree")
flagGoDefRoot = flag.String("goroot", ".", "the path to the Go dev directory that will receive the generated files")
@@ -160,12 +169,15 @@
}()
}

- // Default -arch to arm64 when -arm64Path is specified.
- if *arm64Path != "" && *FlagArch != "arm64" {
- if *xedPath != "" {
- log.Fatalf("both -xedPath and -arm64Path specified")
+ // At most one instruction source may be specified.
+ nPaths := 0
+ for _, p := range []string{*xedPath, *arm64Path, *svePath} {
+ if p != "" {
+ nPaths++
}
- // *FlagArch = "arm64"
+ }
+ if nPaths > 1 {
+ log.Fatalf("only one of -xedPath, -arm64Path or -svePath may be specified")
}

// Load instructions into the architecture-specific defs set.
@@ -183,8 +195,16 @@
log.Fatalf("loading ARM64 instructions: %s", err)
}
}
+ case "sve":
+ if *svePath != "" {
+ var err error
+ defs, err = sve.Load(*svePath)
+ if err != nil {
+ log.Fatalf("loading ARM64 SVE instructions: %s", err)
+ }
+ }
default:
- log.Fatalf("simdgen only supports amd64 and arm64")
+ log.Fatalf("simdgen only supports amd64, arm64 and sve")
}

var inputs []unify.Closure
@@ -210,7 +230,7 @@
inputs = append(inputs, defs)

base := filepath.Base(path)
- if base == "go_amd64.yaml" || base == "go_arm64.yaml" {
+ if base == "go_amd64.yaml" || base == "go_arm64.yaml" || base == "go_sve.yaml" {
// These must all be used in the final result
for def := range defs.Summands() {
must[def] = struct{}{}
diff --git a/src/simd/archsimd/_gen/simdgen/ops/AddSub/go_sve.yaml b/src/simd/archsimd/_gen/simdgen/ops/AddSub/go_sve.yaml
new file mode 100644
index 0000000..81007f0
--- /dev/null
+++ b/src/simd/archsimd/_gen/simdgen/ops/AddSub/go_sve.yaml
@@ -0,0 +1,41 @@
+!sum
+# SVE Add family (first-step draft).
+#
+# These unify the unpredicated, vector-by-vector SVE Add instructions emitted by
+# the sve package against the scalable Go types in types_sve.yaml. The Go
+# operation names and docs come from ops/AddSub/categories.yaml.
+#
+# Predicated / immediate SVE Add forms are not emitted yet (see sve.EmitAll), so
+# there are no masked or "…Const" entries here.
+
+# Add — integer ADD and floating-point FADD, unpredicated.
+- go: Add
+ asm: "ZADD|ZFADD"
+ in:
+ - &any
+ go: $t
+ - *any
+ out:
+ - *any
+
+# AddSaturated — signed saturating SQADD.
+- go: AddSaturated
+ asm: "ZSQADD"
+ in:
+ - &int
+ go: $t
+ base: int
+ - *int
+ out:
+ - *int
+
+# AddSaturated — unsigned saturating UQADD.
+- go: AddSaturated
+ asm: "ZUQADD"
+ in:
+ - &uint
+ go: $t
+ base: uint
+ - *uint
+ out:
+ - *uint
diff --git a/src/simd/archsimd/_gen/simdgen/sve/emit.go b/src/simd/archsimd/_gen/simdgen/sve/emit.go
new file mode 100644
index 0000000..46b6567
--- /dev/null
+++ b/src/simd/archsimd/_gen/simdgen/sve/emit.go
@@ -0,0 +1,144 @@
+// 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 sve
+
+import (
+ "fmt"
+ "strings"
+
+ "simd/archsimd/_gen/unify"
+)
+
+// asComment wraps text into // comment lines of at most width columns.
+func asComment(text string, width int) string {
+ text = strings.TrimSpace(text)
+ text = strings.ReplaceAll(text, "&amp;", "&")
+ text = strings.ReplaceAll(text, "\n", " ")
+ words := strings.Fields(text)
+ var lines []string
+ line := ""
+ for _, w := range words {
+ if line != "" {
+ line += " "
+ }
+ line += w
+ if len(line) >= width {
+ lines = append(lines, "// "+line)
+ line = ""
+ }
+ }
+ if line != "" {
+ lines = append(lines, "// "+line)
+ }
+ return strings.Join(lines, "\n")
+}
+
+// Emit renders an operand as a unify value.
+//
+// Vector (Z) and predicate (P) operands are scalable, so they carry a base type
+// and element width but no fixed total bit width or lane count.
+func (op *Operand) Emit() *unify.Value {
+ var db unify.DefBuilder
+ db.Add("class", unify.NewValue(unify.NewStringExact(op.Class)))
+ if op.BaseType != "" {
+ db.Add("base", unify.NewValue(unify.NewStringExact(op.BaseType)))
+ }
+ if op.ElemBits > 0 {
+ db.Add("elemBits", unify.NewValue(unify.NewStringExact(fmt.Sprint(op.ElemBits))))
+ }
+ if op.Role != "" {
+ db.Add("role", unify.NewValue(unify.NewStringExact(op.Role)))
+ }
+ db.Add("asmPos", unify.NewValue(unify.NewStringExact(fmt.Sprint(op.AsmPos))))
+ return unify.NewValue(db.Build())
+}
+
+// emitOne emits a single instruction def for the given base type and element
+// width. ops is the fully-instantiated operand list.
+func (inst *Instruction) emitOne(asm, arrangement string, ops []Operand) *unify.Value {
+ var db unify.DefBuilder
+ db.Add("asm", unify.NewValue(unify.NewStringExact(asm)))
+ db.Add("arrangement", unify.NewValue(unify.NewStringExact(arrangement)))
+ db.Add("goarch", unify.NewValue(unify.NewStringExact("arm64")))
+ db.Add("cpuFeature", unify.NewValue(unify.NewStringExact(inst.CPUFeature())))
+ db.Add("inVariant", unify.NewValue(unify.NewTuple()))
+ if doc := inst.Documentation(); doc != "" {
+ db.Add("details", unify.NewValue(unify.NewStringExact(asComment(doc, 80))))
+ }
+
+ var ins, outs []*unify.Value
+ for i := range ops {
+ if ops[i].Role == "destination" {
+ outs = append(outs, ops[i].Emit())
+ } else {
+ ins = append(ins, ops[i].Emit())
+ }
+ }
+ db.Add("in", unify.NewValue(unify.NewTuple(ins...)))
+ db.Add("out", unify.NewValue(unify.NewTuple(outs...)))
+ return unify.NewValue(db.Build())
+}
+
+// EmitAll emits the unify defs for this instruction, one per (base type,
+// element width) combination.
+//
+// As a first-step draft, it only emits the unpredicated, vector-by-vector forms
+// (no governing predicate, no immediate operand). These map directly to the
+// simplest Go SIMD APIs. Predicated and immediate forms are recognized and
+// skipped; adding them requires plumbing SVE predication through the mask
+// machinery and is left for a follow-up.
+func (inst *Instruction) EmitAll() []*unify.Value {
+ if !inst.IsSVE() || inst.IsAlias() {
+ return nil
+ }
+ template := inst.operands()
+ if len(template) == 0 {
+ return nil
+ }
+ // Skip forms we do not yet model.
+ if hasImm(template) || governingPredicates(template) > 0 {
+ return nil
+ }
+
+ asm := "Z" + inst.Mnemonic()
+ baseSet := inst.BaseTypeSet()
+ sizes := inst.ElementSizes()
+
+ var defs []*unify.Value
+ for _, bt := range []BaseType{BaseInt, BaseUint, BaseFloat} {
+ if bt&baseSet == 0 {
+ continue
+ }
+ base := bt.String()
+ for _, elemBits := range sizes {
+ if bt == BaseFloat && elemBits < 16 {
+ // No half/quarter-word floating point Go types.
+ continue
+ }
+ // Clone the template and instantiate for this shape.
+ ops := make([]Operand, len(template))
+ copy(ops, template)
+ for i := range ops {
+ ops[i].instantiate(base, elemBits)
+ }
+ defs = append(defs, inst.emitOne(asm, elemLetter(elemBits), ops))
+ }
+ }
+ return defs
+}
+
+// String returns the lane interpretation name.
+func (bt BaseType) String() string {
+ switch bt {
+ case BaseInt:
+ return "int"
+ case BaseUint:
+ return "uint"
+ case BaseFloat:
+ return "float"
+ default:
+ return ""
+ }
+}
diff --git a/src/simd/archsimd/_gen/simdgen/sve/instruction.go b/src/simd/archsimd/_gen/simdgen/sve/instruction.go
new file mode 100644
index 0000000..abf08e8
--- /dev/null
+++ b/src/simd/archsimd/_gen/simdgen/sve/instruction.go
@@ -0,0 +1,225 @@
+// 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 sve loads ARM64 SVE / SVE2 instruction definitions from the ARM A64
+// ISA XML files and emits them as simdgen unify values, mirroring the NEON
+// loader in the sibling arm64 package.
+//
+// Unlike NEON, SVE registers are "scalable": their total bit width is the
+// implementation-defined vector length rather than a fixed 128/256/512 bits. So
+// emitted vector operands carry only a base type and an element width, never a
+// fixed bits/lanes count. The corresponding Go types (Int8s, Float32s, ...) and
+// predicate mask types (Mask8s, ...) are similarly length-agnostic.
+//
+// This is a first-step draft: it currently emits the unpredicated,
+// vector-by-vector forms that map directly to the simplest Go APIs (e.g. Add).
+// Predicated and immediate forms are parsed but skipped; see EmitAll.
+package sve
+
+import (
+ "strings"
+
+ "golang.org/x/arch/arm64/instgen/xmlspec"
+)
+
+// Instruction wraps a parsed ARM64 XML instruction with SVE-specific logic.
+type Instruction struct {
+ xmlspec.Instruction
+
+ mnemonicCache string
+}
+
+// BaseType is the lane interpretation set of an instruction.
+type BaseType int
+
+const (
+ BaseInt BaseType = 1 << iota
+ BaseUint
+ BaseFloat
+)
+
+// extractDocVar returns the value of the named docvar, or "".
+func (inst *Instruction) extractDocVar(key string) string {
+ for _, dv := range inst.DocVars {
+ if dv.Key == key {
+ return dv.Value
+ }
+ }
+ return ""
+}
+
+// Mnemonic returns the instruction mnemonic, e.g. "ADD", "FADD", "SQADD".
+func (inst *Instruction) Mnemonic() string {
+ if inst.mnemonicCache != "" {
+ return inst.mnemonicCache
+ }
+ m := inst.extractDocVar("mnemonic")
+ if inst.IsAlias() {
+ m = inst.extractDocVar("alias_mnemonic")
+ }
+ inst.mnemonicCache = m
+ return m
+}
+
+// IsAlias reports whether this XML entry describes an alias of another
+// instruction.
+func (inst *Instruction) IsAlias() bool {
+ return inst.Type == "alias"
+}
+
+// InstrClass returns the instruction class docvar, e.g. "sve" or "sve2".
+func (inst *Instruction) InstrClass() string {
+ return inst.extractDocVar("instr-class")
+}
+
+// IsSVE reports whether this is an SVE or SVE2 instruction.
+func (inst *Instruction) IsSVE() bool {
+ switch inst.InstrClass() {
+ case "sve", "sve2":
+ return true
+ }
+ return false
+}
+
+// CPUFeature returns the simdgen cpuFeature string for this instruction.
+func (inst *Instruction) CPUFeature() string {
+ switch inst.InstrClass() {
+ case "sve2":
+ return "SVE2"
+ default:
+ return "SVE"
+ }
+}
+
+// BaseTypeSet reports which lane interpretations the instruction supports.
+//
+// SVE floating-point instructions are mnemonically distinguished by a leading
+// "F" (FADD, FMUL, ...). Integer instructions apply to both signed and unsigned
+// lanes; simdgen narrows this later via the Go operation definitions (e.g. the
+// signed SQADD vs unsigned UQADD).
+func (inst *Instruction) BaseTypeSet() BaseType {
+ if strings.HasPrefix(inst.Mnemonic(), "F") {
+ return BaseFloat
+ }
+ return BaseInt | BaseUint
+}
+
+// ElementSizes returns the element widths (in bits) that this instruction's
+// <T> arrangement symbol may take, derived from the size table in the XML
+// explanations. Values are among 8/16/32/64.
+func (inst *Instruction) ElementSizes() []int {
+ seen := map[int]bool{}
+ var sizes []int
+ add := func(bits int) {
+ if bits != 0 && !seen[bits] {
+ seen[bits] = true
+ sizes = append(sizes, bits)
+ }
+ }
+ for _, exp := range inst.Explanations.Explanations {
+ // The <T> symbol's definition table lists the element specifiers.
+ if strings.TrimSpace(exp.Symbol.Value) != "<T>" {
+ continue
+ }
+ for _, row := range exp.Definition.Table.TGroup.TBody.Row {
+ for _, entry := range row.Entries {
+ if entry.Class == "symbol" {
+ add(elemLetterBits(strings.TrimSpace(entry.Value)))
+ }
+ }
+ }
+ }
+ return sizes
+}
+
+// elemLetterBits maps an SVE element specifier letter to its bit width.
+func elemLetterBits(letter string) int {
+ switch letter {
+ case "B":
+ return 8
+ case "H":
+ return 16
+ case "S":
+ return 32
+ case "D":
+ return 64
+ default:
+ return 0
+ }
+}
+
+// elemLetter is the inverse of elemLetterBits: it maps a bit width to its SVE
+// element specifier letter (used as the arrangement in emitted defs).
+func elemLetter(bits int) string {
+ switch bits {
+ case 8:
+ return "B"
+ case 16:
+ return "H"
+ case 32:
+ return "S"
+ case 64:
+ return "D"
+ default:
+ return ""
+ }
+}
+
+// asmTemplate returns the first assembly template that contains an arrangement
+// (a ">." sequence, i.e. a register with a <T>/.B/... specifier). SVE Add-family
+// instructions have a single relevant encoding template.
+func (inst *Instruction) asmTemplate() string {
+ for _, class := range inst.Classes.Iclass {
+ for _, enc := range class.Encodings {
+ s := asmTemplateToString(enc.AsmTemplate)
+ if strings.Contains(s, ">.") {
+ return s
+ }
+ }
+ }
+ return ""
+}
+
+// operands parses the operands from the instruction's assembly template.
+func (inst *Instruction) operands() []Operand {
+ return operands(inst.asmTemplate())
+}
+
+// hasImm reports whether any operand is an immediate.
+func hasImm(ops []Operand) bool {
+ for _, op := range ops {
+ if op.Type == OperandImm {
+ return true
+ }
+ }
+ return false
+}
+
+// governingPredicates counts the governing predicate (mask) operands.
+func governingPredicates(ops []Operand) int {
+ n := 0
+ for _, op := range ops {
+ if op.Class == "mask" && op.Role == "mask" {
+ n++
+ }
+ }
+ return n
+}
+
+// Documentation returns a one-line description of the instruction.
+func (inst *Instruction) Documentation() string {
+ if len(inst.Desc.Authored.Paragraphs) > 0 {
+ return inst.Desc.Authored.Paragraphs[0].Text
+ }
+ return inst.Title
+}
+
+// asmTemplateToString flattens an AsmTemplate to its text.
+func asmTemplateToString(t xmlspec.AsmTemplate) string {
+ var b strings.Builder
+ for _, ta := range t.TextA {
+ b.WriteString(ta.Value)
+ }
+ return b.String()
+}
diff --git a/src/simd/archsimd/_gen/simdgen/sve/instruction_test.go b/src/simd/archsimd/_gen/simdgen/sve/instruction_test.go
new file mode 100644
index 0000000..e9e4008
--- /dev/null
+++ b/src/simd/archsimd/_gen/simdgen/sve/instruction_test.go
@@ -0,0 +1,147 @@
+// 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 sve
+
+import (
+ "encoding/xml"
+ "reflect"
+ "strings"
+ "testing"
+
+ "golang.org/x/arch/arm64/instgen/xmlspec"
+)
+
+// sizeTable is the XML explanation table shared by ADD/FADD/etc. that maps the
+// <T> arrangement symbol to the element specifiers B/H/S/D.
+const sizeTable = `
+ <explanations>
+ <explanation>
+ <symbol link="t">&lt;T&gt;</symbol>
+ <definition>
+ <table><tgroup><tbody>
+ <row><entry class="symbol">B</entry></row>
+ <row><entry class="symbol">H</entry></row>
+ <row><entry class="symbol">S</entry></row>
+ <row><entry class="symbol">D</entry></row>
+ </tbody></tgroup></table>
+ </definition>
+ </explanation>
+ </explanations>`
+
+// addUnpred is ADD (vectors, unpredicated): ADD <Zd>.<T>, <Zn>.<T>, <Zm>.<T>.
+const addUnpred = `<instructionsection id="add_z_zz" title="ADD (vectors, unpredicated)" type="instruction">
+ <docvars>
+ <docvar key="instr-class" value="sve"/>
+ <docvar key="mnemonic" value="ADD"/>
+ </docvars>
+ <desc><authored><para>Add active elements of the second source to the first.</para></authored></desc>
+ <classes><iclass><encoding name="add_z_zz">
+ <asmtemplate><text>ADD </text><a link="zd">&lt;Zd&gt;</a><text>.</text><a link="t">&lt;T&gt;</a><text>, </text><a link="zn">&lt;Zn&gt;</a><text>.</text><a link="t">&lt;T&gt;</a><text>, </text><a link="zm">&lt;Zm&gt;</a><text>.</text><a link="t">&lt;T&gt;</a></asmtemplate>
+ </encoding></iclass></classes>` + sizeTable + `</instructionsection>`
+
+// addPred is ADD (vectors, predicated): ADD <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>.
+// It must be skipped by the current draft (governing predicate).
+const addPred = `<instructionsection id="add_z_p_zz" title="ADD (vectors, predicated)" type="instruction">
+ <docvars>
+ <docvar key="instr-class" value="sve"/>
+ <docvar key="mnemonic" value="ADD"/>
+ </docvars>
+ <classes><iclass><encoding name="add_z_p_zz">
+ <asmtemplate><text>ADD </text><a link="zdn">&lt;Zdn&gt;</a><text>.</text><a link="t">&lt;T&gt;</a><text>, </text><a link="pg">&lt;Pg&gt;</a><text>/M, </text><a link="zdn">&lt;Zdn&gt;</a><text>.</text><a link="t">&lt;T&gt;</a><text>, </text><a link="zm">&lt;Zm&gt;</a><text>.</text><a link="t">&lt;T&gt;</a></asmtemplate>
+ </encoding></iclass></classes>` + sizeTable + `</instructionsection>`
+
+// faddUnpred is FADD (vectors, unpredicated): FADD <Zd>.<T>, <Zn>.<T>, <Zm>.<T>.
+// Its size table only lists H/S/D.
+const faddUnpred = `<instructionsection id="fadd_z_zz" title="FADD (vectors, unpredicated)" type="instruction">
+ <docvars>
+ <docvar key="instr-class" value="sve"/>
+ <docvar key="mnemonic" value="FADD"/>
+ </docvars>
+ <classes><iclass><encoding name="fadd_z_zz">
+ <asmtemplate><text>FADD </text><a link="zd">&lt;Zd&gt;</a><text>.</text><a link="t">&lt;T&gt;</a><text>, </text><a link="zn">&lt;Zn&gt;</a><text>.</text><a link="t">&lt;T&gt;</a><text>, </text><a link="zm">&lt;Zm&gt;</a><text>.</text><a link="t">&lt;T&gt;</a></asmtemplate>
+ </encoding></iclass></classes>
+ <explanations>
+ <explanation>
+ <symbol link="t">&lt;T&gt;</symbol>
+ <definition><table><tgroup><tbody>
+ <row><entry class="symbol">H</entry></row>
+ <row><entry class="symbol">S</entry></row>
+ <row><entry class="symbol">D</entry></row>
+ </tbody></tgroup></table></definition>
+ </explanation>
+ </explanations>
+</instructionsection>`
+
+func parse(t *testing.T, x string) *Instruction {
+ t.Helper()
+ var ip xmlspec.InstructionParsed
+ if err := xml.Unmarshal([]byte(x), &ip); err != nil {
+ t.Fatalf("unmarshal: %v", err)
+ }
+ return &Instruction{Instruction: ip.Instruction}
+}
+
+func TestMnemonicAndClass(t *testing.T) {
+ inst := parse(t, addUnpred)
+ if got := inst.Mnemonic(); got != "ADD" {
+ t.Errorf("Mnemonic = %q, want ADD", got)
+ }
+ if !inst.IsSVE() {
+ t.Errorf("IsSVE = false, want true")
+ }
+ if got := inst.CPUFeature(); got != "SVE" {
+ t.Errorf("CPUFeature = %q, want SVE", got)
+ }
+}
+
+func TestElementSizes(t *testing.T) {
+ if got := parse(t, addUnpred).ElementSizes(); !reflect.DeepEqual(got, []int{8, 16, 32, 64}) {
+ t.Errorf("ADD ElementSizes = %v, want [8 16 32 64]", got)
+ }
+ if got := parse(t, faddUnpred).ElementSizes(); !reflect.DeepEqual(got, []int{16, 32, 64}) {
+ t.Errorf("FADD ElementSizes = %v, want [16 32 64]", got)
+ }
+}
+
+func TestOperands(t *testing.T) {
+ ops := parse(t, addUnpred).operands()
+ var got []string
+ for _, op := range ops {
+ got = append(got, op.Type.String()+":"+op.Role)
+ }
+ want := []string{"ZReg:destination", "ZReg:op0", "ZReg:op1"}
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("operands = %v, want %v", got, want)
+ }
+}
+
+func TestEmitAllUnpredicated(t *testing.T) {
+ // ADD: int|uint × {8,16,32,64} = 8 defs.
+ defs := parse(t, addUnpred).EmitAll()
+ if len(defs) != 8 {
+ t.Fatalf("ADD EmitAll = %d defs, want 8", len(defs))
+ }
+ s := defs[0].String()
+ for _, want := range []string{"ZADD", "arm64", "SVE", "elemBits"} {
+ if !strings.Contains(s, want) {
+ t.Errorf("emitted def missing %q:\n%s", want, s)
+ }
+ }
+
+ // FADD: float × {16,32,64} = 3 defs.
+ if got := len(parse(t, faddUnpred).EmitAll()); got != 3 {
+ t.Errorf("FADD EmitAll = %d defs, want 3", got)
+ }
+}
+
+func TestEmitAllSkipsPredicated(t *testing.T) {
+ inst := parse(t, addPred)
+ if governingPredicates(inst.operands()) != 1 {
+ t.Fatalf("expected one governing predicate in predicated ADD")
+ }
+ if got := inst.EmitAll(); got != nil {
+ t.Errorf("predicated ADD emitted %d defs, want 0 (skipped)", len(got))
+ }
+}
diff --git a/src/simd/archsimd/_gen/simdgen/sve/load.go b/src/simd/archsimd/_gen/simdgen/sve/load.go
new file mode 100644
index 0000000..8c8f047
--- /dev/null
+++ b/src/simd/archsimd/_gen/simdgen/sve/load.go
@@ -0,0 +1,50 @@
+// 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 sve
+
+import (
+ "sort"
+
+ "simd/archsimd/_gen/unify"
+
+ "golang.org/x/arch/arm64/instgen/xmlspec"
+)
+
+// ParseInstructions parses the ARM64 ISA XML files at path and returns the
+// SVE / SVE2 instructions.
+func ParseInstructions(path string) ([]*Instruction, error) {
+ xmlInsts := xmlspec.ParseXMLFiles(path)
+
+ var insts []*Instruction
+ for _, xmlInst := range xmlInsts {
+ if xmlInst == nil {
+ continue
+ }
+ inst := &Instruction{Instruction: xmlInst.Instruction}
+ if inst.Mnemonic() == "" || !inst.IsSVE() {
+ continue
+ }
+ insts = append(insts, inst)
+ }
+
+ sort.Slice(insts, func(i, j int) bool {
+ return insts[i].Mnemonic() < insts[j].Mnemonic()
+ })
+ return insts, nil
+}
+
+// Load parses the ARM64 ISA XML files at path and returns the SVE / SVE2
+// instruction definitions as simdgen unify values.
+func Load(path string) ([]*unify.Value, error) {
+ insts, err := ParseInstructions(path)
+ if err != nil {
+ return nil, err
+ }
+ var defs []*unify.Value
+ for _, inst := range insts {
+ defs = append(defs, inst.EmitAll()...)
+ }
+ return defs, nil
+}
diff --git a/src/simd/archsimd/_gen/simdgen/sve/operands.go b/src/simd/archsimd/_gen/simdgen/sve/operands.go
new file mode 100644
index 0000000..3506e7c
--- /dev/null
+++ b/src/simd/archsimd/_gen/simdgen/sve/operands.go
@@ -0,0 +1,242 @@
+// 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 sve
+
+import (
+ "fmt"
+ "strings"
+)
+
+// OperandType classifies an SVE instruction operand.
+type OperandType int
+
+const (
+ // OperandZReg is a scalable vector register (Z), e.g. <Zd>.<T>, <Zn>.<T>.
+ // It has no fixed total bit width: the width is the implementation-defined
+ // vector length. Only its element type and element width are known.
+ OperandZReg OperandType = iota
+ // OperandPReg is a scalable predicate register (P), e.g. <Pg>/M, <Pd>.<T>.
+ // A predicate is modeled as a Go mask value.
+ OperandPReg
+ // OperandGReg is a general-purpose scalar register (W/X/R).
+ OperandGReg
+ // OperandImm is an immediate.
+ OperandImm
+)
+
+func (t OperandType) String() string {
+ switch t {
+ case OperandZReg:
+ return "ZReg"
+ case OperandPReg:
+ return "PReg"
+ case OperandGReg:
+ return "GReg"
+ case OperandImm:
+ return "Imm"
+ default:
+ return "Unknown"
+ }
+}
+
+// Operand is an SVE instruction operand instantiated for a concrete element size.
+type Operand struct {
+ Type OperandType
+ Class string // "vreg", "mask", "greg", "immediate"
+ BaseType string // "int", "uint", "float" (for vreg/mask/greg)
+ ElemBits int // element width in bits (8/16/32/64)
+ // Role is the operand's role. Possible values:
+ // - "destination": the output register
+ // - "op0", "op1", ...: input registers
+ // - "mask": a governing predicate (Pg/M or Pg/Z)
+ Role string
+ // Predication is "M" (merging) or "Z" (zeroing) for governing predicates,
+ // otherwise "".
+ Predication string
+ // AsmPos is the position in the Go assembly syntax (0 for the destination
+ // register, 1+ for inputs). It mirrors the source template order.
+ AsmPos int
+}
+
+// parsedOperand is a classified but not-yet-instantiated operand token.
+type parsedOperand struct {
+ text string // raw token, e.g. "<Zd>.<T>", "<Pg>/M"
+ asmPos int
+ operandType OperandType
+ isDestination bool
+ predication string // "M", "Z" or ""
+}
+
+// operands parses the operands of an SVE instruction from its assembly
+// template (e.g. "ADD <Zd>.<T>, <Zn>.<T>, <Zm>.<T>"). It returns the operands
+// in the canonical simdgen order: outputs first, then governing predicate, then
+// inputs.
+func operands(asmTemplate string) []Operand {
+ tokens := tokenizeTemplate(asmTemplate)
+ parsed := make([]parsedOperand, 0, len(tokens))
+ for i, tok := range tokens {
+ parsed = append(parsed, classifyToken(tok, i))
+ }
+ return buildOperandList(parsed)
+}
+
+// tokenizeTemplate strips the mnemonic and splits the remaining operands on
+// commas that are not nested inside brackets.
+func tokenizeTemplate(template string) []string {
+ template = stripMnemonic(template)
+ var tokens []string
+ depth := 0
+ cur := strings.Builder{}
+ flush := func() {
+ s := strings.TrimSpace(cur.String())
+ if s != "" {
+ tokens = append(tokens, s)
+ }
+ cur.Reset()
+ }
+ for _, r := range template {
+ switch r {
+ case '[', '{':
+ depth++
+ case ']', '}':
+ depth--
+ case ',':
+ if depth == 0 {
+ flush()
+ continue
+ }
+ }
+ cur.WriteRune(r)
+ }
+ flush()
+ return tokens
+}
+
+// stripMnemonic removes the leading mnemonic from an assembly template.
+func stripMnemonic(template string) string {
+ if _, after, ok := strings.Cut(strings.TrimSpace(template), " "); ok {
+ return strings.TrimSpace(after)
+ }
+ return template
+}
+
+// classifyToken determines an operand's type, whether it is a destination, and
+// its predication (for governing predicates).
+func classifyToken(text string, asmPos int) parsedOperand {
+ p := parsedOperand{text: text, asmPos: asmPos}
+ switch {
+ case strings.HasPrefix(text, "<Z"):
+ p.operandType = OperandZReg
+ p.isDestination = isDestinationReg(text)
+ case strings.HasPrefix(text, "<P"):
+ p.operandType = OperandPReg
+ p.isDestination = isDestinationReg(text)
+ if strings.HasSuffix(text, "/M") {
+ p.predication = "M"
+ } else if strings.HasSuffix(text, "/Z") {
+ p.predication = "Z"
+ }
+ case strings.HasPrefix(text, "<W"), strings.HasPrefix(text, "<X"), strings.HasPrefix(text, "<R"):
+ p.operandType = OperandGReg
+ p.isDestination = isDestinationReg(text)
+ case strings.HasPrefix(text, "#"):
+ p.operandType = OperandImm
+ default:
+ p.operandType = OperandZReg
+ }
+ return p
+}
+
+// isDestinationReg reports whether a register token names a destination
+// register. In ARM naming, the register letter following the class letter is
+// 'd' for destinations (e.g. <Zd>, <Zda>, <Zdn>, <Pd>).
+func isDestinationReg(text string) bool {
+ // text is like "<Zd>.<T>" or "<Pg>/M". Extract the inner name.
+ name := text
+ if i := strings.IndexByte(name, '<'); i >= 0 {
+ name = name[i+1:]
+ }
+ if i := strings.IndexByte(name, '>'); i >= 0 {
+ name = name[:i]
+ }
+ // name is like "Zd", "Zdn", "Zm", "Pg". The class letter is name[0],
+ // the register-role letter is name[1].
+ return len(name) >= 2 && name[1] == 'd'
+}
+
+// buildOperandList lowers parsed operands into Operands ordered as
+// outputs + governing-predicate + inputs. Roles are assigned here.
+func buildOperandList(parsed []parsedOperand) []Operand {
+ var outs, masks, ins []Operand
+ inputCount := 0
+ for _, p := range parsed {
+ switch p.operandType {
+ case OperandPReg:
+ if p.predication != "" {
+ // Governing predicate: modeled as a mask input.
+ masks = append(masks, Operand{
+ Type: OperandPReg, Class: "mask", Role: "mask",
+ Predication: p.predication, AsmPos: p.asmPos,
+ })
+ continue
+ }
+ // Predicate result or source (e.g. compares); treat like a reg.
+ op := Operand{Type: OperandPReg, Class: "mask", AsmPos: p.asmPos}
+ if p.isDestination {
+ op.Role = "destination"
+ outs = append(outs, op)
+ } else {
+ op.Role = inputRole(inputCount)
+ inputCount++
+ ins = append(ins, op)
+ }
+ case OperandImm:
+ ins = append(ins, Operand{
+ Type: OperandImm, Class: "immediate",
+ Role: inputRole(inputCount), AsmPos: p.asmPos,
+ })
+ inputCount++
+ default:
+ class := "vreg"
+ if p.operandType == OperandGReg {
+ class = "greg"
+ }
+ op := Operand{Type: p.operandType, Class: class, AsmPos: p.asmPos}
+ if p.isDestination {
+ op.Role = "destination"
+ outs = append(outs, op)
+ } else {
+ op.Role = inputRole(inputCount)
+ inputCount++
+ ins = append(ins, op)
+ }
+ }
+ }
+ result := append(outs, masks...)
+ return append(result, ins...)
+}
+
+// inputRole names an input operand: "op0", "op1", ...
+func inputRole(index int) string {
+ return fmt.Sprintf("op%d", index)
+}
+
+// instantiate stamps a concrete element size and base type into a vector,
+// predicate, or general register operand.
+func (op *Operand) instantiate(baseType string, elemBits int) {
+ switch op.Type {
+ case OperandZReg:
+ op.BaseType = baseType
+ op.ElemBits = elemBits
+ case OperandPReg:
+ // Predicates are always integer masks; their element width tracks the
+ // governed vector's element width.
+ op.BaseType = "int"
+ op.ElemBits = elemBits
+ case OperandGReg:
+ op.BaseType = baseType
+ op.ElemBits = elemBits
+ }
+}
diff --git a/src/simd/archsimd/_gen/simdgen/sve_integration_test.go b/src/simd/archsimd/_gen/simdgen/sve_integration_test.go
new file mode 100644
index 0000000..e0fa260
--- /dev/null
+++ b/src/simd/archsimd/_gen/simdgen/sve_integration_test.go
@@ -0,0 +1,94 @@
+// 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 (
+ "encoding/xml"
+ "strings"
+ "testing"
+
+ "simd/archsimd/_gen/simdgen/sve"
+ "simd/archsimd/_gen/unify"
+
+ "golang.org/x/arch/arm64/instgen/xmlspec"
+)
+
+// addXML is ADD (vectors, unpredicated): ADD <Zd>.<T>, <Zn>.<T>, <Zm>.<T>,
+// standing in for the real ARM64 ISA XML (which is not vendored).
+const addXML = `<instructionsection id="add_z_zz" title="ADD (vectors, unpredicated)" type="instruction">
+ <docvars>
+ <docvar key="instr-class" value="sve"/>
+ <docvar key="mnemonic" value="ADD"/>
+ </docvars>
+ <desc><authored><para>Add active elements.</para></authored></desc>
+ <classes><iclass><encoding name="add_z_zz">
+ <asmtemplate><text>ADD </text><a link="zd">&lt;Zd&gt;</a><text>.</text><a link="t">&lt;T&gt;</a><text>, </text><a link="zn">&lt;Zn&gt;</a><text>.</text><a link="t">&lt;T&gt;</a><text>, </text><a link="zm">&lt;Zm&gt;</a><text>.</text><a link="t">&lt;T&gt;</a></asmtemplate>
+ </encoding></iclass></classes>
+ <explanations><explanation>
+ <symbol link="t">&lt;T&gt;</symbol>
+ <definition><table><tgroup><tbody>
+ <row><entry class="symbol">B</entry></row>
+ <row><entry class="symbol">H</entry></row>
+ <row><entry class="symbol">S</entry></row>
+ <row><entry class="symbol">D</entry></row>
+ </tbody></tgroup></table></definition>
+ </explanation></explanations>
+</instructionsection>`
+
+// TestSVEAddUnifies checks that the SVE loader's emitted defs unify with the
+// SVE Add operation and type definitions to yield concrete Go API mappings.
+func TestSVEAddUnifies(t *testing.T) {
+ var ip xmlspec.InstructionParsed
+ if err := xml.Unmarshal([]byte(addXML), &ip); err != nil {
+ t.Fatalf("unmarshal: %v", err)
+ }
+ inst := &sve.Instruction{Instruction: ip.Instruction}
+ defs := inst.EmitAll()
+ if len(defs) == 0 {
+ t.Fatal("EmitAll produced no defs")
+ }
+
+ inputs := []unify.Closure{unify.NewSum(defs...)}
+ for _, path := range []string{"go_sve.yaml", "types_sve.yaml", "categories.yaml"} {
+ cl, err := unify.ReadFile(path, unify.ReadOpts{})
+ if err != nil {
+ t.Fatalf("ReadFile %s: %v", path, err)
+ }
+ inputs = append(inputs, cl)
+ }
+
+ unified, err := unify.Unify(inputs...)
+ if err != nil {
+ t.Fatalf("Unify: %v", err)
+ }
+
+ // Collect the (go, asm, in-types) of every exact result.
+ var got []string
+ sawInt8s, sawUint8s := false, false
+ for v := range unified.All() {
+ if !v.Exact() {
+ continue
+ }
+ s := v.String()
+ if strings.Contains(s, "Add") {
+ if strings.Contains(s, "Int8s") {
+ sawInt8s = true
+ }
+ if strings.Contains(s, "Uint8s") {
+ sawUint8s = true
+ }
+ got = append(got, s)
+ }
+ }
+ if len(got) == 0 {
+ t.Fatal("no Add results after unification")
+ }
+ if !sawInt8s {
+ t.Errorf("expected an Int8s Add mapping; results:\n%s", strings.Join(got, "\n---\n"))
+ }
+ if !sawUint8s {
+ t.Errorf("expected a Uint8s Add mapping")
+ }
+}
diff --git a/src/simd/archsimd/_gen/simdgen/types_sve.yaml b/src/simd/archsimd/_gen/simdgen/types_sve.yaml
new file mode 100644
index 0000000..5acf98f
--- /dev/null
+++ b/src/simd/archsimd/_gen/simdgen/types_sve.yaml
@@ -0,0 +1,35 @@
+# This file defines the possible types of each SVE operand and result.
+#
+# Unlike the fixed-width NEON/AVX types in types.yaml, SVE vectors are
+# "scalable": their total bit width is the implementation-defined vector length,
+# not a compile-time constant. So these shapes carry only a base type and an
+# element width (elemBits) — never a fixed bits/lanes count. The Go types are
+# correspondingly length-agnostic (Int8s, Float32s, ...) and predicates are
+# modeled as scalable masks (Mask8s, ...).
+#
+# Used with -arch sve; see go_sve.yaml for the operations that unify against
+# these shapes and the SVE instruction definitions produced by the sve package.
+
+in: !repeat
+- !sum &types
+ - {class: vreg, go: Int8s, base: "int", elemBits: 8}
+ - {class: vreg, go: Int16s, base: "int", elemBits: 16}
+ - {class: vreg, go: Int32s, base: "int", elemBits: 32}
+ - {class: vreg, go: Int64s, base: "int", elemBits: 64}
+ - {class: vreg, go: Uint8s, base: "uint", elemBits: 8}
+ - {class: vreg, go: Uint16s, base: "uint", elemBits: 16}
+ - {class: vreg, go: Uint32s, base: "uint", elemBits: 32}
+ - {class: vreg, go: Uint64s, base: "uint", elemBits: 64}
+ - {class: vreg, go: Float32s, base: "float", elemBits: 32}
+ - {class: vreg, go: Float64s, base: "float", elemBits: 64}
+
+ - {class: mask, go: Mask8s, base: "int", elemBits: 8}
+ - {class: mask, go: Mask16s, base: "int", elemBits: 16}
+ - {class: mask, go: Mask32s, base: "int", elemBits: 32}
+ - {class: mask, go: Mask64s, base: "int", elemBits: 64}
+
+ - {class: immediate, go: Immediate}
+inVariant: !repeat
+- *types
+out: !repeat
+- *types

Change information

Files:
  • M src/simd/archsimd/_gen/simdgen/arch.go
  • A src/simd/archsimd/_gen/simdgen/go_sve.yaml
  • M src/simd/archsimd/_gen/simdgen/main.go
  • A src/simd/archsimd/_gen/simdgen/ops/AddSub/go_sve.yaml
  • A src/simd/archsimd/_gen/simdgen/sve/emit.go
  • A src/simd/archsimd/_gen/simdgen/sve/instruction.go
  • A src/simd/archsimd/_gen/simdgen/sve/instruction_test.go
  • A src/simd/archsimd/_gen/simdgen/sve/load.go
  • A src/simd/archsimd/_gen/simdgen/sve/operands.go
  • A src/simd/archsimd/_gen/simdgen/sve_integration_test.go
  • A src/simd/archsimd/_gen/simdgen/types_sve.yaml
Change size: XL
Delta: 11 files changed, 1029 insertions(+), 11 deletions(-)
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I4a5416fe794346482edde1d46975ffe2bcf5b31b
Gerrit-Change-Number: 810560
Gerrit-PatchSet: 1
Gerrit-Owner: Junyang Shao <su...@golang.org>
unsatisfied_requirement
satisfied_requirement
open
diffy

Junyang Shao (Gerrit)

unread,
Aug 5, 2026, 4:28:27 PM (2 days ago) Aug 5
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
Attention needed from Junyang Shao

Junyang Shao uploaded new patchset

Junyang Shao uploaded patch set #2 to this change.
Open in Gerrit

Related details

Attention is currently required from:
  • Junyang Shao
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newpatchset
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I4a5416fe794346482edde1d46975ffe2bcf5b31b
Gerrit-Change-Number: 810560
Gerrit-PatchSet: 2
Gerrit-Owner: Junyang Shao <su...@golang.org>
Gerrit-Reviewer: Junyang Shao <shaoj...@google.com>
Gerrit-Attention: Junyang Shao <shaoj...@google.com>
unsatisfied_requirement
satisfied_requirement
open
diffy

Junyang Shao (Gerrit)

unread,
Aug 5, 2026, 5:37:09 PM (2 days ago) Aug 5
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
Attention needed from Junyang Shao

Junyang Shao uploaded new patchset

Junyang Shao uploaded patch set #3 to this change.
Open in Gerrit

Related details

Attention is currently required from:
  • Junyang Shao
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newpatchset
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I4a5416fe794346482edde1d46975ffe2bcf5b31b
Gerrit-Change-Number: 810560
Gerrit-PatchSet: 3
unsatisfied_requirement
satisfied_requirement
open
diffy

Junyang Shao (Gerrit)

unread,
Aug 6, 2026, 11:41:34 PM (23 hours ago) Aug 6
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
Attention needed from Junyang Shao

Junyang Shao uploaded new patchset

Junyang Shao uploaded patch set #4 to this change.
Open in Gerrit

Related details

Attention is currently required from:
  • Junyang Shao
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newpatchset
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I4a5416fe794346482edde1d46975ffe2bcf5b31b
Gerrit-Change-Number: 810560
Gerrit-PatchSet: 4
unsatisfied_requirement
satisfied_requirement
open
diffy

Junyang Shao (Gerrit)

unread,
2:59 PM (8 hours ago) 2:59 PM
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
Attention needed from Junyang Shao

Junyang Shao uploaded new patchset

Junyang Shao uploaded patch set #5 to this change.
Open in Gerrit

Related details

Attention is currently required from:
  • Junyang Shao
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newpatchset
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I4a5416fe794346482edde1d46975ffe2bcf5b31b
Gerrit-Change-Number: 810560
Gerrit-PatchSet: 5
unsatisfied_requirement
satisfied_requirement
open
diffy

Junyang Shao (Gerrit)

unread,
3:00 PM (8 hours ago) 3:00 PM
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
Attention needed from Junyang Shao

Junyang Shao uploaded new patchset

Junyang Shao uploaded patch set #6 to this change.
Open in Gerrit

Related details

Attention is currently required from:
  • Junyang Shao
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newpatchset
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I4a5416fe794346482edde1d46975ffe2bcf5b31b
Gerrit-Change-Number: 810560
Gerrit-PatchSet: 6
unsatisfied_requirement
satisfied_requirement
open
diffy

Junyang Shao (Gerrit)

unread,
3:00 PM (8 hours ago) 3:00 PM
to Junyang Shao, goph...@pubsubhelper.golang.org, David Chase, Cherry Mui, golang-co...@googlegroups.com
Attention needed from Cherry Mui, David Chase and Junyang Shao

Junyang Shao voted

Code-Review+2
Commit-Queue+1
Open in Gerrit

Related details

Attention is currently required from:
  • Cherry Mui
  • David Chase
  • Junyang Shao
Submit Requirements:
  • requirement satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I4a5416fe794346482edde1d46975ffe2bcf5b31b
Gerrit-Change-Number: 810560
Gerrit-PatchSet: 6
Gerrit-Owner: Junyang Shao <su...@golang.org>
Gerrit-Reviewer: Cherry Mui <cher...@google.com>
Gerrit-Reviewer: David Chase <drc...@google.com>
Gerrit-Reviewer: Junyang Shao <shaoj...@google.com>
Gerrit-Attention: Cherry Mui <cher...@google.com>
Gerrit-Attention: David Chase <drc...@google.com>
Gerrit-Attention: Junyang Shao <su...@golang.org>
Gerrit-Comment-Date: Fri, 07 Aug 2026 19:00:39 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
satisfied_requirement
unsatisfied_requirement
open
diffy

Junyang Shao (Gerrit)

unread,
3:01 PM (8 hours ago) 3:01 PM
to Junyang Shao, goph...@pubsubhelper.golang.org, golang...@luci-project-accounts.iam.gserviceaccount.com, David Chase, Cherry Mui, golang-co...@googlegroups.com
Attention needed from Cherry Mui, David Chase and Junyang Shao

Junyang Shao added 1 comment

Patchset-level comments
File-level comment, Patchset 6 (Latest):
Junyang Shao . resolved

This CL is drafted by Claude.

I iterated on this and did some cleanup, some redundant codes still exist, but I feel like it's good enough :D.

Open in Gerrit

Related details

Attention is currently required from:
  • Cherry Mui
  • David Chase
  • Junyang Shao
Submit Requirements:
  • requirement satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I4a5416fe794346482edde1d46975ffe2bcf5b31b
Gerrit-Change-Number: 810560
Gerrit-PatchSet: 6
Gerrit-Owner: Junyang Shao <su...@golang.org>
Gerrit-Reviewer: Cherry Mui <cher...@google.com>
Gerrit-Reviewer: David Chase <drc...@google.com>
Gerrit-Reviewer: Junyang Shao <shaoj...@google.com>
Gerrit-Attention: Cherry Mui <cher...@google.com>
Gerrit-Attention: David Chase <drc...@google.com>
Gerrit-Attention: Junyang Shao <su...@golang.org>
Gerrit-Comment-Date: Fri, 07 Aug 2026 19:01:30 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy
Reply all
Reply to author
Forward
0 new messages