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