github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/ssa/gen/main.go (about) 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. 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 ) 22 23 type arch struct { 24 name string 25 pkg string // obj package to import for this arch. 26 genfile string // source file containing opcode code generation. 27 ops []opData 28 blocks []blockData 29 regnames []string 30 gpregmask regMask 31 fpregmask regMask 32 specialregmask regMask 33 framepointerreg int8 34 generic bool 35 } 36 37 type opData struct { 38 name string 39 reg regInfo 40 asm string 41 typ string // default result type 42 aux string 43 rematerializeable bool 44 argLength int32 // number of arguments, if -1, then this operation has a variable number of arguments 45 commutative bool // this operation is commutative on its first 2 arguments (e.g. addition) 46 resultInArg0 bool // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register 47 clobberFlags bool // this op clobbers flags register 48 } 49 50 type blockData struct { 51 name string 52 } 53 54 type regInfo struct { 55 inputs []regMask 56 clobbers regMask 57 outputs []regMask 58 } 59 60 type regMask uint64 61 62 func (a arch) regMaskComment(r regMask) string { 63 var buf bytes.Buffer 64 for i := uint64(0); r != 0; i++ { 65 if r&1 != 0 { 66 if buf.Len() == 0 { 67 buf.WriteString(" //") 68 } 69 buf.WriteString(" ") 70 buf.WriteString(a.regnames[i]) 71 } 72 r >>= 1 73 } 74 return buf.String() 75 } 76 77 var archs []arch 78 79 func main() { 80 flag.Parse() 81 sort.Sort(ArchsByName(archs)) 82 genOp() 83 genLower() 84 } 85 86 func genOp() { 87 w := new(bytes.Buffer) 88 fmt.Fprintf(w, "// autogenerated: do not edit!\n") 89 fmt.Fprintf(w, "// generated from gen/*Ops.go\n") 90 fmt.Fprintln(w) 91 fmt.Fprintln(w, "package ssa") 92 93 fmt.Fprintln(w, "import (") 94 fmt.Fprintln(w, "\"cmd/internal/obj\"") 95 for _, a := range archs { 96 if a.pkg != "" { 97 fmt.Fprintf(w, "%q\n", a.pkg) 98 } 99 } 100 fmt.Fprintln(w, ")") 101 102 // generate Block* declarations 103 fmt.Fprintln(w, "const (") 104 fmt.Fprintln(w, "BlockInvalid BlockKind = iota") 105 for _, a := range archs { 106 fmt.Fprintln(w) 107 for _, d := range a.blocks { 108 fmt.Fprintf(w, "Block%s%s\n", a.Name(), d.name) 109 } 110 } 111 fmt.Fprintln(w, ")") 112 113 // generate block kind string method 114 fmt.Fprintln(w, "var blockString = [...]string{") 115 fmt.Fprintln(w, "BlockInvalid:\"BlockInvalid\",") 116 for _, a := range archs { 117 fmt.Fprintln(w) 118 for _, b := range a.blocks { 119 fmt.Fprintf(w, "Block%s%s:\"%s\",\n", a.Name(), b.name, b.name) 120 } 121 } 122 fmt.Fprintln(w, "}") 123 fmt.Fprintln(w, "func (k BlockKind) String() string {return blockString[k]}") 124 125 // generate Op* declarations 126 fmt.Fprintln(w, "const (") 127 fmt.Fprintln(w, "OpInvalid Op = iota") 128 for _, a := range archs { 129 fmt.Fprintln(w) 130 for _, v := range a.ops { 131 fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name) 132 } 133 } 134 fmt.Fprintln(w, ")") 135 136 // generate OpInfo table 137 fmt.Fprintln(w, "var opcodeTable = [...]opInfo{") 138 fmt.Fprintln(w, " { name: \"OpInvalid\" },") 139 for _, a := range archs { 140 fmt.Fprintln(w) 141 142 pkg := path.Base(a.pkg) 143 for _, v := range a.ops { 144 fmt.Fprintln(w, "{") 145 fmt.Fprintf(w, "name:\"%s\",\n", v.name) 146 147 // flags 148 if v.aux != "" { 149 fmt.Fprintf(w, "auxType: aux%s,\n", v.aux) 150 } 151 fmt.Fprintf(w, "argLen: %d,\n", v.argLength) 152 153 if v.rematerializeable { 154 if v.reg.clobbers != 0 { 155 log.Fatalf("%s is rematerializeable and clobbers registers", v.name) 156 } 157 fmt.Fprintln(w, "rematerializeable: true,") 158 } 159 if v.commutative { 160 fmt.Fprintln(w, "commutative: true,") 161 } 162 if v.resultInArg0 { 163 fmt.Fprintln(w, "resultInArg0: true,") 164 if v.reg.inputs[0] != v.reg.outputs[0] { 165 log.Fatalf("input[0] and output[0] must use the same registers for %s", v.name) 166 } 167 if v.commutative && v.reg.inputs[1] != v.reg.outputs[0] { 168 log.Fatalf("input[1] and output[0] must use the same registers for %s", v.name) 169 } 170 } 171 if v.clobberFlags { 172 fmt.Fprintln(w, "clobberFlags: true,") 173 } 174 if a.name == "generic" { 175 fmt.Fprintln(w, "generic:true,") 176 fmt.Fprintln(w, "},") // close op 177 // generic ops have no reg info or asm 178 continue 179 } 180 if v.asm != "" { 181 fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm) 182 } 183 fmt.Fprintln(w, "reg:regInfo{") 184 185 // Compute input allocation order. We allocate from the 186 // most to the least constrained input. This order guarantees 187 // that we will always be able to find a register. 188 var s []intPair 189 for i, r := range v.reg.inputs { 190 if r != 0 { 191 s = append(s, intPair{countRegs(r), i}) 192 } 193 } 194 if len(s) > 0 { 195 sort.Sort(byKey(s)) 196 fmt.Fprintln(w, "inputs: []inputInfo{") 197 for _, p := range s { 198 r := v.reg.inputs[p.val] 199 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r)) 200 } 201 fmt.Fprintln(w, "},") 202 } 203 204 if v.reg.clobbers > 0 { 205 fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers)) 206 } 207 208 // reg outputs 209 s = s[:0] 210 for i, r := range v.reg.outputs { 211 s = append(s, intPair{countRegs(r), i}) 212 } 213 if len(s) > 0 { 214 sort.Sort(byKey(s)) 215 fmt.Fprintln(w, "outputs: []outputInfo{") 216 for _, p := range s { 217 r := v.reg.outputs[p.val] 218 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r)) 219 } 220 fmt.Fprintln(w, "},") 221 } 222 fmt.Fprintln(w, "},") // close reg info 223 fmt.Fprintln(w, "},") // close op 224 } 225 } 226 fmt.Fprintln(w, "}") 227 228 fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}") 229 230 // generate op string method 231 fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }") 232 233 // generate registers 234 for _, a := range archs { 235 if a.generic { 236 continue 237 } 238 fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name) 239 for i, r := range a.regnames { 240 fmt.Fprintf(w, " {%d, \"%s\"},\n", i, r) 241 } 242 fmt.Fprintln(w, "}") 243 fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask) 244 fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask) 245 fmt.Fprintf(w, "var specialRegMask%s = regMask(%d)\n", a.name, a.specialregmask) 246 fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg) 247 } 248 249 // gofmt result 250 b := w.Bytes() 251 var err error 252 b, err = format.Source(b) 253 if err != nil { 254 fmt.Printf("%s\n", w.Bytes()) 255 panic(err) 256 } 257 258 err = ioutil.WriteFile("../opGen.go", b, 0666) 259 if err != nil { 260 log.Fatalf("can't write output: %v\n", err) 261 } 262 263 // Check that the arch genfile handles all the arch-specific opcodes. 264 // This is very much a hack, but it is better than nothing. 265 for _, a := range archs { 266 if a.genfile == "" { 267 continue 268 } 269 270 src, err := ioutil.ReadFile(a.genfile) 271 if err != nil { 272 log.Fatalf("can't read %s: %v", a.genfile, err) 273 } 274 275 for _, v := range a.ops { 276 pattern := fmt.Sprintf("\\Wssa[.]Op%s%s\\W", a.name, v.name) 277 match, err := regexp.Match(pattern, src) 278 if err != nil { 279 log.Fatalf("bad opcode regexp %s: %v", pattern, err) 280 } 281 if !match { 282 log.Fatalf("Op%s%s has no code generation in %s", a.name, v.name, a.genfile) 283 } 284 } 285 } 286 } 287 288 // Name returns the name of the architecture for use in Op* and Block* enumerations. 289 func (a arch) Name() string { 290 s := a.name 291 if s == "generic" { 292 s = "" 293 } 294 return s 295 } 296 297 func genLower() { 298 for _, a := range archs { 299 genRules(a) 300 } 301 } 302 303 // countRegs returns the number of set bits in the register mask. 304 func countRegs(r regMask) int { 305 n := 0 306 for r != 0 { 307 n += int(r & 1) 308 r >>= 1 309 } 310 return n 311 } 312 313 // for sorting a pair of integers by key 314 type intPair struct { 315 key, val int 316 } 317 type byKey []intPair 318 319 func (a byKey) Len() int { return len(a) } 320 func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 321 func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key } 322 323 type ArchsByName []arch 324 325 func (x ArchsByName) Len() int { return len(x) } 326 func (x ArchsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 327 func (x ArchsByName) Less(i, j int) bool { return x[i].name < x[j].name }