1
2
3
4
5 package main
6
7 import (
8 "fmt"
9 "log"
10 "regexp"
11 "slices"
12 "strconv"
13 "strings"
14 "unicode"
15
16 "simd/archsimd/_gen/unify"
17 )
18
19 type Operation struct {
20 rawOperation
21
22
23
24
25
26 Go string
27
28
29
30
31
32
33
34
35 Documentation string
36
37
38
39
40 In []Operand
41 }
42
43
44
45 type rawOperation struct {
46 Go string
47
48 GoArch string
49 Asm string
50 OperandOrder *string
51
52
53 SpecialLower *string
54
55 In []Operand
56 InVariant []Operand
57 Out []Operand
58 MemFeatures *string
59 MemFeaturesData *string
60 Commutative bool
61 CPUFeature string
62 Zeroing *bool
63 Documentation *string
64 AddDoc *string
65
66
67 ConstImm *string
68
69 NameAndSizeCheck *bool
70
71 NoTypes *string
72
73 NoGenericOps *string
74
75 SSAVariant *string
76
77
78 HideMaskMethods *bool
79 }
80
81 func (o *Operation) IsMasked() bool {
82 if len(o.InVariant) == 0 {
83 return false
84 }
85 if len(o.InVariant) == 1 && o.InVariant[0].Class == "mask" {
86 return true
87 }
88 panic(fmt.Errorf("unknown inVariant"))
89 }
90
91 func (o *Operation) SkipMaskedMethod() bool {
92 if o.HideMaskMethods == nil {
93 return false
94 }
95 if *o.HideMaskMethods && o.IsMasked() {
96 return true
97 }
98 return false
99 }
100
101 var reForName = regexp.MustCompile(`\bNAME\b`)
102
103 func (o *Operation) DecodeUnified(v *unify.Value) error {
104 if err := v.Decode(&o.rawOperation); err != nil {
105 return err
106 }
107
108 isMasked := o.IsMasked()
109
110
111 o.Go = o.rawOperation.Go
112 if isMasked {
113 o.Go += "Masked"
114 }
115
116
117 if o.rawOperation.Documentation != nil {
118 o.Documentation = *o.rawOperation.Documentation
119 } else {
120 o.Documentation = "// UNDOCUMENTED"
121 }
122 o.Documentation = reForName.ReplaceAllString(o.Documentation, o.Go)
123 if isMasked {
124 o.Documentation += "\n//\n// This operation is applied selectively under a write mask."
125
126 if unicode.IsUpper([]rune(o.Go)[0]) {
127 trueVal := "true"
128 o.NoGenericOps = &trueVal
129 o.NoTypes = &trueVal
130 }
131 }
132 if o.rawOperation.AddDoc != nil {
133 o.Documentation += "\n" + reForName.ReplaceAllString(*o.rawOperation.AddDoc, o.Go)
134 }
135
136 o.In = append(o.rawOperation.In, o.rawOperation.InVariant...)
137
138
139
140 if len(o.In) > 0 && len(o.Out) > 0 {
141 inLanes := o.In[0].Lanes
142 outLanes := o.Out[0].Lanes
143 if inLanes != nil && outLanes != nil && *inLanes < *outLanes {
144 if (strings.Contains(o.Go, "Saturate") || strings.Contains(o.Go, "Truncate")) &&
145 !strings.Contains(o.Go, "Concat") {
146 o.Documentation += "\n// Results are packed to low elements in the returned vector, its upper elements are zeroed."
147 }
148 }
149 }
150
151 return nil
152 }
153
154 func (o *Operation) VectorWidth() int {
155 out := o.Out[0]
156 if out.Class == "vreg" {
157 return *out.Bits
158 } else if out.Class == "greg" || out.Class == "mask" {
159 for i := range o.In {
160 if o.In[i].Class == "vreg" {
161 return *o.In[i].Bits
162 }
163 }
164 }
165 panic(fmt.Errorf("Figure out what the vector width is for %v and implement it", *o))
166 }
167
168
169
170
171
172
173
174
175
176 var demotingConvertOps = map[string]bool{
177 "VPMOVQD128": true, "VPMOVSQD128": true, "VPMOVUSQD128": true, "VPMOVQW128": true, "VPMOVSQW128": true,
178 "VPMOVUSQW128": true, "VPMOVDW128": true, "VPMOVSDW128": true, "VPMOVUSDW128": true, "VPMOVQB128": true,
179 "VPMOVSQB128": true, "VPMOVUSQB128": true, "VPMOVDB128": true, "VPMOVSDB128": true, "VPMOVUSDB128": true,
180 "VPMOVWB128": true, "VPMOVSWB128": true, "VPMOVUSWB128": true,
181 "VPMOVQDMasked128": true, "VPMOVSQDMasked128": true, "VPMOVUSQDMasked128": true, "VPMOVQWMasked128": true, "VPMOVSQWMasked128": true,
182 "VPMOVUSQWMasked128": true, "VPMOVDWMasked128": true, "VPMOVSDWMasked128": true, "VPMOVUSDWMasked128": true, "VPMOVQBMasked128": true,
183 "VPMOVSQBMasked128": true, "VPMOVUSQBMasked128": true, "VPMOVDBMasked128": true, "VPMOVSDBMasked128": true, "VPMOVUSDBMasked128": true,
184 "VPMOVWBMasked128": true, "VPMOVSWBMasked128": true, "VPMOVUSWBMasked128": true,
185 }
186
187 func machineOpName(maskType maskShape, gOp Operation) string {
188 asm := gOp.Asm
189 if maskType == OneMask {
190 asm += "Masked"
191 }
192 asm = fmt.Sprintf("%s%d", asm, gOp.VectorWidth())
193 if gOp.SSAVariant != nil {
194 asm += *gOp.SSAVariant
195 }
196 if demotingConvertOps[asm] {
197
198
199 asm = fmt.Sprintf("%s_%d", asm, *gOp.In[0].Bits)
200 }
201 return asm
202 }
203
204 func compareStringPointers(x, y *string) int {
205 if x != nil && y != nil {
206 return compareNatural(*x, *y)
207 }
208 if x == nil && y == nil {
209 return 0
210 }
211 if x == nil {
212 return -1
213 }
214 return 1
215 }
216
217 func compareIntPointers(x, y *int) int {
218 if x != nil && y != nil {
219 return *x - *y
220 }
221 if x == nil && y == nil {
222 return 0
223 }
224 if x == nil {
225 return -1
226 }
227 return 1
228 }
229
230 func compareOperations(x, y Operation) int {
231 if c := compareNatural(x.Go, y.Go); c != 0 {
232 return c
233 }
234 xIn, yIn := x.In, y.In
235
236 if len(xIn) > len(yIn) && xIn[len(xIn)-1].Class == "mask" {
237 xIn = xIn[:len(xIn)-1]
238 } else if len(xIn) < len(yIn) && yIn[len(yIn)-1].Class == "mask" {
239 yIn = yIn[:len(yIn)-1]
240 }
241
242 if len(xIn) < len(yIn) {
243 return -1
244 }
245 if len(xIn) > len(yIn) {
246 return 1
247 }
248 if len(x.Out) < len(y.Out) {
249 return -1
250 }
251 if len(x.Out) > len(y.Out) {
252 return 1
253 }
254 for i := range xIn {
255 ox, oy := &xIn[i], &yIn[i]
256 if c := compareOperands(ox, oy); c != 0 {
257 return c
258 }
259 }
260 return 0
261 }
262
263 func compareOperands(x, y *Operand) int {
264 if c := compareNatural(x.Class, y.Class); c != 0 {
265 return c
266 }
267 if x.Class == "immediate" {
268 return compareStringPointers(x.ImmOffset, y.ImmOffset)
269 } else {
270 if c := compareStringPointers(x.Base, y.Base); c != 0 {
271 return c
272 }
273 if c := compareIntPointers(x.ElemBits, y.ElemBits); c != 0 {
274 return c
275 }
276 if c := compareIntPointers(x.Bits, y.Bits); c != 0 {
277 return c
278 }
279 return 0
280 }
281 }
282
283 type Operand struct {
284 Class string
285
286 Go *string
287 AsmPos int
288
289 Base *string
290 ElemBits *int
291 Bits *int
292
293 Const *string
294
295
296
297
298 ImmOffset *string
299 Name *string
300 Lanes *int
301
302
303
304 TreatLikeAScalarOfSize *int
305
306
307 OverwriteClass *string
308
309
310 OverwriteBase *string
311
312
313
314 OverwriteElementBits *int
315
316 FixedReg *string
317 }
318
319
320 func isDigit(b byte) bool {
321 return b >= '0' && b <= '9'
322 }
323
324
325
326
327
328
329
330
331
332
333
334 func compareNatural(s1, s2 string) int {
335 i, j := 0, 0
336 len1, len2 := len(s1), len(s2)
337
338 for i < len1 && j < len2 {
339
340 if isDigit(s1[i]) && isDigit(s2[j]) {
341
342 numStart1 := i
343 for i < len1 && isDigit(s1[i]) {
344 i++
345 }
346 num1, _ := strconv.Atoi(s1[numStart1:i])
347
348 numStart2 := j
349 for j < len2 && isDigit(s2[j]) {
350 j++
351 }
352 num2, _ := strconv.Atoi(s2[numStart2:j])
353
354 if num1 < num2 {
355 return -1
356 }
357 if num1 > num2 {
358 return 1
359 }
360
361 } else {
362
363 if s1[i] < s2[j] {
364 return -1
365 }
366 if s1[i] > s2[j] {
367 return 1
368 }
369 i++
370 j++
371 }
372 }
373
374
375 return strings.Compare(s1, s2)
376 }
377
378 const generatedHeader = `// Code generated by 'simdgen -o godefs -goroot $GOROOT -xedPath $XED_PATH go.yaml types.yaml categories.yaml'; DO NOT EDIT.
379 `
380
381 func writeGoDefs(path string, cl unify.Closure) error {
382
383
384 var ops []Operation
385 for def := range cl.All() {
386 var op Operation
387 if !def.Exact() {
388 continue
389 }
390 if err := def.Decode(&op); err != nil {
391 log.Println(err.Error())
392 log.Println(def)
393 continue
394 }
395
396 op.sortOperand()
397 op.adjustAsm()
398 ops = append(ops, op)
399 }
400 slices.SortFunc(ops, compareOperations)
401
402
403 deduped := dedup(ops)
404 slices.SortFunc(deduped, compareOperations)
405
406 if *Verbose {
407 log.Printf("dedup len: %d\n", len(ops))
408 }
409 var err error
410 if err = overwrite(deduped); err != nil {
411 return err
412 }
413 if *Verbose {
414 log.Printf("dedup len: %d\n", len(deduped))
415 }
416 if !*FlagNoDedup {
417
418
419 if deduped, err = dedupGodef(deduped); err != nil {
420 return err
421 }
422 }
423 if *Verbose {
424 log.Printf("dedup len: %d\n", len(deduped))
425 }
426 if !*FlagNoConstImmPorting {
427 if err = copyConstImm(deduped); err != nil {
428 return err
429 }
430 }
431 if *Verbose {
432 log.Printf("dedup len: %d\n", len(deduped))
433 }
434 reportXEDInconsistency(deduped)
435 typeMap := parseSIMDTypes(deduped)
436
437 formatWriteAndClose(writeSIMDTypes(typeMap), path, "src/"+simdPackage+"/types_amd64.go")
438 formatWriteAndClose(writeSIMDFeatures(deduped), path, "src/"+simdPackage+"/cpu.go")
439 f, fI := writeSIMDStubs(deduped, typeMap)
440 formatWriteAndClose(f, path, "src/"+simdPackage+"/ops_amd64.go")
441 formatWriteAndClose(fI, path, "src/"+simdPackage+"/ops_internal_amd64.go")
442 formatWriteAndClose(writeSIMDIntrinsics(deduped, typeMap), path, "src/cmd/compile/internal/ssagen/simdintrinsics.go")
443 formatWriteAndClose(writeSIMDGenericOps(deduped), path, "src/cmd/compile/internal/ssa/_gen/simdgenericOps.go")
444 formatWriteAndClose(writeSIMDMachineOps(deduped), path, "src/cmd/compile/internal/ssa/_gen/simdAMD64ops.go")
445 formatWriteAndClose(writeSIMDSSA(deduped), path, "src/cmd/compile/internal/amd64/simdssa.go")
446 writeAndClose(writeSIMDRules(deduped).Bytes(), path, "src/cmd/compile/internal/ssa/_gen/simdAMD64.rules")
447
448 return nil
449 }
450
View as plain text