1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build ignore
6// +build ignore
7
8// The gen command generates Go code (in the parent directory) for all
9// the architecture-specific opcodes, blocks, and rewrites.
10package main
11
12import (
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// TODO: capitalize these types, so that we can more easily tell variable names
31// apart from type names, and avoid awkward func parameters like "arch arch".
32
33type arch struct {
34	name               string
35	pkg                string // obj package to import for this arch.
36	genfile            string // source file containing opcode code generation.
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
53type opData struct {
54	name              string
55	reg               regInfo
56	asm               string
57	typ               string // default result type
58	aux               string
59	rematerializeable bool
60	argLength         int32  // number of arguments, if -1, then this operation has a variable number of arguments
61	commutative       bool   // this operation is commutative on its first 2 arguments (e.g. addition)
62	resultInArg0      bool   // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
63	resultNotInArgs   bool   // outputs must not be allocated to the same registers as inputs
64	clobberFlags      bool   // this op clobbers flags register
65	call              bool   // is a function call
66	tailCall          bool   // is a tail call
67	nilCheck          bool   // this op is a nil check on arg0
68	faultOnNilArg0    bool   // this op will fault if arg0 is nil (and aux encodes a small offset)
69	faultOnNilArg1    bool   // this op will fault if arg1 is nil (and aux encodes a small offset)
70	hasSideEffects    bool   // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
71	zeroWidth         bool   // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width.
72	unsafePoint       bool   // this op is an unsafe point, i.e. not safe for async preemption
73	symEffect         string // effect this op has on symbol in aux
74	scale             uint8  // amd64/386 indexed load scale
75}
76
77type blockData struct {
78	name     string // the suffix for this block ("EQ", "LT", etc.)
79	controls int    // the number of control values this type of block requires
80	aux      string // the type of the Aux/AuxInt value, if any
81}
82
83type regInfo struct {
84	// inputs[i] encodes the set of registers allowed for the i'th input.
85	// Inputs that don't use registers (flags, memory, etc.) should be 0.
86	inputs []regMask
87	// clobbers encodes the set of registers that are overwritten by
88	// the instruction (other than the output registers).
89	clobbers regMask
90	// outputs[i] encodes the set of registers allowed for the i'th output.
91	outputs []regMask
92}
93
94type regMask uint64
95
96func (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
111var archs []arch
112
113var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
114var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
115var tracefile = flag.String("trace", "", "write trace to `file`")
116
117func 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	// The generate tasks are run concurrently, since they are CPU-intensive
150	// that can easily make use of many cores on a machine.
151	//
152	// Note that there is no limit on the concurrency at the moment. On a
153	// four-core laptop at the time of writing, peak RSS usually reaches
154	// ~200MiB, which seems doable by practically any machine nowadays. If
155	// that stops being the case, we can cap this func to a fixed number of
156	// architectures being generated at once.
157
158	tasks := []func(){
159		genOp,
160	}
161	for _, a := range archs {
162		a := a // the funcs are ran concurrently at a later time
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() // get up-to-date statistics
186		if err := pprof.WriteHeapProfile(f); err != nil {
187			log.Fatal("could not write memory profile: ", err)
188		}
189	}
190}
191
192func 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	// generate Block* declarations
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	// generate block kind string method
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	// generate block kind auxint method
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	// generate Op* declarations
246	fmt.Fprintln(w, "const (")
247	fmt.Fprintln(w, "OpInvalid Op = iota") // make sure OpInvalid is 0.
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	// generate OpInfo table
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			// flags
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				// OpConvert's register mask is selected dynamically,
294				// so don't try to check it in the static table.
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, "},") // close op
350				// generic ops have no reg info or asm
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			// Compute input allocation order. We allocate from the
362			// most to the least constrained input. This order guarantees
363			// that we will always be able to find a register.
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			// reg outputs
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, "},") // close reg info
399			fmt.Fprintln(w, "},") // close op
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	// generate op string method
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	// generate registers
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 // name in cmd/internal/obj/$ARCH
429			switch r {
430			case "SB":
431				// SB isn't a real register.  cmd/internal/obj expects 0 in this case.
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			// Assign a GC register map index to registers
441			// that may contain pointers.
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					// forgive extra spaces
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			// Won't fit in a uint32 mask.
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	// gofmt result
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	// Check that the arch genfile handles all the arch-specific opcodes.
508	// This is very much a hack, but it is better than nothing.
509	//
510	// Do a single regexp pass to record all ops being handled in a map, and
511	// then compare that with the ops list. This is much faster than one
512	// regexp pass per opcode.
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// Name returns the name of the architecture for use in Op* and Block* enumerations.
541func (a arch) Name() string {
542	s := a.name
543	if s == "generic" {
544		s = ""
545	}
546	return s
547}
548
549// countRegs returns the number of set bits in the register mask.
550func 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// for sorting a pair of integers by key
560type intPair struct {
561	key, val int
562}
563type byKey []intPair
564
565func (a byKey) Len() int           { return len(a) }
566func (a byKey) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
567func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }
568
569type ArchsByName []arch
570
571func (x ArchsByName) Len() int           { return len(x) }
572func (x ArchsByName) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
573func (x ArchsByName) Less(i, j int) bool { return x[i].name < x[j].name }
574