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