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