github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 zeroWidth bool // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width. 58 symEffect string // effect this op has on symbol in aux 59 } 60 61 type blockData struct { 62 name string 63 } 64 65 type regInfo struct { 66 // inputs[i] encodes the set of registers allowed for the i'th input. 67 // Inputs that don't use registers (flags, memory, etc.) should be 0. 68 inputs []regMask 69 // clobbers encodes the set of registers that are overwritten by 70 // the instruction (other than the output registers). 71 clobbers regMask 72 // outpus[i] encodes the set of registers allowed for the i'th output. 73 outputs []regMask 74 } 75 76 type regMask uint64 77 78 func (a arch) regMaskComment(r regMask) string { 79 var buf bytes.Buffer 80 for i := uint64(0); r != 0; i++ { 81 if r&1 != 0 { 82 if buf.Len() == 0 { 83 buf.WriteString(" //") 84 } 85 buf.WriteString(" ") 86 buf.WriteString(a.regnames[i]) 87 } 88 r >>= 1 89 } 90 return buf.String() 91 } 92 93 var archs []arch 94 95 func main() { 96 flag.Parse() 97 sort.Sort(ArchsByName(archs)) 98 genOp() 99 genLower() 100 } 101 102 func genOp() { 103 w := new(bytes.Buffer) 104 fmt.Fprintf(w, "// Code generated from gen/*Ops.go; DO NOT EDIT.\n") 105 fmt.Fprintln(w) 106 fmt.Fprintln(w, "package ssa") 107 108 fmt.Fprintln(w, "import (") 109 fmt.Fprintln(w, "\"cmd/internal/obj\"") 110 for _, a := range archs { 111 if a.pkg != "" { 112 fmt.Fprintf(w, "%q\n", a.pkg) 113 } 114 } 115 fmt.Fprintln(w, ")") 116 117 // generate Block* declarations 118 fmt.Fprintln(w, "const (") 119 fmt.Fprintln(w, "BlockInvalid BlockKind = iota") 120 for _, a := range archs { 121 fmt.Fprintln(w) 122 for _, d := range a.blocks { 123 fmt.Fprintf(w, "Block%s%s\n", a.Name(), d.name) 124 } 125 } 126 fmt.Fprintln(w, ")") 127 128 // generate block kind string method 129 fmt.Fprintln(w, "var blockString = [...]string{") 130 fmt.Fprintln(w, "BlockInvalid:\"BlockInvalid\",") 131 for _, a := range archs { 132 fmt.Fprintln(w) 133 for _, b := range a.blocks { 134 fmt.Fprintf(w, "Block%s%s:\"%s\",\n", a.Name(), b.name, b.name) 135 } 136 } 137 fmt.Fprintln(w, "}") 138 fmt.Fprintln(w, "func (k BlockKind) String() string {return blockString[k]}") 139 140 // generate Op* declarations 141 fmt.Fprintln(w, "const (") 142 fmt.Fprintln(w, "OpInvalid Op = iota") // make sure OpInvalid is 0. 143 for _, a := range archs { 144 fmt.Fprintln(w) 145 for _, v := range a.ops { 146 if v.name == "Invalid" { 147 continue 148 } 149 fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name) 150 } 151 } 152 fmt.Fprintln(w, ")") 153 154 // generate OpInfo table 155 fmt.Fprintln(w, "var opcodeTable = [...]opInfo{") 156 fmt.Fprintln(w, " { name: \"OpInvalid\" },") 157 for _, a := range archs { 158 fmt.Fprintln(w) 159 160 pkg := path.Base(a.pkg) 161 for _, v := range a.ops { 162 if v.name == "Invalid" { 163 continue 164 } 165 fmt.Fprintln(w, "{") 166 fmt.Fprintf(w, "name:\"%s\",\n", v.name) 167 168 // flags 169 if v.aux != "" { 170 fmt.Fprintf(w, "auxType: aux%s,\n", v.aux) 171 } 172 fmt.Fprintf(w, "argLen: %d,\n", v.argLength) 173 174 if v.rematerializeable { 175 if v.reg.clobbers != 0 { 176 log.Fatalf("%s is rematerializeable and clobbers registers", v.name) 177 } 178 if v.clobberFlags { 179 log.Fatalf("%s is rematerializeable and clobbers flags", v.name) 180 } 181 fmt.Fprintln(w, "rematerializeable: true,") 182 } 183 if v.commutative { 184 fmt.Fprintln(w, "commutative: true,") 185 } 186 if v.resultInArg0 { 187 fmt.Fprintln(w, "resultInArg0: true,") 188 // OpConvert's register mask is selected dynamically, 189 // so don't try to check it in the static table. 190 if v.name != "Convert" && v.reg.inputs[0] != v.reg.outputs[0] { 191 log.Fatalf("%s: input[0] and output[0] must use the same registers for %s", a.name, v.name) 192 } 193 if v.name != "Convert" && v.commutative && v.reg.inputs[1] != v.reg.outputs[0] { 194 log.Fatalf("%s: input[1] and output[0] must use the same registers for %s", a.name, v.name) 195 } 196 } 197 if v.resultNotInArgs { 198 fmt.Fprintln(w, "resultNotInArgs: true,") 199 } 200 if v.clobberFlags { 201 fmt.Fprintln(w, "clobberFlags: true,") 202 } 203 if v.call { 204 fmt.Fprintln(w, "call: true,") 205 } 206 if v.nilCheck { 207 fmt.Fprintln(w, "nilCheck: true,") 208 } 209 if v.faultOnNilArg0 { 210 fmt.Fprintln(w, "faultOnNilArg0: true,") 211 if v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" { 212 log.Fatalf("faultOnNilArg0 with aux %s not allowed", v.aux) 213 } 214 } 215 if v.faultOnNilArg1 { 216 fmt.Fprintln(w, "faultOnNilArg1: true,") 217 if v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" { 218 log.Fatalf("faultOnNilArg1 with aux %s not allowed", v.aux) 219 } 220 } 221 if v.usesScratch { 222 fmt.Fprintln(w, "usesScratch: true,") 223 } 224 if v.hasSideEffects { 225 fmt.Fprintln(w, "hasSideEffects: true,") 226 } 227 if v.zeroWidth { 228 fmt.Fprintln(w, "zeroWidth: true,") 229 } 230 needEffect := strings.HasPrefix(v.aux, "Sym") 231 if v.symEffect != "" { 232 if !needEffect { 233 log.Fatalf("symEffect with aux %s not allowed", v.aux) 234 } 235 fmt.Fprintf(w, "symEffect: Sym%s,\n", strings.Replace(v.symEffect, ",", "|Sym", -1)) 236 } else if needEffect { 237 log.Fatalf("symEffect needed for aux %s", v.aux) 238 } 239 if a.name == "generic" { 240 fmt.Fprintln(w, "generic:true,") 241 fmt.Fprintln(w, "},") // close op 242 // generic ops have no reg info or asm 243 continue 244 } 245 if v.asm != "" { 246 fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm) 247 } 248 fmt.Fprintln(w, "reg:regInfo{") 249 250 // Compute input allocation order. We allocate from the 251 // most to the least constrained input. This order guarantees 252 // that we will always be able to find a register. 253 var s []intPair 254 for i, r := range v.reg.inputs { 255 if r != 0 { 256 s = append(s, intPair{countRegs(r), i}) 257 } 258 } 259 if len(s) > 0 { 260 sort.Sort(byKey(s)) 261 fmt.Fprintln(w, "inputs: []inputInfo{") 262 for _, p := range s { 263 r := v.reg.inputs[p.val] 264 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r)) 265 } 266 fmt.Fprintln(w, "},") 267 } 268 269 if v.reg.clobbers > 0 { 270 fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers)) 271 } 272 273 // reg outputs 274 s = s[:0] 275 for i, r := range v.reg.outputs { 276 s = append(s, intPair{countRegs(r), i}) 277 } 278 if len(s) > 0 { 279 sort.Sort(byKey(s)) 280 fmt.Fprintln(w, "outputs: []outputInfo{") 281 for _, p := range s { 282 r := v.reg.outputs[p.val] 283 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r)) 284 } 285 fmt.Fprintln(w, "},") 286 } 287 fmt.Fprintln(w, "},") // close reg info 288 fmt.Fprintln(w, "},") // close op 289 } 290 } 291 fmt.Fprintln(w, "}") 292 293 fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}") 294 295 // generate op string method 296 fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }") 297 298 fmt.Fprintln(w, "func (o Op) UsesScratch() bool { return opcodeTable[o].usesScratch }") 299 300 fmt.Fprintln(w, "func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }") 301 fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }") 302 303 // generate registers 304 for _, a := range archs { 305 if a.generic { 306 continue 307 } 308 fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name) 309 var gcRegN int 310 for i, r := range a.regnames { 311 pkg := a.pkg[len("cmd/internal/obj/"):] 312 var objname string // name in cmd/internal/obj/$ARCH 313 switch r { 314 case "SB": 315 // SB isn't a real register. cmd/internal/obj expects 0 in this case. 316 objname = "0" 317 case "SP": 318 objname = pkg + ".REGSP" 319 case "g": 320 objname = pkg + ".REGG" 321 default: 322 objname = pkg + ".REG_" + r 323 } 324 // Assign a GC register map index to registers 325 // that may contain pointers. 326 gcRegIdx := -1 327 if a.gpregmask&(1<<uint(i)) != 0 { 328 gcRegIdx = gcRegN 329 gcRegN++ 330 } 331 fmt.Fprintf(w, " {%d, %s, %d, \"%s\"},\n", i, objname, gcRegIdx, r) 332 } 333 if gcRegN > 32 { 334 // Won't fit in a uint32 mask. 335 log.Fatalf("too many GC registers (%d > 32) on %s", gcRegN, a.name) 336 } 337 fmt.Fprintln(w, "}") 338 fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask) 339 fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask) 340 fmt.Fprintf(w, "var specialRegMask%s = regMask(%d)\n", a.name, a.specialregmask) 341 fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg) 342 fmt.Fprintf(w, "var linkReg%s = int8(%d)\n", a.name, a.linkreg) 343 } 344 345 // gofmt result 346 b := w.Bytes() 347 var err error 348 b, err = format.Source(b) 349 if err != nil { 350 fmt.Printf("%s\n", w.Bytes()) 351 panic(err) 352 } 353 354 err = ioutil.WriteFile("../opGen.go", b, 0666) 355 if err != nil { 356 log.Fatalf("can't write output: %v\n", err) 357 } 358 359 // Check that the arch genfile handles all the arch-specific opcodes. 360 // This is very much a hack, but it is better than nothing. 361 for _, a := range archs { 362 if a.genfile == "" { 363 continue 364 } 365 366 src, err := ioutil.ReadFile(a.genfile) 367 if err != nil { 368 log.Fatalf("can't read %s: %v", a.genfile, err) 369 } 370 371 for _, v := range a.ops { 372 pattern := fmt.Sprintf("\\Wssa[.]Op%s%s\\W", a.name, v.name) 373 match, err := regexp.Match(pattern, src) 374 if err != nil { 375 log.Fatalf("bad opcode regexp %s: %v", pattern, err) 376 } 377 if !match { 378 log.Fatalf("Op%s%s has no code generation in %s", a.name, v.name, a.genfile) 379 } 380 } 381 } 382 } 383 384 // Name returns the name of the architecture for use in Op* and Block* enumerations. 385 func (a arch) Name() string { 386 s := a.name 387 if s == "generic" { 388 s = "" 389 } 390 return s 391 } 392 393 func genLower() { 394 for _, a := range archs { 395 genRules(a) 396 } 397 } 398 399 // countRegs returns the number of set bits in the register mask. 400 func countRegs(r regMask) int { 401 n := 0 402 for r != 0 { 403 n += int(r & 1) 404 r >>= 1 405 } 406 return n 407 } 408 409 // for sorting a pair of integers by key 410 type intPair struct { 411 key, val int 412 } 413 type byKey []intPair 414 415 func (a byKey) Len() int { return len(a) } 416 func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 417 func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key } 418 419 type ArchsByName []arch 420 421 func (x ArchsByName) Len() int { return len(x) } 422 func (x ArchsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 423 func (x ArchsByName) Less(i, j int) bool { return x[i].name < x[j].name }