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