Source file src/pkg/cmd/compile/internal/ssa/gen/main.go
1
2
3
4
5
6
7
8
9 package main
10
11 import (
12 "bytes"
13 "flag"
14 "fmt"
15 "go/format"
16 "io/ioutil"
17 "log"
18 "path"
19 "regexp"
20 "sort"
21 "strings"
22 )
23
24 type arch struct {
25 name string
26 pkg string
27 genfile string
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
39 type opData struct {
40 name string
41 reg regInfo
42 asm string
43 typ string
44 aux string
45 rematerializeable bool
46 argLength int32
47 commutative bool
48 resultInArg0 bool
49 resultNotInArgs bool
50 clobberFlags bool
51 call bool
52 nilCheck bool
53 faultOnNilArg0 bool
54 faultOnNilArg1 bool
55 usesScratch bool
56 hasSideEffects bool
57 zeroWidth bool
58 symEffect string
59 scale uint8
60 }
61
62 type blockData struct {
63 name string
64 }
65
66 type regInfo struct {
67
68
69 inputs []regMask
70
71
72 clobbers regMask
73
74 outputs []regMask
75 }
76
77 type regMask uint64
78
79 func (a arch) regMaskComment(r regMask) string {
80 var buf bytes.Buffer
81 for i := uint64(0); r != 0; i++ {
82 if r&1 != 0 {
83 if buf.Len() == 0 {
84 buf.WriteString(" //")
85 }
86 buf.WriteString(" ")
87 buf.WriteString(a.regnames[i])
88 }
89 r >>= 1
90 }
91 return buf.String()
92 }
93
94 var archs []arch
95
96 func main() {
97 flag.Parse()
98 sort.Sort(ArchsByName(archs))
99 genOp()
100 genLower()
101 }
102
103 func genOp() {
104 w := new(bytes.Buffer)
105 fmt.Fprintf(w, "// Code generated from gen/*Ops.go; DO NOT EDIT.\n")
106 fmt.Fprintln(w)
107 fmt.Fprintln(w, "package ssa")
108
109 fmt.Fprintln(w, "import (")
110 fmt.Fprintln(w, "\"cmd/internal/obj\"")
111 for _, a := range archs {
112 if a.pkg != "" {
113 fmt.Fprintf(w, "%q\n", a.pkg)
114 }
115 }
116 fmt.Fprintln(w, ")")
117
118
119 fmt.Fprintln(w, "const (")
120 fmt.Fprintln(w, "BlockInvalid BlockKind = iota")
121 for _, a := range archs {
122 fmt.Fprintln(w)
123 for _, d := range a.blocks {
124 fmt.Fprintf(w, "Block%s%s\n", a.Name(), d.name)
125 }
126 }
127 fmt.Fprintln(w, ")")
128
129
130 fmt.Fprintln(w, "var blockString = [...]string{")
131 fmt.Fprintln(w, "BlockInvalid:\"BlockInvalid\",")
132 for _, a := range archs {
133 fmt.Fprintln(w)
134 for _, b := range a.blocks {
135 fmt.Fprintf(w, "Block%s%s:\"%s\",\n", a.Name(), b.name, b.name)
136 }
137 }
138 fmt.Fprintln(w, "}")
139 fmt.Fprintln(w, "func (k BlockKind) String() string {return blockString[k]}")
140
141
142 fmt.Fprintln(w, "const (")
143 fmt.Fprintln(w, "OpInvalid Op = iota")
144 for _, a := range archs {
145 fmt.Fprintln(w)
146 for _, v := range a.ops {
147 if v.name == "Invalid" {
148 continue
149 }
150 fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name)
151 }
152 }
153 fmt.Fprintln(w, ")")
154
155
156 fmt.Fprintln(w, "var opcodeTable = [...]opInfo{")
157 fmt.Fprintln(w, " { name: \"OpInvalid\" },")
158 for _, a := range archs {
159 fmt.Fprintln(w)
160
161 pkg := path.Base(a.pkg)
162 for _, v := range a.ops {
163 if v.name == "Invalid" {
164 continue
165 }
166 fmt.Fprintln(w, "{")
167 fmt.Fprintf(w, "name:\"%s\",\n", v.name)
168
169
170 if v.aux != "" {
171 fmt.Fprintf(w, "auxType: aux%s,\n", v.aux)
172 }
173 fmt.Fprintf(w, "argLen: %d,\n", v.argLength)
174
175 if v.rematerializeable {
176 if v.reg.clobbers != 0 {
177 log.Fatalf("%s is rematerializeable and clobbers registers", v.name)
178 }
179 if v.clobberFlags {
180 log.Fatalf("%s is rematerializeable and clobbers flags", v.name)
181 }
182 fmt.Fprintln(w, "rematerializeable: true,")
183 }
184 if v.commutative {
185 fmt.Fprintln(w, "commutative: true,")
186 }
187 if v.resultInArg0 {
188 fmt.Fprintln(w, "resultInArg0: true,")
189
190
191 if v.name != "Convert" && v.reg.inputs[0] != v.reg.outputs[0] {
192 log.Fatalf("%s: input[0] and output[0] must use the same registers for %s", a.name, v.name)
193 }
194 if v.name != "Convert" && v.commutative && v.reg.inputs[1] != v.reg.outputs[0] {
195 log.Fatalf("%s: input[1] and output[0] must use the same registers for %s", a.name, v.name)
196 }
197 }
198 if v.resultNotInArgs {
199 fmt.Fprintln(w, "resultNotInArgs: true,")
200 }
201 if v.clobberFlags {
202 fmt.Fprintln(w, "clobberFlags: true,")
203 }
204 if v.call {
205 fmt.Fprintln(w, "call: true,")
206 }
207 if v.nilCheck {
208 fmt.Fprintln(w, "nilCheck: true,")
209 }
210 if v.faultOnNilArg0 {
211 fmt.Fprintln(w, "faultOnNilArg0: true,")
212 if v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" {
213 log.Fatalf("faultOnNilArg0 with aux %s not allowed", v.aux)
214 }
215 }
216 if v.faultOnNilArg1 {
217 fmt.Fprintln(w, "faultOnNilArg1: true,")
218 if v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" {
219 log.Fatalf("faultOnNilArg1 with aux %s not allowed", v.aux)
220 }
221 }
222 if v.usesScratch {
223 fmt.Fprintln(w, "usesScratch: true,")
224 }
225 if v.hasSideEffects {
226 fmt.Fprintln(w, "hasSideEffects: true,")
227 }
228 if v.zeroWidth {
229 fmt.Fprintln(w, "zeroWidth: true,")
230 }
231 needEffect := strings.HasPrefix(v.aux, "Sym")
232 if v.symEffect != "" {
233 if !needEffect {
234 log.Fatalf("symEffect with aux %s not allowed", v.aux)
235 }
236 fmt.Fprintf(w, "symEffect: Sym%s,\n", strings.Replace(v.symEffect, ",", "|Sym", -1))
237 } else if needEffect {
238 log.Fatalf("symEffect needed for aux %s", v.aux)
239 }
240 if a.name == "generic" {
241 fmt.Fprintln(w, "generic:true,")
242 fmt.Fprintln(w, "},")
243
244 continue
245 }
246 if v.asm != "" {
247 fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm)
248 }
249 if v.scale != 0 {
250 fmt.Fprintf(w, "scale: %d,\n", v.scale)
251 }
252 fmt.Fprintln(w, "reg:regInfo{")
253
254
255
256
257 var s []intPair
258 for i, r := range v.reg.inputs {
259 if r != 0 {
260 s = append(s, intPair{countRegs(r), i})
261 }
262 }
263 if len(s) > 0 {
264 sort.Sort(byKey(s))
265 fmt.Fprintln(w, "inputs: []inputInfo{")
266 for _, p := range s {
267 r := v.reg.inputs[p.val]
268 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
269 }
270 fmt.Fprintln(w, "},")
271 }
272
273 if v.reg.clobbers > 0 {
274 fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers))
275 }
276
277
278 s = s[:0]
279 for i, r := range v.reg.outputs {
280 s = append(s, intPair{countRegs(r), i})
281 }
282 if len(s) > 0 {
283 sort.Sort(byKey(s))
284 fmt.Fprintln(w, "outputs: []outputInfo{")
285 for _, p := range s {
286 r := v.reg.outputs[p.val]
287 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
288 }
289 fmt.Fprintln(w, "},")
290 }
291 fmt.Fprintln(w, "},")
292 fmt.Fprintln(w, "},")
293 }
294 }
295 fmt.Fprintln(w, "}")
296
297 fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}")
298 fmt.Fprintln(w, "func (o Op) Scale() int16 {return int16(opcodeTable[o].scale)}")
299
300
301 fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
302
303 fmt.Fprintln(w, "func (o Op) UsesScratch() bool { return opcodeTable[o].usesScratch }")
304
305 fmt.Fprintln(w, "func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }")
306 fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }")
307
308
309 for _, a := range archs {
310 if a.generic {
311 continue
312 }
313 fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name)
314 var gcRegN int
315 for i, r := range a.regnames {
316 pkg := a.pkg[len("cmd/internal/obj/"):]
317 var objname string
318 switch r {
319 case "SB":
320
321 objname = "0"
322 case "SP":
323 objname = pkg + ".REGSP"
324 case "g":
325 objname = pkg + ".REGG"
326 default:
327 objname = pkg + ".REG_" + r
328 }
329
330
331 gcRegIdx := -1
332 if a.gpregmask&(1<<uint(i)) != 0 {
333 gcRegIdx = gcRegN
334 gcRegN++
335 }
336 fmt.Fprintf(w, " {%d, %s, %d, \"%s\"},\n", i, objname, gcRegIdx, r)
337 }
338 if gcRegN > 32 {
339
340 log.Fatalf("too many GC registers (%d > 32) on %s", gcRegN, a.name)
341 }
342 fmt.Fprintln(w, "}")
343 fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask)
344 fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask)
345 fmt.Fprintf(w, "var specialRegMask%s = regMask(%d)\n", a.name, a.specialregmask)
346 fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg)
347 fmt.Fprintf(w, "var linkReg%s = int8(%d)\n", a.name, a.linkreg)
348 }
349
350
351 b := w.Bytes()
352 var err error
353 b, err = format.Source(b)
354 if err != nil {
355 fmt.Printf("%s\n", w.Bytes())
356 panic(err)
357 }
358
359 err = ioutil.WriteFile("../opGen.go", b, 0666)
360 if err != nil {
361 log.Fatalf("can't write output: %v\n", err)
362 }
363
364
365
366 for _, a := range archs {
367 if a.genfile == "" {
368 continue
369 }
370
371 src, err := ioutil.ReadFile(a.genfile)
372 if err != nil {
373 log.Fatalf("can't read %s: %v", a.genfile, err)
374 }
375
376 for _, v := range a.ops {
377 pattern := fmt.Sprintf("\\Wssa[.]Op%s%s\\W", a.name, v.name)
378 match, err := regexp.Match(pattern, src)
379 if err != nil {
380 log.Fatalf("bad opcode regexp %s: %v", pattern, err)
381 }
382 if !match {
383 log.Fatalf("Op%s%s has no code generation in %s", a.name, v.name, a.genfile)
384 }
385 }
386 }
387 }
388
389
390 func (a arch) Name() string {
391 s := a.name
392 if s == "generic" {
393 s = ""
394 }
395 return s
396 }
397
398 func genLower() {
399 for _, a := range archs {
400 genRules(a)
401 genSplitLoadRules(a)
402 }
403 }
404
405
406 func countRegs(r regMask) int {
407 n := 0
408 for r != 0 {
409 n += int(r & 1)
410 r >>= 1
411 }
412 return n
413 }
414
415
416 type intPair struct {
417 key, val int
418 }
419 type byKey []intPair
420
421 func (a byKey) Len() int { return len(a) }
422 func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
423 func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }
424
425 type ArchsByName []arch
426
427 func (x ArchsByName) Len() int { return len(x) }
428 func (x ArchsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
429 func (x ArchsByName) Less(i, j int) bool { return x[i].name < x[j].name }
430
View as plain text