[dev.simd] simd/archsimd/_gen/cmd/refgen: generate reference implementation
This generates a reference implementation of the SIMD API backed by
the spec implementation.
diff --git a/src/simd/archsimd/_gen/cmd/refgen/main.go b/src/simd/archsimd/_gen/cmd/refgen/main.go
new file mode 100644
index 0000000..af1937a
--- /dev/null
+++ b/src/simd/archsimd/_gen/cmd/refgen/main.go
@@ -0,0 +1,282 @@
+// 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.
+
+// refgen produces a reference implementation of the SIMD API backed by the spec
+// implementation.
+package main
+
+import (
+ "bytes"
+ "cmp"
+ "flag"
+ "fmt"
+ "go/format"
+ "go/types"
+ "io"
+ "log"
+ "maps"
+ "os"
+ "slices"
+ "strings"
+
+ "_gen/specgen"
+ "_gen/specgen/specexpr"
+)
+
+func main() {
+ flag.Usage = func() {
+ w := flag.CommandLine.Output()
+ fmt.Fprintf(w, "usage: refgen [flags] [spec dir]\n")
+ flag.CommandLine.PrintDefaults()
+ }
+
+ flag.Parse()
+ var specDir string
+ switch flag.NArg() {
+ case 0:
+ specDir = specgen.MustFindSpecDir()
+ case 1:
+ specDir = flag.Arg(0)
+ default:
+ flag.Usage()
+ os.Exit(1)
+ }
+
+ funcs, err := specgen.Load(specDir, nil)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s\n", err.Error())
+ os.Exit(1)
+ }
+
+ src := new(bytes.Buffer)
+
+ fmt.Fprintf(src, `// Code generated by 'refgen'. DO NOT EDIT.
+
+package simdref
+
+import "simd/internal/spec"
+
+`)
+
+ // Define all vector types
+ vecTypeSet := make(map[specexpr.Vector]bool)
+ for _, fn := range funcs {
+ if fn.Recv.Type != nil {
+ vecTypeSet[fn.Recv.Type.(specexpr.Vector)] = true
+ }
+ }
+ vecTypes := slices.SortedFunc(maps.Keys(vecTypeSet), func(a, b specexpr.Vector) int {
+ if a.Elem != b.Elem {
+ return cmp.Compare(a.Elem.String(), b.Elem.String())
+ }
+ cmp, ok := a.Width.Compare(b.Width)
+ if ok {
+ return cmp
+ }
+ _, aScale := a.Width.(specexpr.ScalableWidth)
+ _, bScale := b.Width.(specexpr.ScalableWidth)
+ if !aScale && bScale {
+ return 1
+ }
+ return -1
+ })
+ fmt.Fprintf(src, "type (\n")
+ for _, vec := range vecTypes {
+ elem := vec.Elem.String()
+ if vec.Elem.Base == "mask" {
+ elem = fmt.Sprintf("spec.Mask%d", vec.Elem.Bits)
+ }
+
+ fmt.Fprintf(src, "\t%s struct { v []%s }\n", vec.String(), elem)
+ }
+ fmt.Fprintf(src, ")\n\n")
+
+ // Define functions
+ var args []string
+ for _, fn := range funcs {
+ sw := &srcWriter{src, 0}
+
+ fmt.Fprintf(src, "%s {\n", fn.Decl())
+
+ specName, specSig, typeArgs := fn.SpecFunc()
+ specInst, err := types.Instantiate(nil, specSig, typeArgs, false)
+ if err != nil {
+ panic(fmt.Sprintf("instantiating spec function %s: %s", specName, err))
+ }
+
+ specParams := specInst.(*types.Signature).Params()
+ args = args[:0]
+ if fn.Recv.Type != nil {
+ args = append(args, toSpec(fn.Recv.Type, specParams.At(len(args)).Type(), fn.Recv.Name, sw))
+ }
+ for _, in := range fn.In {
+ args = append(args, toSpec(in.Type, specParams.At(len(args)).Type(), in.Name, sw))
+ }
+
+ call := formatCall(specName, typeArgs, args)
+
+ specResults := specInst.(*types.Signature).Results()
+ switch len(fn.Out) {
+ case 0:
+ fmt.Fprintf(src, "\t%s\n", call)
+ case 1:
+ fmt.Fprintf(src, "\treturn %s\n", fromSpec(fn.Out[0].Type, specResults.At(0).Type(), call, sw))
+ default:
+ var tmps []string
+ var res []string
+ for i := range fn.Out {
+ tmp := fmt.Sprintf("r%d", i+1)
+ tmps = append(tmps, tmp)
+ res = append(res, fromSpec(fn.Out[i].Type, specResults.At(i).Type(), tmp, sw))
+ }
+ fmt.Fprintf(src, "\t%s := %s\n", strings.Join(tmps, ", "), call)
+ fmt.Fprintf(src, "\treturn %s\n", strings.Join(res, ", "))
+ }
+ fmt.Fprintf(src, "}\n\n")
+ }
+
+ // Emit source
+ out, err := format.Source(src.Bytes())
+ if err != nil {
+ fmt.Printf("%s", src.Bytes())
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+ fmt.Printf("%s", out)
+}
+
+func formatCall(specName string, typeArgs []types.Type, args []string) string {
+ var callBuf bytes.Buffer
+ fmt.Fprintf(&callBuf, "spec.%s[", specName)
+ for i, typeArg := range typeArgs {
+ if i > 0 {
+ callBuf.WriteString(", ")
+ }
+ types.WriteType(&callBuf, typeArg, specQualifier)
+ }
+ fmt.Fprintf(&callBuf, "](%s)", strings.Join(args, ", "))
+ return callBuf.String()
+}
+
+func specQualifier(pkg *types.Package) string {
+ if pkg.Path() == "simd/internal/spec" {
+ return "spec"
+ }
+ return ""
+}
+
+type srcWriter struct {
+ io.Writer
+ id int
+}
+
+func (w *srcWriter) genIdent() string {
+ ident := fmt.Sprintf("tmp%d", w.id)
+ w.id++
+ return ident
+}
+
+// toSpec returns an expression that converts val from the specref Go type for t
+// to spec type tt. It may write statements to src.
+func toSpec(t specexpr.Type, tt types.Type, val string, src *srcWriter) string {
+ arrayOrSlice := func(tElem specexpr.Type, ttElem types.Type) string {
+ if eVal := toSpec(tElem, ttElem, val, src); eVal == val {
+ // Easy case: the values don't need to change.
+ return val
+ }
+ // Hard case: we need to map each element
+ tmp := src.genIdent()
+ fmt.Fprintf(src, "var %s %s\n", tmp, types.TypeString(tt, specQualifier))
+ fmt.Fprintf(src, "for i := range %s {\n", val)
+ eVal := fromSpec(tElem, ttElem, "("+val+")[i]", src)
+ fmt.Fprintf(src, "\t%s[i] = %s\n", tmp, eVal)
+ fmt.Fprintf(src, "}\n")
+ return tmp
+ }
+
+ switch t := t.(type) {
+ case specexpr.Vector:
+ return val + ".v"
+ case specexpr.Basic:
+ switch tt := tt.(type) {
+ case *types.Named:
+ if tt.Obj().Name() == "UintN" {
+ return "spec.UintN(" + val + ")"
+ }
+ }
+ return val
+ case specexpr.Slice:
+ tt := tt.Underlying().(*types.Slice)
+ return arrayOrSlice(t.Elem, tt.Elem())
+ case specexpr.Array:
+ switch tt := tt.(type) {
+ case *types.Named:
+ if tt.Obj().Name() == "Array" {
+ return toSpec(t.Elem, tt.TypeArgs().At(0), val, src) + "[:]"
+ }
+ }
+ tt := tt.Underlying().(*types.Array)
+ return arrayOrSlice(t.Elem, tt.Elem())
+ case specexpr.Pointer:
+ tt := tt.(*types.Pointer)
+ eVal := toSpec(t.Elem, tt.Elem(), val, src)
+ tmp := src.genIdent()
+ fmt.Fprintf(src, "var %s %s = %s\n", tmp, types.TypeString(tt.Elem(), specQualifier), eVal)
+ return "&" + tmp
+ }
+ log.Fatalf("unexpected specexpr type %s (%T)", t, t)
+ panic("not reachable")
+}
+
+// fromSpec returns an expression that converts val from the spec package type
+// tt to the specref Go type for t. It may write statements to src.
+func fromSpec(t specexpr.Type, tt types.Type, val string, src *srcWriter) string {
+ arrayOrSlice := func(tElem specexpr.Type, ttElem types.Type) string {
+ if eVal := fromSpec(tElem, ttElem, val, src); eVal == val {
+ // Easy case: the values don't need to change.
+ return val
+ }
+ // Hard case: we need to map each element
+ tmp := src.genIdent()
+ fmt.Fprintf(src, "var %s %s\n", tmp, t)
+ fmt.Fprintf(src, "for i := range %s {\n", val)
+ eVal := fromSpec(tElem, ttElem, "("+val+")[i]", src)
+ fmt.Fprintf(src, "\t%s[i] = %s\n", tmp, eVal)
+ fmt.Fprintf(src, "}\n")
+ return tmp
+ }
+
+ switch t := t.(type) {
+ case specexpr.Vector:
+ return fmt.Sprintf("%s{%s}", t, val)
+ case specexpr.Basic:
+ switch tt := tt.(type) {
+ case *types.Named:
+ if tt.Obj().Name() == "UintN" {
+ return fmt.Sprintf("%s(%s)", t, val)
+ }
+ }
+ return val
+ case specexpr.Slice:
+ tt := tt.Underlying().(*types.Slice)
+ return arrayOrSlice(t.Elem, tt.Elem())
+ case specexpr.Array:
+ switch tt := tt.(type) {
+ case *types.Named:
+ if tt.Obj().Name() == "Array" {
+ return fmt.Sprintf("(%s)(%s)", t, fromSpec(t.Elem, tt.TypeArgs().At(0), val, src))
+ }
+ }
+ tt := tt.Underlying().(*types.Array)
+ return arrayOrSlice(t.Elem, tt.Elem())
+ case specexpr.Pointer:
+ tt := tt.(*types.Pointer)
+ eVal := fromSpec(t.Elem, tt.Elem(), val, src)
+ tmp := src.genIdent()
+ fmt.Fprintf(src, "var %s %s = %s\n", tmp, t, eVal)
+ return "&" + tmp
+ }
+ log.Fatalf("unexpected specexpr type %s (%T)", t, t)
+ panic("not reachable")
+}
diff --git a/src/simd/archsimd/_gen/specgen/api.go b/src/simd/archsimd/_gen/specgen/api.go
index f7788c7..87391f0 100644
--- a/src/simd/archsimd/_gen/specgen/api.go
+++ b/src/simd/archsimd/_gen/specgen/api.go
@@ -7,6 +7,7 @@
import (
"_gen/specgen/specexpr"
"fmt"
+ "go/types"
"strings"
)
@@ -23,6 +24,12 @@
In []Arg
Out []Arg
+
+ // specFunc and instance describe the underlying spec function and its
+ // instantiation that led to this API function.
+ specFunc *specFunc
+ typeParamVars map[*types.TypeParam]specexpr.Variable
+ instance *specexpr.Bindings
}
type Arg struct {
@@ -76,3 +83,30 @@
buf.WriteString(f.Signature())
return buf.String()
}
+
+// SpecFunc returns information about the spec package function that generated
+// f. name is the name of the function in the spec package, sig is its
+// uninstantiated signature type, and typeArgs is a slice of the type arguments
+// it was instantiated on to construct f.
+func (f *Func) SpecFunc() (name string, sig *types.Signature, typeArgs []types.Type) {
+ sFn := f.specFunc
+
+ // Build instantiated signature
+ for _, tparam := range sFn.TypeParams {
+ val := f.instance.Get(f.typeParamVars[tparam])
+ switch val := val.(type) {
+ case specexpr.Type:
+ typeArgs = append(typeArgs, specTypeToType(sFn.Pkg, val))
+ case specexpr.Num:
+ wt := sFn.Pkg.WidthTypes[val]
+ if wt == nil {
+ panic(fmt.Sprintf("no spec package type for width %s", val))
+ }
+ typeArgs = append(typeArgs, wt)
+ default:
+ panic("unexpected type parameter value")
+ }
+ }
+
+ return sFn.Name, sFn.Sig, typeArgs
+}
diff --git a/src/simd/archsimd/_gen/specgen/expand.go b/src/simd/archsimd/_gen/specgen/expand.go
index 3be9fb7..f2935e0 100644
--- a/src/simd/archsimd/_gen/specgen/expand.go
+++ b/src/simd/archsimd/_gen/specgen/expand.go
@@ -75,6 +75,7 @@
if fn == nil {
continue
}
+ fn.typeParamVars = typeParamVars
funcs = append(funcs, fn)
}
@@ -89,6 +90,9 @@
func (sFn *specFunc) instantiate(ctx context, b *specexpr.Bindings, argGet map[*types.Var]func(*specexpr.Bindings) specexpr.Type) *Func {
var f Func
+ f.specFunc = sFn
+ f.instance = b
+
// Function or method?
var method bool
if len(sFn.Params) > 0 {
diff --git a/src/simd/archsimd/_gen/specgen/loadspec.go b/src/simd/archsimd/_gen/specgen/loadspec.go
index 72ed1f7..e0aba3a 100644
--- a/src/simd/archsimd/_gen/specgen/loadspec.go
+++ b/src/simd/archsimd/_gen/specgen/loadspec.go
@@ -26,6 +26,9 @@
TypeElems map[types.Type]specexpr.Basic
TypeWidths map[types.Type]specexpr.Num
+ ElemTypes map[specexpr.Basic]types.Type
+ WidthTypes map[specexpr.Num]types.Type
+
VecType types.Type // Uninstantiated Vec type
ArrayType types.Type // Uninstantiated Array type
UintNType types.Type // Uninstantiated UintN type
@@ -187,17 +190,21 @@
// Gather types corresponding to shape constraints
typeElems := make(map[types.Type]specexpr.Basic)
+ elemTypes := make(map[specexpr.Basic]types.Type)
if eltOrMask := lookupType("EltOrMask"); eltOrMask != nil {
for _, elt := range typeSet(eltOrMask) {
basic := shapeElemType(elt)
typeElems[elt] = basic
+ elemTypes[basic] = elt
}
}
typeWidths := make(map[types.Type]specexpr.Num)
+ widthTypes := make(map[specexpr.Num]types.Type)
if width := lookupType("Width"); width != nil {
for _, width := range typeSet(width) {
val := shapeWidthVal(width)
typeWidths[width] = val
+ widthTypes[val] = width
}
}
@@ -213,6 +220,8 @@
Funcs: funcs,
TypeElems: typeElems,
TypeWidths: typeWidths,
+ ElemTypes: elemTypes,
+ WidthTypes: widthTypes,
VecType: vecType,
ArrayType: arrayType,
UintNType: uintNType,
diff --git a/src/simd/archsimd/_gen/specgen/types.go b/src/simd/archsimd/_gen/specgen/types.go
index 6cf7ed3..8c02ebc 100644
--- a/src/simd/archsimd/_gen/specgen/types.go
+++ b/src/simd/archsimd/_gen/specgen/types.go
@@ -163,6 +163,41 @@
panic(fmt.Sprintf("parsing width type %s: %s", t, err))
}
+var basicToBasic = map[specexpr.Basic]types.BasicKind{
+ {Base: "int", Bits: 0}: types.Int,
+ {Base: "int", Bits: 8}: types.Int8,
+ {Base: "int", Bits: 16}: types.Int16,
+ {Base: "int", Bits: 32}: types.Int32,
+ {Base: "int", Bits: 64}: types.Int64,
+ {Base: "uint", Bits: 0}: types.Uint,
+ {Base: "uint", Bits: 8}: types.Uint8,
+ {Base: "uint", Bits: 16}: types.Uint16,
+ {Base: "uint", Bits: 32}: types.Uint32,
+ {Base: "uint", Bits: 64}: types.Uint64,
+ {Base: "float", Bits: 32}: types.Float32,
+ {Base: "float", Bits: 64}: types.Float64,
+}
+
+func specTypeToType(pkg *specPackage, t specexpr.Type) types.Type {
+ switch t := t.(type) {
+ case specexpr.Basic:
+ var t2 types.Type
+ if t.Base == "Mask" {
+ t2 = pkg.ElemTypes[t]
+ } else {
+ if kind, ok := basicToBasic[t]; ok {
+ t2 = types.Typ[kind]
+ }
+ }
+ if t2 == nil {
+ panic(fmt.Sprintf("unknown basic type %s", t))
+ }
+ return t2
+ }
+ // TODO: Implement other specexpr.Type types if we need them
+ panic(fmt.Sprintf("unimplemented specTypeToType for %T", t))
+}
+
type argBinder struct {
ctx context
pkg *specPackage
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
technically an unwanted whitespace, but that will be fixed by formatted output.
// This may be used as a defer. On panic, flush what we have an repanic."and"
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
technically an unwanted whitespace, but that will be fixed by formatted output.
Done
// This may be used as a defer. On panic, flush what we have an repanic.Austin Clements"and"
Done
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Austin Clements would like David Chase and Junyang Shao to review this change.
simd/archsimd/_gen/cmd/refgen: generate reference implementation
This generates a reference implementation of the SIMD API backed by
the spec implementation.
diff --git a/src/simd/archsimd/_gen/cmd/refgen/main.go b/src/simd/archsimd/_gen/cmd/refgen/main.go
new file mode 100644
index 0000000..6db306a
--- /dev/null
+++ b/src/simd/archsimd/_gen/cmd/refgen/main.go
@@ -0,0 +1,289 @@
+// 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.
+
+// refgen produces a reference implementation of the SIMD API backed by the spec
+// implementation.
+package main
+
+import (
+ "bytes"
+ "cmp"
+ "flag"
+ "fmt"
+ "go/format"
+ "go/types"
+ "log"
+ "maps"
+ "os"
+ "slices"
+ "strings"
+
+ "simd/archsimd/_gen/specgen"
+ "simd/archsimd/_gen/specgen/specexpr"
+ src := new(srcWriter)
+ defer src.flushOrDie()
+ if vec.Elem.Base == "Mask" {
+ elem = fmt.Sprintf("spec.Mask%d", vec.Elem.Bits)
+ }
+
+ fmt.Fprintf(src, "\t%s struct { v []%s }\n", vec.String(), elem)
+ }
+ fmt.Fprintf(src, ")\n\n")
+
+ // Define functions
+ var args []string
+ for _, fn := range funcs {
+ fmt.Fprintf(src, "%s {\n", fn.Decl())
+ src.id = 0
+
+ specName, specSig, typeArgs := fn.SpecFunc()
+ specInst, err := types.Instantiate(nil, specSig, typeArgs, false)
+ if err != nil {
+ panic(fmt.Sprintf("instantiating spec function %s: %s", specName, err))
+ }
+
+ specParams := specInst.(*types.Signature).Params()
+ args = args[:0]
+ if fn.Recv.Type != nil {
+ args = append(args, toSpec(fn.Recv.Type, specParams.At(len(args)).Type(), fn.Recv.Name, src))
+ }
+ for _, in := range fn.In {
+ args = append(args, toSpec(in.Type, specParams.At(len(args)).Type(), in.Name, src))
+ }
+
+ call := formatCall(specName, typeArgs, args)
+
+ specResults := specInst.(*types.Signature).Results()
+ switch len(fn.Out) {
+ case 0:
+ fmt.Fprintf(src, "\t%s\n", call)
+ case 1:
+ fmt.Fprintf(src, "\treturn %s\n", fromSpec(fn.Out[0].Type, specResults.At(0).Type(), call, src))
+ default:
+ var tmps []string
+ var res []string
+ for i := range fn.Out {
+ tmp := fmt.Sprintf("r%d", i+1)
+ tmps = append(tmps, tmp)
+ res = append(res, fromSpec(fn.Out[i].Type, specResults.At(i).Type(), tmp, src))
+ }
+ fmt.Fprintf(src, "\t%s := %s\n", strings.Join(tmps, ", "), call)
+ fmt.Fprintf(src, "\treturn %s\n", strings.Join(res, ", "))
+ }
+ fmt.Fprintf(src, "}\n\n")
+ }
+}
+
+type srcWriter struct {
+ bytes.Buffer
+func (w *srcWriter) flushOrDie() {
+ // This may be used as a defer. On panic, flush what we have and repanic.
+ if p := recover(); p != nil {
+ os.Stdout.Write(w.Bytes())
+ panic(p)
+ }
+
+ out, err := format.Source(w.Bytes())
+ if err != nil {
+ os.Stdout.Write(w.Bytes())
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+ os.Stdout.Write(out)
+ w.Reset()
+}
+
+func formatCall(specName string, typeArgs []types.Type, args []string) string {
+ var callBuf bytes.Buffer
+ fmt.Fprintf(&callBuf, "spec.%s[", specName)
+ for i, typeArg := range typeArgs {
+ if i > 0 {
+ callBuf.WriteString(", ")
+ }
+ types.WriteType(&callBuf, typeArg, specQualifier)
+ }
+ fmt.Fprintf(&callBuf, "](%s)", strings.Join(args, ", "))
+ return callBuf.String()
+}
+
+func specQualifier(pkg *types.Package) string {
+ if pkg.Path() == "simd/internal/spec" {
+ return "spec"
+ }
+ return ""
+}
+
index 0a2c0cc..f55c5cf 100644
--- a/src/simd/archsimd/_gen/specgen/api.go
+++ b/src/simd/archsimd/_gen/specgen/api.go
@@ -6,6 +6,7 @@
import (
"fmt"
+ "go/types"
"simd/archsimd/_gen/specgen/specexpr"
index 06e3376..6f6f195 100644
--- a/src/simd/archsimd/_gen/specgen/expand.go
+++ b/src/simd/archsimd/_gen/specgen/expand.go
@@ -75,6 +75,7 @@
if fn == nil {
continue
}
+ fn.typeParamVars = typeParamVars
funcs = append(funcs, fn)
}
@@ -89,6 +90,9 @@
func (sFn *specFunc) instantiate(ctx context, b *specexpr.Bindings, argGet map[*types.Var]func(*specexpr.Bindings) specexpr.Type) *Func {
var f Func
+ f.specFunc = sFn
+ f.instance = b
+
// Function or method?
var method bool
if len(sFn.Params) > 0 {
diff --git a/src/simd/archsimd/_gen/specgen/loadspec.go b/src/simd/archsimd/_gen/specgen/loadspec.go
index 4b96e30..84e9f6c 100644
--- a/src/simd/archsimd/_gen/specgen/loadspec.go
+++ b/src/simd/archsimd/_gen/specgen/loadspec.go
@@ -25,6 +25,9 @@
TypeElems map[types.Type]specexpr.Basic
TypeWidths map[types.Type]specexpr.Num
+ ElemTypes map[specexpr.Basic]types.Type
+ WidthTypes map[specexpr.Num]types.Type
+
VecType types.Type // Uninstantiated Vec type
ArrayType types.Type // Uninstantiated Array type
UintNType types.Type // Uninstantiated UintN type
@@ -186,17 +189,21 @@
// Gather types corresponding to shape constraints
typeElems := make(map[types.Type]specexpr.Basic)
+ elemTypes := make(map[specexpr.Basic]types.Type)
if eltOrMask := lookupType("EltOrMask"); eltOrMask != nil {
for _, elt := range typeSet(eltOrMask) {
basic := shapeElemType(elt)
typeElems[elt] = basic
+ elemTypes[basic] = elt
}
}
typeWidths := make(map[types.Type]specexpr.Num)
+ widthTypes := make(map[specexpr.Num]types.Type)
if width := lookupType("Width"); width != nil {
for _, width := range typeSet(width) {
val := shapeWidthVal(width)
typeWidths[width] = val
+ widthTypes[val] = width
}
}
@@ -212,6 +219,8 @@
Funcs: funcs,
TypeElems: typeElems,
TypeWidths: typeWidths,
+ ElemTypes: elemTypes,
+ WidthTypes: widthTypes,
VecType: vecType,
ArrayType: arrayType,
UintNType: uintNType,
diff --git a/src/simd/archsimd/_gen/specgen/types.go b/src/simd/archsimd/_gen/specgen/types.go
index 07b0a7b..4c1551c 100644
--- a/src/simd/archsimd/_gen/specgen/types.go
+++ b/src/simd/archsimd/_gen/specgen/types.go
@@ -162,6 +162,41 @@
diff --git a/src/simd/internal/spec/TASKS.md b/src/simd/internal/spec/TASKS.md
index 37c3fb7..532f061 100644
--- a/src/simd/internal/spec/TASKS.md
+++ b/src/simd/internal/spec/TASKS.md
@@ -25,7 +25,7 @@
Maybe the hand-written code still lives directly in archsimd, but as
unexported function, and the generator writes the trivial exported API glue
for these.
-- [ ] Generate a full reference implementation for testing that provides the
- SIMD API but just wraps the spec package.
+- [x] Generate a full reference implementation for testing that provides the
+ SIMD API but just wraps the spec package. (Done: _gen/cmd/refgen)
- [ ] Generate conformance tests of the archsimd API against the spec testing
layer.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |