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 }