| // 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 | |
| } |