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