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