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