github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/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 "strings" 22 ) 23 24 type 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 39 type 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 60 type blockData struct { 61 name string 62 } 63 64 type regInfo struct { 65 inputs []regMask 66 clobbers regMask 67 outputs []regMask 68 } 69 70 type regMask uint64 71 72 func (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 87 var archs []arch 88 89 func main() { 90 flag.Parse() 91 sort.Sort(ArchsByName(archs)) 92 genOp() 93 genLower() 94 } 95 96 func 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 if v.clobberFlags { 173 log.Fatalf("%s is rematerializeable and clobbers flags", v.name) 174 } 175 fmt.Fprintln(w, "rematerializeable: true,") 176 } 177 if v.commutative { 178 fmt.Fprintln(w, "commutative: true,") 179 } 180 if v.resultInArg0 { 181 fmt.Fprintln(w, "resultInArg0: true,") 182 if v.reg.inputs[0] != v.reg.outputs[0] { 183 log.Fatalf("%s: input[0] and output[0] must use the same registers for %s", a.name, v.name) 184 } 185 if v.commutative && v.reg.inputs[1] != v.reg.outputs[0] { 186 log.Fatalf("%s: input[1] and output[0] must use the same registers for %s", a.name, v.name) 187 } 188 } 189 if v.resultNotInArgs { 190 fmt.Fprintln(w, "resultNotInArgs: true,") 191 } 192 if v.clobberFlags { 193 fmt.Fprintln(w, "clobberFlags: true,") 194 } 195 if v.call { 196 fmt.Fprintln(w, "call: true,") 197 } 198 if v.nilCheck { 199 fmt.Fprintln(w, "nilCheck: true,") 200 } 201 if v.faultOnNilArg0 { 202 fmt.Fprintln(w, "faultOnNilArg0: true,") 203 if v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" { 204 log.Fatalf("faultOnNilArg0 with aux %s not allowed", v.aux) 205 } 206 } 207 if v.faultOnNilArg1 { 208 fmt.Fprintln(w, "faultOnNilArg1: true,") 209 if v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" { 210 log.Fatalf("faultOnNilArg1 with aux %s not allowed", v.aux) 211 } 212 } 213 if v.usesScratch { 214 fmt.Fprintln(w, "usesScratch: true,") 215 } 216 if v.hasSideEffects { 217 fmt.Fprintln(w, "hasSideEffects: true,") 218 } 219 needEffect := strings.HasPrefix(v.aux, "Sym") 220 if v.symEffect != "" { 221 if !needEffect { 222 log.Fatalf("symEffect with aux %s not allowed", v.aux) 223 } 224 fmt.Fprintf(w, "symEffect: Sym%s,\n", v.symEffect) 225 } else if needEffect { 226 log.Fatalf("symEffect needed for aux %s", v.aux) 227 } 228 if a.name == "generic" { 229 fmt.Fprintln(w, "generic:true,") 230 fmt.Fprintln(w, "},") // close op 231 // generic ops have no reg info or asm 232 continue 233 } 234 if v.asm != "" { 235 fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm) 236 } 237 fmt.Fprintln(w, "reg:regInfo{") 238 239 // Compute input allocation order. We allocate from the 240 // most to the least constrained input. This order guarantees 241 // that we will always be able to find a register. 242 var s []intPair 243 for i, r := range v.reg.inputs { 244 if r != 0 { 245 s = append(s, intPair{countRegs(r), i}) 246 } 247 } 248 if len(s) > 0 { 249 sort.Sort(byKey(s)) 250 fmt.Fprintln(w, "inputs: []inputInfo{") 251 for _, p := range s { 252 r := v.reg.inputs[p.val] 253 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r)) 254 } 255 fmt.Fprintln(w, "},") 256 } 257 258 if v.reg.clobbers > 0 { 259 fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers)) 260 } 261 262 // reg outputs 263 s = s[:0] 264 for i, r := range v.reg.outputs { 265 s = append(s, intPair{countRegs(r), i}) 266 } 267 if len(s) > 0 { 268 sort.Sort(byKey(s)) 269 fmt.Fprintln(w, "outputs: []outputInfo{") 270 for _, p := range s { 271 r := v.reg.outputs[p.val] 272 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r)) 273 } 274 fmt.Fprintln(w, "},") 275 } 276 fmt.Fprintln(w, "},") // close reg info 277 fmt.Fprintln(w, "},") // close op 278 } 279 } 280 fmt.Fprintln(w, "}") 281 282 fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}") 283 284 // generate op string method 285 fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }") 286 287 fmt.Fprintln(w, "func (o Op) UsesScratch() bool { return opcodeTable[o].usesScratch }") 288 289 fmt.Fprintln(w, "func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }") 290 fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }") 291 292 // generate registers 293 for _, a := range archs { 294 if a.generic { 295 continue 296 } 297 fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name) 298 for i, r := range a.regnames { 299 pkg := a.pkg[len("cmd/internal/obj/"):] 300 var objname string // name in cmd/internal/obj/$ARCH 301 switch r { 302 case "SB": 303 // SB isn't a real register. cmd/internal/obj expects 0 in this case. 304 objname = "0" 305 case "SP": 306 objname = pkg + ".REGSP" 307 case "g": 308 objname = pkg + ".REGG" 309 default: 310 objname = pkg + ".REG_" + r 311 } 312 fmt.Fprintf(w, " {%d, %s, \"%s\"},\n", i, objname, r) 313 } 314 fmt.Fprintln(w, "}") 315 fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask) 316 fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask) 317 fmt.Fprintf(w, "var specialRegMask%s = regMask(%d)\n", a.name, a.specialregmask) 318 fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg) 319 fmt.Fprintf(w, "var linkReg%s = int8(%d)\n", a.name, a.linkreg) 320 } 321 322 // gofmt result 323 b := w.Bytes() 324 var err error 325 b, err = format.Source(b) 326 if err != nil { 327 fmt.Printf("%s\n", w.Bytes()) 328 panic(err) 329 } 330 331 err = ioutil.WriteFile("../opGen.go", b, 0666) 332 if err != nil { 333 log.Fatalf("can't write output: %v\n", err) 334 } 335 336 // Check that the arch genfile handles all the arch-specific opcodes. 337 // This is very much a hack, but it is better than nothing. 338 for _, a := range archs { 339 if a.genfile == "" { 340 continue 341 } 342 343 src, err := ioutil.ReadFile(a.genfile) 344 if err != nil { 345 log.Fatalf("can't read %s: %v", a.genfile, err) 346 } 347 348 for _, v := range a.ops { 349 pattern := fmt.Sprintf("\\Wssa[.]Op%s%s\\W", a.name, v.name) 350 match, err := regexp.Match(pattern, src) 351 if err != nil { 352 log.Fatalf("bad opcode regexp %s: %v", pattern, err) 353 } 354 if !match { 355 log.Fatalf("Op%s%s has no code generation in %s", a.name, v.name, a.genfile) 356 } 357 } 358 } 359 } 360 361 // Name returns the name of the architecture for use in Op* and Block* enumerations. 362 func (a arch) Name() string { 363 s := a.name 364 if s == "generic" { 365 s = "" 366 } 367 return s 368 } 369 370 func genLower() { 371 for _, a := range archs { 372 genRules(a) 373 } 374 } 375 376 // countRegs returns the number of set bits in the register mask. 377 func countRegs(r regMask) int { 378 n := 0 379 for r != 0 { 380 n += int(r & 1) 381 r >>= 1 382 } 383 return n 384 } 385 386 // for sorting a pair of integers by key 387 type intPair struct { 388 key, val int 389 } 390 type byKey []intPair 391 392 func (a byKey) Len() int { return len(a) } 393 func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 394 func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key } 395 396 type ArchsByName []arch 397 398 func (x ArchsByName) Len() int { return len(x) } 399 func (x ArchsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 400 func (x ArchsByName) Less(i, j int) bool { return x[i].name < x[j].name }