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