1
2
3
4
5 package specgen
6
7 import (
8 "fmt"
9 "go/types"
10 "regexp"
11 "simd/archsimd/_gen/specgen/specexpr"
12 "strings"
13 )
14
15 func (sFn *specFunc) expand(ctx context, opts *LoadOptions) []*Func {
16 ctx = ctx.at(sFn.Pos)
17
18 var solver specexpr.Solver
19
20 if opts.Trace != nil {
21 fmt.Fprintf(opts.Trace, "## %s%s\n", sFn.Name, sFn.Sig)
22 solver.SetTrace(opts.Trace)
23 }
24
25
26 typeParamVars := make(map[*types.TypeParam]specexpr.Variable)
27 for _, param := range sFn.TypeParams {
28 types, err := constraintToDomain(sFn.Pkg, param.Constraint())
29 if err != nil {
30 panic(err)
31 }
32 varDef := specexpr.Variable("$" + param.String())
33 solver.Declare(varDef, types)
34 typeParamVars[param] = varDef
35 }
36
37 b := &argBinder{ctx, sFn.Pkg, &solver, typeParamVars}
38 argGet := make(map[*types.Var]func(*specexpr.Bindings) specexpr.Type)
39 ok := true
40 for _, v := range sFn.Params {
41 get := b.bindArg(v.Name(), v.Type())
42 ok = ok && (get != nil)
43 argGet[v] = get
44 }
45 for _, v := range sFn.Results {
46 get := b.bindArg(v.Name(), v.Type())
47 ok = ok && (get != nil)
48 argGet[v] = get
49 }
50
51 for _, expr := range sFn.Requirements {
52 solver.Assert(expr)
53 }
54 if !ok {
55 return nil
56 }
57
58
59 defer func() {
60 p := recover()
61 if p != nil {
62 var buf strings.Builder
63 solver.Fprint(&buf)
64 panic(fmt.Sprintf("%s: %s\n%s", ctx.root.fset.Position(sFn.Pos), p, buf.String()))
65 }
66 }()
67 var funcs []*Func
68 for soln, err := range solver.Solve() {
69 if err != nil {
70 ctx.errorf("%s", err)
71 continue
72 }
73
74 fn := sFn.instantiate(ctx, soln, argGet)
75 if fn == nil {
76 continue
77 }
78 fn.typeParamVars = typeParamVars
79
80 funcs = append(funcs, fn)
81 }
82
83 if len(funcs) == 0 {
84 ctx.errorf("impossible constraints (try -f %s -trace)", sFn.Name)
85 }
86
87 return funcs
88 }
89
90 func (sFn *specFunc) instantiate(ctx context, b *specexpr.Bindings, argGet map[*types.Var]func(*specexpr.Bindings) specexpr.Type) *Func {
91 var f Func
92
93 f.specFunc = sFn
94 f.instance = b
95
96
97 var method bool
98 if len(sFn.Params) > 0 {
99 if t, ok := sFn.Params[0].Type().(*types.Named); ok {
100 if t.Origin() == sFn.Pkg.VecType {
101 method = true
102 }
103 }
104 }
105
106
107 name := sFn.NameTmpl.expand(func(s string) string {
108 val := b.Get(specexpr.Variable(s))
109 if val == nil {
110 ctx.errorf("unknown variable %q in function name", s)
111 return ""
112 }
113 str := fmt.Sprint(val)
114
115
116 str = strings.ToTitle(str[:1]) + str[1:]
117 return str
118 })
119 f.Name = name
120
121
122 doc := sFn.Doc.expand(func(s string) string {
123 val := b.Get(specexpr.Variable(s))
124 if val == nil {
125 ctx.errorf("unknown variable %q in doc", s)
126 return ""
127 }
128 return fmt.Sprint(val)
129 })
130
131 if f.Name == sFn.Name {
132 f.Doc = doc
133 } else {
134 f.Doc = regexp.MustCompile(`\b`+regexp.QuoteMeta(sFn.Name)+`\b`).ReplaceAllLiteralString(doc, f.Name)
135 }
136
137
138
139
140
141
142 for _, v := range sFn.Params {
143 t := argGet[v](b)
144 f.In = append(f.In, Arg{v.Name(), t})
145 }
146 if method && len(f.In) > 0 {
147 f.Recv = f.In[0]
148 f.In = f.In[1:]
149 }
150 for _, v := range sFn.Results {
151 t := argGet[v](b)
152 f.Out = append(f.Out, Arg{v.Name(), t})
153 }
154
155 return &f
156 }
157
View as plain text