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// +build ignore
6
7// The gen command generates Go code (in the parent directory) for all
8// the architecture-specific opcodes, blocks, and rewrites.
9package main
10
11import (
12	"bytes"
13	"flag"
14	"fmt"
15	"go/format"
16	"io/ioutil"
17	"log"
18	"path"
19	"regexp"
20	"sort"
21	"strings"
22)
23
24type arch struct {
25	name            string
26	pkg             string // obj package to import for this arch.
27	genfile         string // source file containing opcode code generation.
28	ops             []opData
29	blocks          []blockData
30	regnames        []string
31	gpregmask       regMask
32	fpregmask       regMask
33	specialregmask  regMask
34	framepointerreg int8
35	linkreg         int8
36	generic         bool
37}
38
39type opData struct {
40	name              string
41	reg               regInfo
42	asm               string
43	typ               string // default result type
44	aux               string
45	rematerializeable bool
46	argLength         int32  // number of arguments, if -1, then this operation has a variable number of arguments
47	commutative       bool   // this operation is commutative on its first 2 arguments (e.g. addition)
48	resultInArg0      bool   // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
49	resultNotInArgs   bool   // outputs must not be allocated to the same registers as inputs
50	clobberFlags      bool   // this op clobbers flags register
51	call              bool   // is a function call
52	nilCheck          bool   // this op is a nil check on arg0
53	faultOnNilArg0    bool   // this op will fault if arg0 is nil (and aux encodes a small offset)
54	faultOnNilArg1    bool   // this op will fault if arg1 is nil (and aux encodes a small offset)
55	usesScratch       bool   // this op requires scratch memory space
56	hasSideEffects    bool   // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
57	symEffect         string // effect this op has on symbol in aux
58}
59
60type blockData struct {
61	name string
62}
63
64type regInfo struct {
65	inputs   []regMask
66	clobbers regMask
67	outputs  []regMask
68}
69
70type regMask uint64
71
72func (a arch) regMaskComment(r regMask) string {
73	var buf bytes.Buffer
74	for i := uint64(0); r != 0; i++ {
75		if r&1 != 0 {
76			if buf.Len() == 0 {
77				buf.WriteString(" //")
78			}
79			buf.WriteString(" ")
80			buf.WriteString(a.regnames[i])
81		}
82		r >>= 1
83	}
84	return buf.String()
85}
86
87var archs []arch
88
89func main() {
90	flag.Parse()
91	sort.Sort(ArchsByName(archs))
92	genOp()
93	genLower()
94}
95
96func genOp() {
97	w := new(bytes.Buffer)
98	fmt.Fprintf(w, "// Code generated from gen/*Ops.go; DO NOT EDIT.\n")
99	fmt.Fprintln(w)
100	fmt.Fprintln(w, "package ssa")
101
102	fmt.Fprintln(w, "import (")
103	fmt.Fprintln(w, "\"cmd/internal/obj\"")
104	for _, a := range archs {
105		if a.pkg != "" {
106			fmt.Fprintf(w, "%q\n", a.pkg)
107		}
108	}
109	fmt.Fprintln(w, ")")
110
111	// generate Block* declarations
112	fmt.Fprintln(w, "const (")
113	fmt.Fprintln(w, "BlockInvalid BlockKind = iota")
114	for _, a := range archs {
115		fmt.Fprintln(w)
116		for _, d := range a.blocks {
117			fmt.Fprintf(w, "Block%s%s\n", a.Name(), d.name)
118		}
119	}
120	fmt.Fprintln(w, ")")
121
122	// generate block kind string method
123	fmt.Fprintln(w, "var blockString = [...]string{")
124	fmt.Fprintln(w, "BlockInvalid:\"BlockInvalid\",")
125	for _, a := range archs {
126		fmt.Fprintln(w)
127		for _, b := range a.blocks {
128			fmt.Fprintf(w, "Block%s%s:\"%s\",\n", a.Name(), b.name, b.name)
129		}
130	}
131	fmt.Fprintln(w, "}")
132	fmt.Fprintln(w, "func (k BlockKind) String() string {return blockString[k]}")
133
134	// generate Op* declarations
135	fmt.Fprintln(w, "const (")
136	fmt.Fprintln(w, "OpInvalid Op = iota") // make sure OpInvalid is 0.
137	for _, a := range archs {
138		fmt.Fprintln(w)
139		for _, v := range a.ops {
140			if v.name == "Invalid" {
141				continue
142			}
143			fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name)
144		}
145	}
146	fmt.Fprintln(w, ")")
147
148	// generate OpInfo table
149	fmt.Fprintln(w, "var opcodeTable = [...]opInfo{")
150	fmt.Fprintln(w, " { name: \"OpInvalid\" },")
151	for _, a := range archs {
152		fmt.Fprintln(w)
153
154		pkg := path.Base(a.pkg)
155		for _, v := range a.ops {
156			if v.name == "Invalid" {
157				continue
158			}
159			fmt.Fprintln(w, "{")
160			fmt.Fprintf(w, "name:\"%s\",\n", v.name)
161
162			// flags
163			if v.aux != "" {
164				fmt.Fprintf(w, "auxType: aux%s,\n", v.aux)
165			}
166			fmt.Fprintf(w, "argLen: %d,\n", v.argLength)
167
168			if v.rematerializeable {
169				if v.reg.clobbers != 0 {
170					log.Fatalf("%s is rematerializeable and clobbers registers", v.name)
171				}
172				fmt.Fprintln(w, "rematerializeable: true,")
173			}
174			if v.commutative {
175				fmt.Fprintln(w, "commutative: true,")
176			}
177			if v.resultInArg0 {
178				fmt.Fprintln(w, "resultInArg0: true,")
179				if v.reg.inputs[0] != v.reg.outputs[0] {
180					log.Fatalf("input[0] and output[0] must use the same registers for %s", v.name)
181				}
182				if v.commutative && v.reg.inputs[1] != v.reg.outputs[0] {
183					log.Fatalf("input[1] and output[0] must use the same registers for %s", v.name)
184				}
185			}
186			if v.resultNotInArgs {
187				fmt.Fprintln(w, "resultNotInArgs: true,")
188			}
189			if v.clobberFlags {
190				fmt.Fprintln(w, "clobberFlags: true,")
191			}
192			if v.call {
193				fmt.Fprintln(w, "call: true,")
194			}
195			if v.nilCheck {
196				fmt.Fprintln(w, "nilCheck: true,")
197			}
198			if v.faultOnNilArg0 {
199				fmt.Fprintln(w, "faultOnNilArg0: true,")
200				if v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" {
201					log.Fatalf("faultOnNilArg0 with aux %s not allowed", v.aux)
202				}
203			}
204			if v.faultOnNilArg1 {
205				fmt.Fprintln(w, "faultOnNilArg1: true,")
206				if v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" {
207					log.Fatalf("faultOnNilArg1 with aux %s not allowed", v.aux)
208				}
209			}
210			if v.usesScratch {
211				fmt.Fprintln(w, "usesScratch: true,")
212			}
213			if v.hasSideEffects {
214				fmt.Fprintln(w, "hasSideEffects: true,")
215			}
216			needEffect := strings.HasPrefix(v.aux, "Sym")
217			if v.symEffect != "" {
218				if !needEffect {
219					log.Fatalf("symEffect with aux %s not allowed", v.aux)
220				}
221				fmt.Fprintf(w, "symEffect: Sym%s,\n", v.symEffect)
222			} else if needEffect {
223				log.Fatalf("symEffect needed for aux %s", v.aux)
224			}
225			if a.name == "generic" {
226				fmt.Fprintln(w, "generic:true,")
227				fmt.Fprintln(w, "},") // close op
228				// generic ops have no reg info or asm
229				continue
230			}
231			if v.asm != "" {
232				fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm)
233			}
234			fmt.Fprintln(w, "reg:regInfo{")
235
236			// Compute input allocation order. We allocate from the
237			// most to the least constrained input. This order guarantees
238			// that we will always be able to find a register.
239			var s []intPair
240			for i, r := range v.reg.inputs {
241				if r != 0 {
242					s = append(s, intPair{countRegs(r), i})
243				}
244			}
245			if len(s) > 0 {
246				sort.Sort(byKey(s))
247				fmt.Fprintln(w, "inputs: []inputInfo{")
248				for _, p := range s {
249					r := v.reg.inputs[p.val]
250					fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
251				}
252				fmt.Fprintln(w, "},")
253			}
254
255			if v.reg.clobbers > 0 {
256				fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers))
257			}
258
259			// reg outputs
260			s = s[:0]
261			for i, r := range v.reg.outputs {
262				s = append(s, intPair{countRegs(r), i})
263			}
264			if len(s) > 0 {
265				sort.Sort(byKey(s))
266				fmt.Fprintln(w, "outputs: []outputInfo{")
267				for _, p := range s {
268					r := v.reg.outputs[p.val]
269					fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
270				}
271				fmt.Fprintln(w, "},")
272			}
273			fmt.Fprintln(w, "},") // close reg info
274			fmt.Fprintln(w, "},") // close op
275		}
276	}
277	fmt.Fprintln(w, "}")
278
279	fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}")
280
281	// generate op string method
282	fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
283
284	fmt.Fprintln(w, "func (o Op) UsesScratch() bool { return opcodeTable[o].usesScratch }")
285
286	fmt.Fprintln(w, "func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }")
287	fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }")
288
289	// generate registers
290	for _, a := range archs {
291		if a.generic {
292			continue
293		}
294		fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name)
295		for i, r := range a.regnames {
296			pkg := a.pkg[len("cmd/internal/obj/"):]
297			var objname string // name in cmd/internal/obj/$ARCH
298			switch r {
299			case "SB":
300				// SB isn't a real register.  cmd/internal/obj expects 0 in this case.
301				objname = "0"
302			case "SP":
303				objname = pkg + ".REGSP"
304			case "g":
305				objname = pkg + ".REGG"
306			default:
307				objname = pkg + ".REG_" + r
308			}
309			fmt.Fprintf(w, "  {%d, %s, \"%s\"},\n", i, objname, r)
310		}
311		fmt.Fprintln(w, "}")
312		fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask)
313		fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask)
314		fmt.Fprintf(w, "var specialRegMask%s = regMask(%d)\n", a.name, a.specialregmask)
315		fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg)
316		fmt.Fprintf(w, "var linkReg%s = int8(%d)\n", a.name, a.linkreg)
317	}
318
319	// gofmt result
320	b := w.Bytes()
321	var err error
322	b, err = format.Source(b)
323	if err != nil {
324		fmt.Printf("%s\n", w.Bytes())
325		panic(err)
326	}
327
328	err = ioutil.WriteFile("../opGen.go", b, 0666)
329	if err != nil {
330		log.Fatalf("can't write output: %v\n", err)
331	}
332
333	// Check that the arch genfile handles all the arch-specific opcodes.
334	// This is very much a hack, but it is better than nothing.
335	for _, a := range archs {
336		if a.genfile == "" {
337			continue
338		}
339
340		src, err := ioutil.ReadFile(a.genfile)
341		if err != nil {
342			log.Fatalf("can't read %s: %v", a.genfile, err)
343		}
344
345		for _, v := range a.ops {
346			pattern := fmt.Sprintf("\\Wssa[.]Op%s%s\\W", a.name, v.name)
347			match, err := regexp.Match(pattern, src)
348			if err != nil {
349				log.Fatalf("bad opcode regexp %s: %v", pattern, err)
350			}
351			if !match {
352				log.Fatalf("Op%s%s has no code generation in %s", a.name, v.name, a.genfile)
353			}
354		}
355	}
356}
357
358// Name returns the name of the architecture for use in Op* and Block* enumerations.
359func (a arch) Name() string {
360	s := a.name
361	if s == "generic" {
362		s = ""
363	}
364	return s
365}
366
367func genLower() {
368	for _, a := range archs {
369		genRules(a)
370	}
371}
372
373// countRegs returns the number of set bits in the register mask.
374func countRegs(r regMask) int {
375	n := 0
376	for r != 0 {
377		n += int(r & 1)
378		r >>= 1
379	}
380	return n
381}
382
383// for sorting a pair of integers by key
384type intPair struct {
385	key, val int
386}
387type byKey []intPair
388
389func (a byKey) Len() int           { return len(a) }
390func (a byKey) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
391func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }
392
393type ArchsByName []arch
394
395func (x ArchsByName) Len() int           { return len(x) }
396func (x ArchsByName) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
397func (x ArchsByName) Less(i, j int) bool { return x[i].name < x[j].name }
398