1
2
3
4
5
6
7 package main
8
9 import (
10 "bytes"
11 "flag"
12 "fmt"
13 "go/format"
14 "log"
15 "math/bits"
16 "os"
17 "path"
18 "regexp"
19 "runtime"
20 "runtime/pprof"
21 "runtime/trace"
22 "sort"
23 "strings"
24 "sync"
25 )
26
27
28
29
30 type arch struct {
31 name string
32 pkg string
33 genfile string
34 ops []opData
35 blocks []blockData
36 regnames []string
37 ParamIntRegNames string
38 ParamFloatRegNames string
39 gpregmask regMask
40 fpregmask regMask
41 fp32regmask regMask
42 fp64regmask regMask
43 specialregmask regMask
44 framepointerreg int8
45 linkreg int8
46 generic bool
47 imports []string
48 }
49
50 type opData struct {
51 name string
52 reg regInfo
53 asm string
54 typ string
55 aux string
56 rematerializeable bool
57 argLength int32
58 commutative bool
59 resultInArg0 bool
60 resultNotInArgs bool
61 clobberFlags bool
62 needIntTemp bool
63 call bool
64 tailCall bool
65 nilCheck bool
66 faultOnNilArg0 bool
67 faultOnNilArg1 bool
68 hasSideEffects bool
69 zeroWidth bool
70 unsafePoint bool
71 symEffect string
72 scale uint8
73 }
74
75 type blockData struct {
76 name string
77 controls int
78 aux string
79 }
80
81 type regInfo struct {
82
83
84 inputs []regMask
85
86
87 clobbers regMask
88
89 outputs []regMask
90 }
91
92 type regMask uint64
93
94 func (a arch) regMaskComment(r regMask) string {
95 var buf strings.Builder
96 for i := uint64(0); r != 0; i++ {
97 if r&1 != 0 {
98 if buf.Len() == 0 {
99 buf.WriteString(" //")
100 }
101 buf.WriteString(" ")
102 buf.WriteString(a.regnames[i])
103 }
104 r >>= 1
105 }
106 return buf.String()
107 }
108
109 var archs []arch
110
111 var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
112 var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
113 var tracefile = flag.String("trace", "", "write trace to `file`")
114
115 func main() {
116 flag.Parse()
117 if *cpuprofile != "" {
118 f, err := os.Create(*cpuprofile)
119 if err != nil {
120 log.Fatal("could not create CPU profile: ", err)
121 }
122 defer f.Close()
123 if err := pprof.StartCPUProfile(f); err != nil {
124 log.Fatal("could not start CPU profile: ", err)
125 }
126 defer pprof.StopCPUProfile()
127 }
128 if *tracefile != "" {
129 f, err := os.Create(*tracefile)
130 if err != nil {
131 log.Fatalf("failed to create trace output file: %v", err)
132 }
133 defer func() {
134 if err := f.Close(); err != nil {
135 log.Fatalf("failed to close trace file: %v", err)
136 }
137 }()
138
139 if err := trace.Start(f); err != nil {
140 log.Fatalf("failed to start trace: %v", err)
141 }
142 defer trace.Stop()
143 }
144
145 sort.Sort(ArchsByName(archs))
146
147
148
149
150
151
152
153
154
155
156 tasks := []func(){
157 genOp,
158 genAllocators,
159 }
160 for _, a := range archs {
161 a := a
162 tasks = append(tasks, func() {
163 genRules(a)
164 genSplitLoadRules(a)
165 genLateLowerRules(a)
166 })
167 }
168 var wg sync.WaitGroup
169 for _, task := range tasks {
170 task := task
171 wg.Add(1)
172 go func() {
173 task()
174 wg.Done()
175 }()
176 }
177 wg.Wait()
178
179 if *memprofile != "" {
180 f, err := os.Create(*memprofile)
181 if err != nil {
182 log.Fatal("could not create memory profile: ", err)
183 }
184 defer f.Close()
185 runtime.GC()
186 if err := pprof.WriteHeapProfile(f); err != nil {
187 log.Fatal("could not write memory profile: ", err)
188 }
189 }
190 }
191
192 func genOp() {
193 w := new(bytes.Buffer)
194 fmt.Fprintf(w, "// Code generated from _gen/*Ops.go using 'go generate'; DO NOT EDIT.\n")
195 fmt.Fprintln(w)
196 fmt.Fprintln(w, "package ssa")
197
198 fmt.Fprintln(w, "import (")
199 fmt.Fprintln(w, "\"cmd/internal/obj\"")
200 for _, a := range archs {
201 if a.pkg != "" {
202 fmt.Fprintf(w, "%q\n", a.pkg)
203 }
204 }
205 fmt.Fprintln(w, ")")
206
207
208 fmt.Fprintln(w, "const (")
209 fmt.Fprintln(w, "BlockInvalid BlockKind = iota")
210 for _, a := range archs {
211 fmt.Fprintln(w)
212 for _, d := range a.blocks {
213 fmt.Fprintf(w, "Block%s%s\n", a.Name(), d.name)
214 }
215 }
216 fmt.Fprintln(w, ")")
217
218
219 fmt.Fprintln(w, "var blockString = [...]string{")
220 fmt.Fprintln(w, "BlockInvalid:\"BlockInvalid\",")
221 for _, a := range archs {
222 fmt.Fprintln(w)
223 for _, b := range a.blocks {
224 fmt.Fprintf(w, "Block%s%s:\"%s\",\n", a.Name(), b.name, b.name)
225 }
226 }
227 fmt.Fprintln(w, "}")
228 fmt.Fprintln(w, "func (k BlockKind) String() string {return blockString[k]}")
229
230
231 fmt.Fprintln(w, "func (k BlockKind) AuxIntType() string {")
232 fmt.Fprintln(w, "switch k {")
233 for _, a := range archs {
234 for _, b := range a.blocks {
235 if b.auxIntType() == "invalid" {
236 continue
237 }
238 fmt.Fprintf(w, "case Block%s%s: return \"%s\"\n", a.Name(), b.name, b.auxIntType())
239 }
240 }
241 fmt.Fprintln(w, "}")
242 fmt.Fprintln(w, "return \"\"")
243 fmt.Fprintln(w, "}")
244
245
246 fmt.Fprintln(w, "const (")
247 fmt.Fprintln(w, "OpInvalid Op = iota")
248 for _, a := range archs {
249 fmt.Fprintln(w)
250 for _, v := range a.ops {
251 if v.name == "Invalid" {
252 continue
253 }
254 fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name)
255 }
256 }
257 fmt.Fprintln(w, ")")
258
259
260 fmt.Fprintln(w, "var opcodeTable = [...]opInfo{")
261 fmt.Fprintln(w, " { name: \"OpInvalid\" },")
262 for _, a := range archs {
263 fmt.Fprintln(w)
264
265 pkg := path.Base(a.pkg)
266 for _, v := range a.ops {
267 if v.name == "Invalid" {
268 continue
269 }
270 fmt.Fprintln(w, "{")
271 fmt.Fprintf(w, "name:\"%s\",\n", v.name)
272
273
274 if v.aux != "" {
275 fmt.Fprintf(w, "auxType: aux%s,\n", v.aux)
276 }
277 fmt.Fprintf(w, "argLen: %d,\n", v.argLength)
278
279 if v.rematerializeable {
280 if v.reg.clobbers != 0 {
281 log.Fatalf("%s is rematerializeable and clobbers registers", v.name)
282 }
283 if v.clobberFlags {
284 log.Fatalf("%s is rematerializeable and clobbers flags", v.name)
285 }
286 fmt.Fprintln(w, "rematerializeable: true,")
287 }
288 if v.commutative {
289 fmt.Fprintln(w, "commutative: true,")
290 }
291 if v.resultInArg0 {
292 fmt.Fprintln(w, "resultInArg0: true,")
293
294
295 if v.name != "Convert" && v.reg.inputs[0] != v.reg.outputs[0] {
296 log.Fatalf("%s: input[0] and output[0] must use the same registers for %s", a.name, v.name)
297 }
298 if v.name != "Convert" && v.commutative && v.reg.inputs[1] != v.reg.outputs[0] {
299 log.Fatalf("%s: input[1] and output[0] must use the same registers for %s", a.name, v.name)
300 }
301 }
302 if v.resultNotInArgs {
303 fmt.Fprintln(w, "resultNotInArgs: true,")
304 }
305 if v.clobberFlags {
306 fmt.Fprintln(w, "clobberFlags: true,")
307 }
308 if v.needIntTemp {
309 fmt.Fprintln(w, "needIntTemp: true,")
310 }
311 if v.call {
312 fmt.Fprintln(w, "call: true,")
313 }
314 if v.tailCall {
315 fmt.Fprintln(w, "tailCall: true,")
316 }
317 if v.nilCheck {
318 fmt.Fprintln(w, "nilCheck: true,")
319 }
320 if v.faultOnNilArg0 {
321 fmt.Fprintln(w, "faultOnNilArg0: true,")
322 if v.aux != "Sym" && v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" {
323 log.Fatalf("faultOnNilArg0 with aux %s not allowed", v.aux)
324 }
325 }
326 if v.faultOnNilArg1 {
327 fmt.Fprintln(w, "faultOnNilArg1: true,")
328 if v.aux != "Sym" && v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" {
329 log.Fatalf("faultOnNilArg1 with aux %s not allowed", v.aux)
330 }
331 }
332 if v.hasSideEffects {
333 fmt.Fprintln(w, "hasSideEffects: true,")
334 }
335 if v.zeroWidth {
336 fmt.Fprintln(w, "zeroWidth: true,")
337 }
338 if v.unsafePoint {
339 fmt.Fprintln(w, "unsafePoint: true,")
340 }
341 needEffect := strings.HasPrefix(v.aux, "Sym")
342 if v.symEffect != "" {
343 if !needEffect {
344 log.Fatalf("symEffect with aux %s not allowed", v.aux)
345 }
346 fmt.Fprintf(w, "symEffect: Sym%s,\n", strings.Replace(v.symEffect, ",", "|Sym", -1))
347 } else if needEffect {
348 log.Fatalf("symEffect needed for aux %s", v.aux)
349 }
350 if a.name == "generic" {
351 fmt.Fprintln(w, "generic:true,")
352 fmt.Fprintln(w, "},")
353
354 continue
355 }
356 if v.asm != "" {
357 fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm)
358 }
359 if v.scale != 0 {
360 fmt.Fprintf(w, "scale: %d,\n", v.scale)
361 }
362 fmt.Fprintln(w, "reg:regInfo{")
363
364
365
366
367 var s []intPair
368 for i, r := range v.reg.inputs {
369 if r != 0 {
370 s = append(s, intPair{countRegs(r), i})
371 }
372 }
373 if len(s) > 0 {
374 sort.Sort(byKey(s))
375 fmt.Fprintln(w, "inputs: []inputInfo{")
376 for _, p := range s {
377 r := v.reg.inputs[p.val]
378 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
379 }
380 fmt.Fprintln(w, "},")
381 }
382
383 if v.reg.clobbers > 0 {
384 fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers))
385 }
386
387
388 s = s[:0]
389 for i, r := range v.reg.outputs {
390 s = append(s, intPair{countRegs(r), i})
391 }
392 if len(s) > 0 {
393 sort.Sort(byKey(s))
394 fmt.Fprintln(w, "outputs: []outputInfo{")
395 for _, p := range s {
396 r := v.reg.outputs[p.val]
397 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
398 }
399 fmt.Fprintln(w, "},")
400 }
401 fmt.Fprintln(w, "},")
402 fmt.Fprintln(w, "},")
403 }
404 }
405 fmt.Fprintln(w, "}")
406
407 fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}")
408 fmt.Fprintln(w, "func (o Op) Scale() int16 {return int16(opcodeTable[o].scale)}")
409
410
411 fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
412
413 fmt.Fprintln(w, "func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }")
414 fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }")
415 fmt.Fprintln(w, "func (o Op) IsTailCall() bool { return opcodeTable[o].tailCall }")
416 fmt.Fprintln(w, "func (o Op) HasSideEffects() bool { return opcodeTable[o].hasSideEffects }")
417 fmt.Fprintln(w, "func (o Op) UnsafePoint() bool { return opcodeTable[o].unsafePoint }")
418 fmt.Fprintln(w, "func (o Op) ResultInArg0() bool { return opcodeTable[o].resultInArg0 }")
419
420
421 for _, a := range archs {
422 if a.generic {
423 continue
424 }
425 fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name)
426 var gcRegN int
427 num := map[string]int8{}
428 for i, r := range a.regnames {
429 num[r] = int8(i)
430 pkg := a.pkg[len("cmd/internal/obj/"):]
431 var objname string
432 switch r {
433 case "SB":
434
435 objname = "0"
436 case "SP":
437 objname = pkg + ".REGSP"
438 case "g":
439 objname = pkg + ".REGG"
440 default:
441 objname = pkg + ".REG_" + r
442 }
443
444
445 gcRegIdx := -1
446 if a.gpregmask&(1<<uint(i)) != 0 {
447 gcRegIdx = gcRegN
448 gcRegN++
449 }
450 fmt.Fprintf(w, " {%d, %s, %d, \"%s\"},\n", i, objname, gcRegIdx, r)
451 }
452 parameterRegisterList := func(paramNamesString string) []int8 {
453 paramNamesString = strings.TrimSpace(paramNamesString)
454 if paramNamesString == "" {
455 return nil
456 }
457 paramNames := strings.Split(paramNamesString, " ")
458 var paramRegs []int8
459 for _, regName := range paramNames {
460 if regName == "" {
461
462 continue
463 }
464 if regNum, ok := num[regName]; ok {
465 paramRegs = append(paramRegs, regNum)
466 delete(num, regName)
467 } else {
468 log.Fatalf("parameter register %s for architecture %s not a register name (or repeated in parameter list)", regName, a.name)
469 }
470 }
471 return paramRegs
472 }
473
474 paramIntRegs := parameterRegisterList(a.ParamIntRegNames)
475 paramFloatRegs := parameterRegisterList(a.ParamFloatRegNames)
476
477 if gcRegN > 32 {
478
479 log.Fatalf("too many GC registers (%d > 32) on %s", gcRegN, a.name)
480 }
481 fmt.Fprintln(w, "}")
482 fmt.Fprintf(w, "var paramIntReg%s = %#v\n", a.name, paramIntRegs)
483 fmt.Fprintf(w, "var paramFloatReg%s = %#v\n", a.name, paramFloatRegs)
484 fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask)
485 fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask)
486 if a.fp32regmask != 0 {
487 fmt.Fprintf(w, "var fp32RegMask%s = regMask(%d)\n", a.name, a.fp32regmask)
488 }
489 if a.fp64regmask != 0 {
490 fmt.Fprintf(w, "var fp64RegMask%s = regMask(%d)\n", a.name, a.fp64regmask)
491 }
492 fmt.Fprintf(w, "var specialRegMask%s = regMask(%d)\n", a.name, a.specialregmask)
493 fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg)
494 fmt.Fprintf(w, "var linkReg%s = int8(%d)\n", a.name, a.linkreg)
495 }
496
497
498 b := w.Bytes()
499 var err error
500 b, err = format.Source(b)
501 if err != nil {
502 fmt.Printf("%s\n", w.Bytes())
503 panic(err)
504 }
505
506 if err := os.WriteFile("../opGen.go", b, 0666); err != nil {
507 log.Fatalf("can't write output: %v\n", err)
508 }
509
510
511
512
513
514
515
516 for _, a := range archs {
517 if a.genfile == "" {
518 continue
519 }
520
521 pattern := fmt.Sprintf(`\Wssa\.Op%s([a-zA-Z0-9_]+)\W`, a.name)
522 rxOp, err := regexp.Compile(pattern)
523 if err != nil {
524 log.Fatalf("bad opcode regexp %s: %v", pattern, err)
525 }
526
527 src, err := os.ReadFile(a.genfile)
528 if err != nil {
529 log.Fatalf("can't read %s: %v", a.genfile, err)
530 }
531 seen := make(map[string]bool, len(a.ops))
532 for _, m := range rxOp.FindAllSubmatch(src, -1) {
533 seen[string(m[1])] = true
534 }
535 for _, op := range a.ops {
536 if !seen[op.name] {
537 log.Fatalf("Op%s%s has no code generation in %s", a.name, op.name, a.genfile)
538 }
539 }
540 }
541 }
542
543
544 func (a arch) Name() string {
545 s := a.name
546 if s == "generic" {
547 s = ""
548 }
549 return s
550 }
551
552
553 func countRegs(r regMask) int {
554 return bits.OnesCount64(uint64(r))
555 }
556
557
558 type intPair struct {
559 key, val int
560 }
561 type byKey []intPair
562
563 func (a byKey) Len() int { return len(a) }
564 func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
565 func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }
566
567 type ArchsByName []arch
568
569 func (x ArchsByName) Len() int { return len(x) }
570 func (x ArchsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
571 func (x ArchsByName) Less(i, j int) bool { return x[i].name < x[j].name }
572
View as plain text