github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/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 generic bool 31 } 32 33 type opData struct { 34 name string 35 reg regInfo 36 asm string 37 typ string // default result type 38 aux string 39 rematerializeable bool 40 argLength int32 // number of arguments, if -1, then this operation has a variable number of arguments 41 commutative bool // this operation is commutative (e.g. addition) 42 resultInArg0 bool // v and v.Args[0] must be allocated to the same register 43 } 44 45 type blockData struct { 46 name string 47 } 48 49 type regInfo struct { 50 inputs []regMask 51 clobbers regMask 52 outputs []regMask 53 } 54 55 type regMask uint64 56 57 func (a arch) regMaskComment(r regMask) string { 58 var buf bytes.Buffer 59 for i := uint64(0); r != 0; i++ { 60 if r&1 != 0 { 61 if buf.Len() == 0 { 62 buf.WriteString(" //") 63 } 64 buf.WriteString(" ") 65 buf.WriteString(a.regnames[i]) 66 } 67 r >>= 1 68 } 69 return buf.String() 70 } 71 72 var archs []arch 73 74 func main() { 75 flag.Parse() 76 genOp() 77 genLower() 78 } 79 80 func genOp() { 81 w := new(bytes.Buffer) 82 fmt.Fprintf(w, "// autogenerated: do not edit!\n") 83 fmt.Fprintf(w, "// generated from gen/*Ops.go\n") 84 fmt.Fprintln(w) 85 fmt.Fprintln(w, "package ssa") 86 87 fmt.Fprintln(w, "import (") 88 fmt.Fprintln(w, "\"cmd/internal/obj\"") 89 for _, a := range archs { 90 if a.pkg != "" { 91 fmt.Fprintf(w, "%q\n", a.pkg) 92 } 93 } 94 fmt.Fprintln(w, ")") 95 96 // generate Block* declarations 97 fmt.Fprintln(w, "const (") 98 fmt.Fprintln(w, "BlockInvalid BlockKind = iota") 99 for _, a := range archs { 100 fmt.Fprintln(w) 101 for _, d := range a.blocks { 102 fmt.Fprintf(w, "Block%s%s\n", a.Name(), d.name) 103 } 104 } 105 fmt.Fprintln(w, ")") 106 107 // generate block kind string method 108 fmt.Fprintln(w, "var blockString = [...]string{") 109 fmt.Fprintln(w, "BlockInvalid:\"BlockInvalid\",") 110 for _, a := range archs { 111 fmt.Fprintln(w) 112 for _, b := range a.blocks { 113 fmt.Fprintf(w, "Block%s%s:\"%s\",\n", a.Name(), b.name, b.name) 114 } 115 } 116 fmt.Fprintln(w, "}") 117 fmt.Fprintln(w, "func (k BlockKind) String() string {return blockString[k]}") 118 119 // generate Op* declarations 120 fmt.Fprintln(w, "const (") 121 fmt.Fprintln(w, "OpInvalid Op = iota") 122 for _, a := range archs { 123 fmt.Fprintln(w) 124 for _, v := range a.ops { 125 fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name) 126 } 127 } 128 fmt.Fprintln(w, ")") 129 130 // generate OpInfo table 131 fmt.Fprintln(w, "var opcodeTable = [...]opInfo{") 132 fmt.Fprintln(w, " { name: \"OpInvalid\" },") 133 for _, a := range archs { 134 fmt.Fprintln(w) 135 136 pkg := path.Base(a.pkg) 137 for _, v := range a.ops { 138 fmt.Fprintln(w, "{") 139 fmt.Fprintf(w, "name:\"%s\",\n", v.name) 140 141 // flags 142 if v.aux != "" { 143 fmt.Fprintf(w, "auxType: aux%s,\n", v.aux) 144 } 145 fmt.Fprintf(w, "argLen: %d,\n", v.argLength) 146 147 if v.rematerializeable { 148 if v.reg.clobbers != 0 { 149 log.Fatalf("%s is rematerializeable and clobbers registers", v.name) 150 } 151 fmt.Fprintln(w, "rematerializeable: true,") 152 } 153 if v.commutative { 154 fmt.Fprintln(w, "commutative: true,") 155 } 156 if v.resultInArg0 { 157 fmt.Fprintln(w, "resultInArg0: true,") 158 if v.reg.inputs[0] != v.reg.outputs[0] { 159 log.Fatalf("input[0] and output registers must be equal for %s", v.name) 160 } 161 if v.commutative && v.reg.inputs[1] != v.reg.outputs[0] { 162 log.Fatalf("input[1] and output registers must be equal for %s", v.name) 163 } 164 } 165 if a.name == "generic" { 166 fmt.Fprintln(w, "generic:true,") 167 fmt.Fprintln(w, "},") // close op 168 // generic ops have no reg info or asm 169 continue 170 } 171 if v.asm != "" { 172 fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm) 173 } 174 fmt.Fprintln(w, "reg:regInfo{") 175 176 // Compute input allocation order. We allocate from the 177 // most to the least constrained input. This order guarantees 178 // that we will always be able to find a register. 179 var s []intPair 180 for i, r := range v.reg.inputs { 181 if r != 0 { 182 s = append(s, intPair{countRegs(r), i}) 183 } 184 } 185 if len(s) > 0 { 186 sort.Sort(byKey(s)) 187 fmt.Fprintln(w, "inputs: []inputInfo{") 188 for _, p := range s { 189 r := v.reg.inputs[p.val] 190 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r)) 191 } 192 fmt.Fprintln(w, "},") 193 } 194 if v.reg.clobbers > 0 { 195 fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers)) 196 } 197 // reg outputs 198 if len(v.reg.outputs) > 0 { 199 fmt.Fprintln(w, "outputs: []regMask{") 200 for _, r := range v.reg.outputs { 201 fmt.Fprintf(w, "%d,%s\n", r, a.regMaskComment(r)) 202 } 203 fmt.Fprintln(w, "},") 204 } 205 fmt.Fprintln(w, "},") // close reg info 206 fmt.Fprintln(w, "},") // close op 207 } 208 } 209 fmt.Fprintln(w, "}") 210 211 fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}") 212 213 // generate op string method 214 fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }") 215 216 // generate registers 217 for _, a := range archs { 218 if a.generic { 219 continue 220 } 221 fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name) 222 for i, r := range a.regnames { 223 fmt.Fprintf(w, " {%d, \"%s\"},\n", i, r) 224 } 225 fmt.Fprintln(w, "}") 226 } 227 228 // gofmt result 229 b := w.Bytes() 230 var err error 231 b, err = format.Source(b) 232 if err != nil { 233 fmt.Printf("%s\n", w.Bytes()) 234 panic(err) 235 } 236 237 err = ioutil.WriteFile("../opGen.go", b, 0666) 238 if err != nil { 239 log.Fatalf("can't write output: %v\n", err) 240 } 241 242 // Check that the arch genfile handles all the arch-specific opcodes. 243 // This is very much a hack, but it is better than nothing. 244 for _, a := range archs { 245 if a.genfile == "" { 246 continue 247 } 248 249 src, err := ioutil.ReadFile(a.genfile) 250 if err != nil { 251 log.Fatalf("can't read %s: %v", a.genfile, err) 252 } 253 254 for _, v := range a.ops { 255 pattern := fmt.Sprintf("\\Wssa[.]Op%s%s\\W", a.name, v.name) 256 match, err := regexp.Match(pattern, src) 257 if err != nil { 258 log.Fatalf("bad opcode regexp %s: %v", pattern, err) 259 } 260 if !match { 261 log.Fatalf("Op%s%s has no code generation in %s", a.name, v.name, a.genfile) 262 } 263 } 264 } 265 } 266 267 // Name returns the name of the architecture for use in Op* and Block* enumerations. 268 func (a arch) Name() string { 269 s := a.name 270 if s == "generic" { 271 s = "" 272 } 273 return s 274 } 275 276 func genLower() { 277 for _, a := range archs { 278 genRules(a) 279 } 280 } 281 282 // countRegs returns the number of set bits in the register mask. 283 func countRegs(r regMask) int { 284 n := 0 285 for r != 0 { 286 n += int(r & 1) 287 r >>= 1 288 } 289 return n 290 } 291 292 // for sorting a pair of integers by key 293 type intPair struct { 294 key, val int 295 } 296 type byKey []intPair 297 298 func (a byKey) Len() int { return len(a) } 299 func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 300 func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }