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