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/_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 return nil
139 }
140
141 func (o *Operation) VectorWidth() int {
142 out := o.Out[0]
143 if out.Class == "vreg" {
144 return *out.Bits
145 } else if out.Class == "greg" || out.Class == "mask" {
146 for i := range o.In {
147 if o.In[i].Class == "vreg" {
148 return *o.In[i].Bits
149 }
150 }
151 }
152 panic(fmt.Errorf("Figure out what the vector width is for %v and implement it", *o))
153 }
154
155
156
157
158
159
160
161
162
163 var demotingConvertOps = map[string]bool{
164 "VPMOVQD128": true, "VPMOVSQD128": true, "VPMOVUSQD128": true, "VPMOVQW128": true, "VPMOVSQW128": true,
165 "VPMOVUSQW128": true, "VPMOVDW128": true, "VPMOVSDW128": true, "VPMOVUSDW128": true, "VPMOVQB128": true,
166 "VPMOVSQB128": true, "VPMOVUSQB128": true, "VPMOVDB128": true, "VPMOVSDB128": true, "VPMOVUSDB128": true,
167 "VPMOVWB128": true, "VPMOVSWB128": true, "VPMOVUSWB128": true,
168 "VPMOVQDMasked128": true, "VPMOVSQDMasked128": true, "VPMOVUSQDMasked128": true, "VPMOVQWMasked128": true, "VPMOVSQWMasked128": true,
169 "VPMOVUSQWMasked128": true, "VPMOVDWMasked128": true, "VPMOVSDWMasked128": true, "VPMOVUSDWMasked128": true, "VPMOVQBMasked128": true,
170 "VPMOVSQBMasked128": true, "VPMOVUSQBMasked128": true, "VPMOVDBMasked128": true, "VPMOVSDBMasked128": true, "VPMOVUSDBMasked128": true,
171 "VPMOVWBMasked128": true, "VPMOVSWBMasked128": true, "VPMOVUSWBMasked128": true,
172 }
173
174 func machineOpName(maskType maskShape, gOp Operation) string {
175 asm := gOp.Asm
176 if maskType == OneMask {
177 asm += "Masked"
178 }
179 asm = fmt.Sprintf("%s%d", asm, gOp.VectorWidth())
180 if gOp.SSAVariant != nil {
181 asm += *gOp.SSAVariant
182 }
183 if demotingConvertOps[asm] {
184
185
186 asm = fmt.Sprintf("%s_%d", asm, *gOp.In[0].Bits)
187 }
188 return asm
189 }
190
191 func compareStringPointers(x, y *string) int {
192 if x != nil && y != nil {
193 return compareNatural(*x, *y)
194 }
195 if x == nil && y == nil {
196 return 0
197 }
198 if x == nil {
199 return -1
200 }
201 return 1
202 }
203
204 func compareIntPointers(x, y *int) int {
205 if x != nil && y != nil {
206 return *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 compareOperations(x, y Operation) int {
218 if c := compareNatural(x.Go, y.Go); c != 0 {
219 return c
220 }
221 xIn, yIn := x.In, y.In
222
223 if len(xIn) > len(yIn) && xIn[len(xIn)-1].Class == "mask" {
224 xIn = xIn[:len(xIn)-1]
225 } else if len(xIn) < len(yIn) && yIn[len(yIn)-1].Class == "mask" {
226 yIn = yIn[:len(yIn)-1]
227 }
228
229 if len(xIn) < len(yIn) {
230 return -1
231 }
232 if len(xIn) > len(yIn) {
233 return 1
234 }
235 if len(x.Out) < len(y.Out) {
236 return -1
237 }
238 if len(x.Out) > len(y.Out) {
239 return 1
240 }
241 for i := range xIn {
242 ox, oy := &xIn[i], &yIn[i]
243 if c := compareOperands(ox, oy); c != 0 {
244 return c
245 }
246 }
247 return 0
248 }
249
250 func compareOperands(x, y *Operand) int {
251 if c := compareNatural(x.Class, y.Class); c != 0 {
252 return c
253 }
254 if x.Class == "immediate" {
255 return compareStringPointers(x.ImmOffset, y.ImmOffset)
256 } else {
257 if c := compareStringPointers(x.Base, y.Base); c != 0 {
258 return c
259 }
260 if c := compareIntPointers(x.ElemBits, y.ElemBits); c != 0 {
261 return c
262 }
263 if c := compareIntPointers(x.Bits, y.Bits); c != 0 {
264 return c
265 }
266 return 0
267 }
268 }
269
270 type Operand struct {
271 Class string
272
273 Go *string
274 AsmPos int
275
276 Base *string
277 ElemBits *int
278 Bits *int
279
280 Const *string
281
282
283
284
285 ImmOffset *string
286 Name *string
287 Lanes *int
288
289
290
291 TreatLikeAScalarOfSize *int
292
293
294 OverwriteClass *string
295
296
297 OverwriteBase *string
298
299
300
301 OverwriteElementBits *int
302
303 FixedReg *string
304 }
305
306
307 func isDigit(b byte) bool {
308 return b >= '0' && b <= '9'
309 }
310
311
312
313
314
315
316
317
318
319
320
321 func compareNatural(s1, s2 string) int {
322 i, j := 0, 0
323 len1, len2 := len(s1), len(s2)
324
325 for i < len1 && j < len2 {
326
327 if isDigit(s1[i]) && isDigit(s2[j]) {
328
329 numStart1 := i
330 for i < len1 && isDigit(s1[i]) {
331 i++
332 }
333 num1, _ := strconv.Atoi(s1[numStart1:i])
334
335 numStart2 := j
336 for j < len2 && isDigit(s2[j]) {
337 j++
338 }
339 num2, _ := strconv.Atoi(s2[numStart2:j])
340
341 if num1 < num2 {
342 return -1
343 }
344 if num1 > num2 {
345 return 1
346 }
347
348 } else {
349
350 if s1[i] < s2[j] {
351 return -1
352 }
353 if s1[i] > s2[j] {
354 return 1
355 }
356 i++
357 j++
358 }
359 }
360
361
362 return strings.Compare(s1, s2)
363 }
364
365 const generatedHeader = `// Code generated by x/arch/internal/simdgen using 'go run . -xedPath $XED_PATH -o godefs -goroot $GOROOT go.yaml types.yaml categories.yaml'; DO NOT EDIT.
366 `
367
368 func writeGoDefs(path string, cl unify.Closure) error {
369
370
371 var ops []Operation
372 for def := range cl.All() {
373 var op Operation
374 if !def.Exact() {
375 continue
376 }
377 if err := def.Decode(&op); err != nil {
378 log.Println(err.Error())
379 log.Println(def)
380 continue
381 }
382
383 op.sortOperand()
384 ops = append(ops, op)
385 }
386 slices.SortFunc(ops, compareOperations)
387
388
389 deduped := dedup(ops)
390 slices.SortFunc(deduped, compareOperations)
391
392 if *Verbose {
393 log.Printf("dedup len: %d\n", len(ops))
394 }
395 var err error
396 if err = overwrite(deduped); err != nil {
397 return err
398 }
399 if *Verbose {
400 log.Printf("dedup len: %d\n", len(deduped))
401 }
402 if *Verbose {
403 log.Printf("dedup len: %d\n", len(deduped))
404 }
405 if !*FlagNoDedup {
406
407
408 if deduped, err = dedupGodef(deduped); err != nil {
409 return err
410 }
411 }
412 if *Verbose {
413 log.Printf("dedup len: %d\n", len(deduped))
414 }
415 if !*FlagNoConstImmPorting {
416 if err = copyConstImm(deduped); err != nil {
417 return err
418 }
419 }
420 if *Verbose {
421 log.Printf("dedup len: %d\n", len(deduped))
422 }
423 reportXEDInconsistency(deduped)
424 typeMap := parseSIMDTypes(deduped)
425
426 formatWriteAndClose(writeSIMDTypes(typeMap), path, "src/"+simdPackage+"/types_amd64.go")
427 formatWriteAndClose(writeSIMDFeatures(deduped), path, "src/"+simdPackage+"/cpu.go")
428 f, fI := writeSIMDStubs(deduped, typeMap)
429 formatWriteAndClose(f, path, "src/"+simdPackage+"/ops_amd64.go")
430 formatWriteAndClose(fI, path, "src/"+simdPackage+"/ops_internal_amd64.go")
431 formatWriteAndClose(writeSIMDIntrinsics(deduped, typeMap), path, "src/cmd/compile/internal/ssagen/simdintrinsics.go")
432 formatWriteAndClose(writeSIMDGenericOps(deduped), path, "src/cmd/compile/internal/ssa/_gen/simdgenericOps.go")
433 formatWriteAndClose(writeSIMDMachineOps(deduped), path, "src/cmd/compile/internal/ssa/_gen/simdAMD64ops.go")
434 formatWriteAndClose(writeSIMDSSA(deduped), path, "src/cmd/compile/internal/amd64/simdssa.go")
435 writeAndClose(writeSIMDRules(deduped).Bytes(), path, "src/cmd/compile/internal/ssa/_gen/simdAMD64.rules")
436
437 return nil
438 }
439
View as plain text