blob: 81e08a8572943f199e4408509d5a8508cb0275cf [file]
// 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 specgen
import (
"fmt"
"go/token"
"go/types"
"simd/archsimd/_gen/specgen/specexpr"
"strings"
)
// Func represents a function or method in the SIMD API.
type Func struct {
Name string
// Doc is the function documentation, split into classified paragraphs.
Doc []Paragraph
// Commutative indicates that this operation produces the same result
// regardless of the order of its arguments in Recv and In.
Commutative bool
// The general category of this function or method (useful for overview
// documentation).
Category string
// Recv, if non-zero, is the shape of the receiver. The name of the receiver
// is always "x".
Recv Arg
In []Arg
Out []Arg
// Pos is the source position of this definition.
Pos token.Position
// 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 {
Name string
Type specexpr.Type
}
func (f *Func) Signature() string {
var buf strings.Builder
buf.WriteString("func ")
argList := func(args []Arg, isResults bool) {
if isResults {
if len(args) == 0 {
return
} else if len(args) == 1 && args[0].Name == "" {
// "if there is exactly one unnamed result it may be written as
// an unparenthesized type"
buf.WriteString(args[0].Type.String())
return
}
}
// "Within a list of parameters or results, the names (IdentifierList)
// must either all be present or all be absent." If any are named, we
// must replace empty names with "_".
anyNamed := false
for _, arg := range args {
if arg.Name != "" {
anyNamed = true
break
}
}
buf.WriteByte('(')
for i, arg := range args {
if i > 0 {
buf.WriteString(", ")
}
name := arg.Name
if anyNamed && name == "" {
name = "_"
}
if name != "" {
buf.WriteString(name)
buf.WriteByte(' ')
}
buf.WriteString(arg.Type.String())
}
buf.WriteByte(')')
}
if f.Recv.Type != nil {
argList([]Arg{f.Recv}, false)
buf.WriteByte(' ')
}
buf.WriteString(f.Name)
argList(f.In, false)
if len(f.Out) > 0 {
buf.WriteByte(' ')
argList(f.Out, true)
}
return buf.String()
}
func (f *Func) Decl() string {
var buf strings.Builder
comment, err := FormatComment(f.Doc)
if err != nil {
panic(err)
}
buf.WriteString(comment)
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
}