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