github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 // prefer v and v.Args[0] to 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 } 159 if a.name == "generic" { 160 fmt.Fprintln(w, "generic:true,") 161 fmt.Fprintln(w, "},") // close op 162 // generic ops have no reg info or asm 163 continue 164 } 165 if v.asm != "" { 166 fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm) 167 } 168 fmt.Fprintln(w, "reg:regInfo{") 169 170 // Compute input allocation order. We allocate from the 171 // most to the least constrained input. This order guarantees 172 // that we will always be able to find a register. 173 var s []intPair 174 for i, r := range v.reg.inputs { 175 if r != 0 { 176 s = append(s, intPair{countRegs(r), i}) 177 } 178 } 179 if len(s) > 0 { 180 sort.Sort(byKey(s)) 181 fmt.Fprintln(w, "inputs: []inputInfo{") 182 for _, p := range s { 183 r := v.reg.inputs[p.val] 184 fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r)) 185 } 186 fmt.Fprintln(w, "},") 187 } 188 if v.reg.clobbers > 0 { 189 fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers)) 190 } 191 // reg outputs 192 if len(v.reg.outputs) > 0 { 193 fmt.Fprintln(w, "outputs: []regMask{") 194 for _, r := range v.reg.outputs { 195 fmt.Fprintf(w, "%d,%s\n", r, a.regMaskComment(r)) 196 } 197 fmt.Fprintln(w, "},") 198 } 199 fmt.Fprintln(w, "},") // close reg info 200 fmt.Fprintln(w, "},") // close op 201 } 202 } 203 fmt.Fprintln(w, "}") 204 205 fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}") 206 207 // generate op string method 208 fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }") 209 210 // generate registers 211 for _, a := range archs { 212 if a.generic { 213 continue 214 } 215 fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name) 216 for i, r := range a.regnames { 217 fmt.Fprintf(w, " {%d, \"%s\"},\n", i, r) 218 } 219 fmt.Fprintln(w, "}") 220 } 221 222 // gofmt result 223 b := w.Bytes() 224 var err error 225 b, err = format.Source(b) 226 if err != nil { 227 fmt.Printf("%s\n", w.Bytes()) 228 panic(err) 229 } 230 231 err = ioutil.WriteFile("../opGen.go", b, 0666) 232 if err != nil { 233 log.Fatalf("can't write output: %v\n", err) 234 } 235 236 // Check that the arch genfile handles all the arch-specific opcodes. 237 // This is very much a hack, but it is better than nothing. 238 for _, a := range archs { 239 if a.genfile == "" { 240 continue 241 } 242 243 src, err := ioutil.ReadFile(a.genfile) 244 if err != nil { 245 log.Fatalf("can't read %s: %v", a.genfile, err) 246 } 247 248 for _, v := range a.ops { 249 pattern := fmt.Sprintf("\\Wssa[.]Op%s%s\\W", a.name, v.name) 250 match, err := regexp.Match(pattern, src) 251 if err != nil { 252 log.Fatalf("bad opcode regexp %s: %v", pattern, err) 253 } 254 if !match { 255 log.Fatalf("Op%s%s has no code generation in %s", a.name, v.name, a.genfile) 256 } 257 } 258 } 259 } 260 261 // Name returns the name of the architecture for use in Op* and Block* enumerations. 262 func (a arch) Name() string { 263 s := a.name 264 if s == "generic" { 265 s = "" 266 } 267 return s 268 } 269 270 func genLower() { 271 for _, a := range archs { 272 genRules(a) 273 } 274 } 275 276 // countRegs returns the number of set bits in the register mask. 277 func countRegs(r regMask) int { 278 n := 0 279 for r != 0 { 280 n += int(r & 1) 281 r >>= 1 282 } 283 return n 284 } 285 286 // for sorting a pair of integers by key 287 type intPair struct { 288 key, val int 289 } 290 type byKey []intPair 291 292 func (a byKey) Len() int { return len(a) } 293 func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 294 func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }