1
2
3
4
5
6
7
8
9
10 package main
11
12 import (
13 "bytes"
14 "flag"
15 "fmt"
16 "go/format"
17 "io/ioutil"
18 "log"
19 "os"
20 "path"
21 "regexp"
22 "runtime"
23 "runtime/pprof"
24 "runtime/trace"
25 "sort"
26 "strings"
27 "sync"
28 )
29
30
31
32
33 type arch struct {
34 name string
35 pkg string
36 genfile string
37 ops []opData
38 blocks []blockData
39 regnames []string
40 ParamIntRegNames string
41 ParamFloatRegNames string
42 gpregmask regMask
43 fpregmask regMask
44 fp32regmask regMask
45 fp64regmask regMask
46 specialregmask regMask
47 framepointerreg int8
48 linkreg int8
49 generic bool
50 imports []string
51 }
52
53 type opData struct {
54 name string
55 reg regInfo
56 asm string
57 typ string
58 aux string
59 rematerializeable bool
60 argLength int32
61 commutative bool
62 resultInArg0 bool
63 resultNotInArgs bool
64 clobberFlags bool
65 call bool
66 tailCall bool
67 nilCheck bool
68 faultOnNilArg0 bool
69 faultOnNilArg1 bool
70 hasSideEffects bool
71 zeroWidth bool
72 unsafePoint bool
73 symEffect string
74 scale uint8
75 }
76
77 type blockData struct {
78 name string
79 controls int
80 aux string
81 }
82
83 type regInfo struct {
84
85
86 inputs []regMask
87
88
89 clobbers regMask
90
91 outputs []regMask
92 }
93
94 type regMask uint64
95
96 func (a arch) regMaskComment(r regMask) string {
97 var buf bytes.Buffer
98 for i := uint64(0); r != 0; i++ {
99 if r&1 != 0 {
100 if buf.Len() == 0 {
101 buf.WriteString(" //")
102 }
103 buf.WriteString(" ")
104 buf.WriteString(a.regnames[i])
105 }
106 r >>= 1
107 }
108 return buf.String()
109 }
110
111 var archs []arch
112
113 var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
114 var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
115 var tracefile = flag.String("trace", "", "write trace to `file`")
116
117 func main() {
118 flag.Parse()
119 if *cpuprofile != "" {
120 f, err := os.Create(*cpuprofile)
121 if err != nil {
122 log.Fatal("could not create CPU profile: ", err)
123 }
124 defer f.Close()
125 if err := pprof.StartCPUProfile(f); err != nil {
126 log.Fatal("could not start CPU profile: ", err)
127 }
128 defer pprof.StopCPUProfile()
129 }
130 if *tracefile != "" {
131 f, err := os.Create(*tracefile)
132 if err != nil {
133 log.Fatalf("failed to create trace output file: %v", err)
134 }
135 defer func() {
136 if err := f.Close(); err != nil {
137 log.Fatalf("failed to close trace file: %v", err)
138 }
139 }()
140
141 if err := trace.Start(f); err != nil {
142 log.Fatalf("failed to start trace: %v", err)
143 }
144 defer trace.Stop()
145 }
146
147 sort.Sort(ArchsByName(archs))
148
149
150
151
152
153
154
155
156
157
158 tasks := []func(){
159 genOp,
160 }
161 for _, a := range archs {
162 a := a
163 tasks = append(tasks, func() {
164 genRules(a)
165 genSplitLoadRules(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; 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.call {
309 fmt.Fprintln(w, "call: true,")
310 }
311 if v.tailCall {
312 fmt.Fprintln(w, "tailCall: true,")
313 }
314 if v.nilCheck {
315 fmt.Fprintln(w, "nilCheck: true,")
316 }
317 if v.faultOnNilArg0 {
318 fmt.Fprintln(w, "faultOnNilArg0: true,")
319 if v.aux != "Sym" && v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" {
320 log.Fatalf("faultOnNilArg0 with aux %s not allowed", v.aux)
321 }
322 }
323 if v.faultOnNilArg1 {
324 fmt.Fprintln(w, "faultOnNilArg1: true,")
325 if v.aux != "Sym" && v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" {
326 log.Fatalf("faultOnNilArg1 with aux %s not allowed", v.aux)
327 }
328 }
329 if v.hasSideEffects {
330 fmt.Fprintln(w, "hasSideEffects: true,")
331 }
332 if v.zeroWidth {
333 fmt.Fprintln(w, "zeroWidth: true,")
334 }
335 if v.unsafePoint {
336 fmt.Fprintln(w, "unsafePoint: true,")
337 }
338 needEffect := strings.HasPrefix(v.aux, "Sym")
339 if v.symEffect != "" {
340 if !needEffect {
341 log.Fatalf("symEffect with aux %s not allowed", v.aux)
342 }
343 fmt.Fprintf(w, "symEffect: Sym%s,\n", strings.Replace(v.symEffect, ",", "|Sym", -1))
344 } else if needEffect {
345 log.Fatalf("symEffect needed for aux %s", v.aux)
346 }
347 if a.name == "generic" {
348 fmt.Fprintln(w, "generic:true,")
349 fmt.Fprintln(w, "},")
350
351 continue
352 }
353 if v.asm != "" {
354 fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm)
355 }
356 if v.scale != 0 {
357 fmt.Fprintf(w, "scale: %d,\n", v.scale)
358 }
359 fmt.Fprintln(w, "reg:regInfo{")
360
361
362
363
364 var s []intPair
365 for i, r := range v.reg.inputs {
366 if r != 0 {
367 s = append(s, intPair{countRegs(r), i})
368 }
369 }
370 if len(s) > 0 {
371 sort.Sort(byKey(s))
372 fmt.Fprintln(w, "inputs: []inputInfo{")
373 for _, p := range s {
374 r := v.reg.inputs[p.val]
375 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
376 }
377 fmt.Fprintln(w, "},")
378 }
379
380 if v.reg.clobbers > 0 {
381 fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers))
382 }
383
384
385 s = s[:0]
386 for i, r := range v.reg.outputs {
387 s = append(s, intPair{countRegs(r), i})
388 }
389 if len(s) > 0 {
390 sort.Sort(byKey(s))
391 fmt.Fprintln(w, "outputs: []outputInfo{")
392 for _, p := range s {
393 r := v.reg.outputs[p.val]
394 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
395 }
396 fmt.Fprintln(w, "},")
397 }
398 fmt.Fprintln(w, "},")
399 fmt.Fprintln(w, "},")
400 }
401 }
402 fmt.Fprintln(w, "}")
403
404 fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}")
405 fmt.Fprintln(w, "func (o Op) Scale() int16 {return int16(opcodeTable[o].scale)}")
406
407
408 fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
409
410 fmt.Fprintln(w, "func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }")
411 fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }")
412 fmt.Fprintln(w, "func (o Op) IsTailCall() bool { return opcodeTable[o].tailCall }")
413 fmt.Fprintln(w, "func (o Op) HasSideEffects() bool { return opcodeTable[o].hasSideEffects }")
414 fmt.Fprintln(w, "func (o Op) UnsafePoint() bool { return opcodeTable[o].unsafePoint }")
415 fmt.Fprintln(w, "func (o Op) ResultInArg0() bool { return opcodeTable[o].resultInArg0 }")
416
417
418 for _, a := range archs {
419 if a.generic {
420 continue
421 }
422 fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name)
423 var gcRegN int
424 num := map[string]int8{}
425 for i, r := range a.regnames {
426 num[r] = int8(i)
427 pkg := a.pkg[len("cmd/internal/obj/"):]
428 var objname string
429 switch r {
430 case "SB":
431
432 objname = "0"
433 case "SP":
434 objname = pkg + ".REGSP"
435 case "g":
436 objname = pkg + ".REGG"
437 default:
438 objname = pkg + ".REG_" + r
439 }
440
441
442 gcRegIdx := -1
443 if a.gpregmask&(1<<uint(i)) != 0 {
444 gcRegIdx = gcRegN
445 gcRegN++
446 }
447 fmt.Fprintf(w, " {%d, %s, %d, \"%s\"},\n", i, objname, gcRegIdx, r)
448 }
449 parameterRegisterList := func(paramNamesString string) []int8 {
450 paramNamesString = strings.TrimSpace(paramNamesString)
451 if paramNamesString == "" {
452 return nil
453 }
454 paramNames := strings.Split(paramNamesString, " ")
455 var paramRegs []int8
456 for _, regName := range paramNames {
457 if regName == "" {
458
459 continue
460 }
461 if regNum, ok := num[regName]; ok {
462 paramRegs = append(paramRegs, regNum)
463 delete(num, regName)
464 } else {
465 log.Fatalf("parameter register %s for architecture %s not a register name (or repeated in parameter list)", regName, a.name)
466 }
467 }
468 return paramRegs
469 }
470
471 paramIntRegs := parameterRegisterList(a.ParamIntRegNames)
472 paramFloatRegs := parameterRegisterList(a.ParamFloatRegNames)
473
474 if gcRegN > 32 {
475
476 log.Fatalf("too many GC registers (%d > 32) on %s", gcRegN, a.name)
477 }
478 fmt.Fprintln(w, "}")
479 fmt.Fprintf(w, "var paramIntReg%s = %#v\n", a.name, paramIntRegs)
480 fmt.Fprintf(w, "var paramFloatReg%s = %#v\n", a.name, paramFloatRegs)
481 fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask)
482 fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask)
483 if a.fp32regmask != 0 {
484 fmt.Fprintf(w, "var fp32RegMask%s = regMask(%d)\n", a.name, a.fp32regmask)
485 }
486 if a.fp64regmask != 0 {
487 fmt.Fprintf(w, "var fp64RegMask%s = regMask(%d)\n", a.name, a.fp64regmask)
488 }
489 fmt.Fprintf(w, "var specialRegMask%s = regMask(%d)\n", a.name, a.specialregmask)
490 fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg)
491 fmt.Fprintf(w, "var linkReg%s = int8(%d)\n", a.name, a.linkreg)
492 }
493
494
495 b := w.Bytes()
496 var err error
497 b, err = format.Source(b)
498 if err != nil {
499 fmt.Printf("%s\n", w.Bytes())
500 panic(err)
501 }
502
503 if err := ioutil.WriteFile("../opGen.go", b, 0666); err != nil {
504 log.Fatalf("can't write output: %v\n", err)
505 }
506
507
508
509
510
511
512
513 for _, a := range archs {
514 if a.genfile == "" {
515 continue
516 }
517
518 pattern := fmt.Sprintf(`\Wssa\.Op%s([a-zA-Z0-9_]+)\W`, a.name)
519 rxOp, err := regexp.Compile(pattern)
520 if err != nil {
521 log.Fatalf("bad opcode regexp %s: %v", pattern, err)
522 }
523
524 src, err := ioutil.ReadFile(a.genfile)
525 if err != nil {
526 log.Fatalf("can't read %s: %v", a.genfile, err)
527 }
528 seen := make(map[string]bool, len(a.ops))
529 for _, m := range rxOp.FindAllSubmatch(src, -1) {
530 seen[string(m[1])] = true
531 }
532 for _, op := range a.ops {
533 if !seen[op.name] {
534 log.Fatalf("Op%s%s has no code generation in %s", a.name, op.name, a.genfile)
535 }
536 }
537 }
538 }
539
540
541 func (a arch) Name() string {
542 s := a.name
543 if s == "generic" {
544 s = ""
545 }
546 return s
547 }
548
549
550 func countRegs(r regMask) int {
551 n := 0
552 for r != 0 {
553 n += int(r & 1)
554 r >>= 1
555 }
556 return n
557 }
558
559
560 type intPair struct {
561 key, val int
562 }
563 type byKey []intPair
564
565 func (a byKey) Len() int { return len(a) }
566 func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
567 func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }
568
569 type ArchsByName []arch
570
571 func (x ArchsByName) Len() int { return len(x) }
572 func (x ArchsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
573 func (x ArchsByName) Less(i, j int) bool { return x[i].name < x[j].name }
574
View as plain text