Source file src/cmd/compile/internal/ssa/_gen/main.go

     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  // The gen command generates Go code (in the parent directory) for all
     6  // the architecture-specific opcodes, blocks, and rewrites.
     7  package main
     8  
     9  import (
    10  	"bytes"
    11  	"flag"
    12  	"fmt"
    13  	"go/format"
    14  	"log"
    15  	"math/bits"
    16  	"os"
    17  	"path"
    18  	"regexp"
    19  	"runtime"
    20  	"runtime/pprof"
    21  	"runtime/trace"
    22  	"slices"
    23  	"sort"
    24  	"strings"
    25  	"sync"
    26  )
    27  
    28  // TODO: capitalize these types, so that we can more easily tell variable names
    29  // apart from type names, and avoid awkward func parameters like "arch arch".
    30  
    31  type arch struct {
    32  	name               string
    33  	pkg                string // obj package to import for this arch.
    34  	genfile            string // source file containing opcode code generation.
    35  	genSIMDfile        string // source file containing opcode code generation for SIMD.
    36  	ops                []opData
    37  	blocks             []blockData
    38  	regnames           []string
    39  	ParamIntRegNames   string
    40  	ParamFloatRegNames string
    41  	gpregmask          regMask
    42  	fpregmask          regMask
    43  	fp32regmask        regMask
    44  	fp64regmask        regMask
    45  	simdregmask        regMask
    46  	specialregmask     regMask
    47  	framepointerreg    int8
    48  	linkreg            int8
    49  	generic            bool
    50  	imports            []string
    51  }
    52  
    53  type opData struct {
    54  	name              string
    55  	reg               regInfo
    56  	asm               string
    57  	typ               string // default result type
    58  	aux               string
    59  	rematerializeable bool
    60  	argLength         int32  // number of arguments, if -1, then this operation has a variable number of arguments
    61  	commutative       bool   // this operation is commutative on its first 2 arguments (e.g. addition)
    62  	resultInArg0      bool   // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
    63  	resultNotInArgs   bool   // outputs must not be allocated to the same registers as inputs
    64  	clobberFlags      bool   // this op clobbers flags register
    65  	needIntTemp       bool   // need a temporary free integer register
    66  	call              bool   // is a function call
    67  	tailCall          bool   // is a tail call
    68  	nilCheck          bool   // this op is a nil check on arg0
    69  	faultOnNilArg0    bool   // this op will fault if arg0 is nil (and aux encodes a small offset)
    70  	faultOnNilArg1    bool   // this op will fault if arg1 is nil (and aux encodes a small offset)
    71  	hasSideEffects    bool   // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
    72  	zeroWidth         bool   // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width.
    73  	unsafePoint       bool   // this op is an unsafe point, i.e. not safe for async preemption
    74  	fixedReg          bool   // this op will be assigned a fixed register
    75  	earlyOk           bool   // executing this op in an earlier block is ok
    76  	addrSinkArg0      bool   // the address in arg0 does not propagate to the result
    77  	addrSinkArg1      bool   // the address in arg1 does not propagate to the result
    78  	symEffect         string // effect this op has on symbol in aux
    79  	scale             uint8  // amd64/386 indexed load scale
    80  }
    81  
    82  type blockData struct {
    83  	name     string // the suffix for this block ("EQ", "LT", etc.)
    84  	controls int    // the number of control values this type of block requires
    85  	aux      string // the type of the Aux/AuxInt value, if any
    86  }
    87  
    88  type regInfo struct {
    89  	// inputs[i] encodes the set of registers allowed for the i'th input.
    90  	// Inputs that don't use registers (flags, memory, etc.) should be 0.
    91  	inputs []regMask
    92  	// clobbers encodes the set of registers that are overwritten by
    93  	// the instruction (other than the output registers).
    94  	clobbers regMask
    95  	// Instruction clobbers the register containing input 0.
    96  	clobbersArg0 bool
    97  	// Instruction clobbers the register containing input 1.
    98  	clobbersArg1 bool
    99  	// outputs[i] encodes the set of registers allowed for the i'th output.
   100  	outputs []regMask
   101  }
   102  
   103  type regMask struct {
   104  	v1, v2 uint64
   105  }
   106  
   107  func regMaskAt(i uint) regMask {
   108  	if i < 64 {
   109  		return regMask{v1: 1 << i}
   110  	}
   111  	return regMask{v2: 1 << (i - 64)}
   112  }
   113  
   114  func (r regMask) empty() bool {
   115  	return r.v1 == 0 && r.v2 == 0
   116  }
   117  
   118  func (r regMask) hasReg(i uint) bool {
   119  	if i < 64 {
   120  		return (r.v1>>i)&1 != 0
   121  	}
   122  	return (r.v2>>(i-64))&1 != 0
   123  }
   124  
   125  func (r regMask) addReg(i uint) regMask {
   126  	if i < 64 {
   127  		return regMask{r.v1 | 1<<i, r.v2}
   128  	}
   129  	return regMask{r.v1, r.v2 | 1<<(i-64)}
   130  }
   131  
   132  func (r regMask) union(s regMask) regMask {
   133  	return regMask{r.v1 | s.v1, r.v2 | s.v2}
   134  }
   135  
   136  func (r regMask) minus(s regMask) regMask {
   137  	return regMask{r.v1 &^ s.v1, r.v2 &^ s.v2}
   138  }
   139  
   140  func (a arch) regMaskComment(r regMask) string {
   141  	var buf strings.Builder
   142  	for i := uint(0); i < uint(len(a.regnames)); i++ {
   143  		if r.hasReg(i) {
   144  			if buf.Len() == 0 {
   145  				buf.WriteString(" //")
   146  			}
   147  			buf.WriteString(" ")
   148  			buf.WriteString(a.regnames[i])
   149  		}
   150  	}
   151  	return buf.String()
   152  }
   153  
   154  var archs []arch
   155  
   156  var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
   157  var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
   158  var tracefile = flag.String("trace", "", "write trace to `file`")
   159  var outDir = flag.String("outdir", "..", "directory in which to write generated files")
   160  
   161  func main() {
   162  	flag.Parse()
   163  	if *cpuprofile != "" {
   164  		f, err := os.Create(*cpuprofile)
   165  		if err != nil {
   166  			log.Fatal("could not create CPU profile: ", err)
   167  		}
   168  		defer f.Close()
   169  		if err := pprof.StartCPUProfile(f); err != nil {
   170  			log.Fatal("could not start CPU profile: ", err)
   171  		}
   172  		defer pprof.StopCPUProfile()
   173  	}
   174  	if *tracefile != "" {
   175  		f, err := os.Create(*tracefile)
   176  		if err != nil {
   177  			log.Fatalf("failed to create trace output file: %v", err)
   178  		}
   179  		defer func() {
   180  			if err := f.Close(); err != nil {
   181  				log.Fatalf("failed to close trace file: %v", err)
   182  			}
   183  		}()
   184  
   185  		if err := trace.Start(f); err != nil {
   186  			log.Fatalf("failed to start trace: %v", err)
   187  		}
   188  		defer trace.Stop()
   189  	}
   190  
   191  	if *outDir != ".." {
   192  		err := os.MkdirAll(*outDir, 0755)
   193  		if err != nil {
   194  			log.Fatalf("failed to create output directory: %v", err)
   195  		}
   196  	}
   197  
   198  	slices.SortFunc(archs, func(a, b arch) int {
   199  		return strings.Compare(a.name, b.name)
   200  	})
   201  
   202  	// The generate tasks are run concurrently, since they are CPU-intensive
   203  	// that can easily make use of many cores on a machine.
   204  	//
   205  	// Note that there is no limit on the concurrency at the moment. On a
   206  	// four-core laptop at the time of writing, peak RSS usually reaches
   207  	// ~200MiB, which seems doable by practically any machine nowadays. If
   208  	// that stops being the case, we can cap this func to a fixed number of
   209  	// architectures being generated at once.
   210  
   211  	tasks := []func(){
   212  		genOp,
   213  		genAllocators,
   214  	}
   215  	for _, a := range archs {
   216  		a := a // the funcs are ran concurrently at a later time
   217  		tasks = append(tasks, func() {
   218  			genRules(a)
   219  			genSplitLoadRules(a)
   220  			genLateLowerRules(a)
   221  		})
   222  	}
   223  	var wg sync.WaitGroup
   224  	for _, task := range tasks {
   225  		wg.Add(1)
   226  		go func() {
   227  			task()
   228  			wg.Done()
   229  		}()
   230  	}
   231  	wg.Wait()
   232  
   233  	if *memprofile != "" {
   234  		f, err := os.Create(*memprofile)
   235  		if err != nil {
   236  			log.Fatal("could not create memory profile: ", err)
   237  		}
   238  		defer f.Close()
   239  		runtime.GC() // get up-to-date statistics
   240  		if err := pprof.WriteHeapProfile(f); err != nil {
   241  			log.Fatal("could not write memory profile: ", err)
   242  		}
   243  	}
   244  }
   245  
   246  func outFile(file string) string {
   247  	return *outDir + "/" + file
   248  }
   249  
   250  func genOp() {
   251  	w := new(bytes.Buffer)
   252  	fmt.Fprintf(w, "// Code generated from _gen/*Ops.go using 'go generate'; DO NOT EDIT.\n")
   253  	fmt.Fprintln(w)
   254  	fmt.Fprintln(w, "package ssa")
   255  
   256  	fmt.Fprintln(w, "import (")
   257  	fmt.Fprintln(w, "\"cmd/internal/obj\"")
   258  	for _, a := range archs {
   259  		if a.pkg != "" {
   260  			fmt.Fprintf(w, "%q\n", a.pkg)
   261  		}
   262  	}
   263  	fmt.Fprintln(w, ")")
   264  
   265  	// generate Block* declarations
   266  	fmt.Fprintln(w, "const (")
   267  	fmt.Fprintln(w, "BlockInvalid BlockKind = iota")
   268  	for _, a := range archs {
   269  		fmt.Fprintln(w)
   270  		for _, d := range a.blocks {
   271  			fmt.Fprintf(w, "Block%s%s\n", a.Name(), d.name)
   272  		}
   273  	}
   274  	fmt.Fprintln(w, ")")
   275  
   276  	// generate block kind string method
   277  	fmt.Fprintln(w, "var blockString = [...]string{")
   278  	fmt.Fprintln(w, "BlockInvalid:\"BlockInvalid\",")
   279  	for _, a := range archs {
   280  		fmt.Fprintln(w)
   281  		for _, b := range a.blocks {
   282  			fmt.Fprintf(w, "Block%s%s:\"%s\",\n", a.Name(), b.name, b.name)
   283  		}
   284  	}
   285  	fmt.Fprintln(w, "}")
   286  	fmt.Fprintln(w, "func (k BlockKind) String() string {return blockString[k]}")
   287  
   288  	// generate block kind auxint method
   289  	fmt.Fprintln(w, "func (k BlockKind) AuxIntType() string {")
   290  	fmt.Fprintln(w, "switch k {")
   291  	for _, a := range archs {
   292  		for _, b := range a.blocks {
   293  			if b.auxIntType() == "invalid" {
   294  				continue
   295  			}
   296  			fmt.Fprintf(w, "case Block%s%s: return \"%s\"\n", a.Name(), b.name, b.auxIntType())
   297  		}
   298  	}
   299  	fmt.Fprintln(w, "}")
   300  	fmt.Fprintln(w, "return \"\"")
   301  	fmt.Fprintln(w, "}")
   302  
   303  	// generate Op* declarations
   304  	fmt.Fprintln(w, "const (")
   305  	fmt.Fprintln(w, "OpInvalid Op = iota") // make sure OpInvalid is 0.
   306  	for _, a := range archs {
   307  		fmt.Fprintln(w)
   308  		for _, v := range a.ops {
   309  			if v.name == "Invalid" {
   310  				continue
   311  			}
   312  			fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name)
   313  		}
   314  	}
   315  	fmt.Fprintln(w, ")")
   316  
   317  	// generate OpInfo table
   318  	fmt.Fprintln(w, "var opcodeTable = [...]opInfo{")
   319  	fmt.Fprintln(w, " { name: \"OpInvalid\" },")
   320  	for _, a := range archs {
   321  		fmt.Fprintln(w)
   322  
   323  		pkg := path.Base(a.pkg)
   324  		for _, v := range a.ops {
   325  			if v.name == "Invalid" {
   326  				continue
   327  			}
   328  			fmt.Fprintln(w, "{")
   329  			fmt.Fprintf(w, "name:\"%s\",\n", v.name)
   330  
   331  			// flags
   332  			if v.aux != "" {
   333  				fmt.Fprintf(w, "auxType: aux%s,\n", v.aux)
   334  			}
   335  			fmt.Fprintf(w, "argLen: %d,\n", v.argLength)
   336  
   337  			if v.rematerializeable {
   338  				if !v.reg.clobbers.empty() || v.reg.clobbersArg0 || v.reg.clobbersArg1 {
   339  					log.Fatalf("%s is rematerializeable and clobbers registers", v.name)
   340  				}
   341  				if v.clobberFlags {
   342  					log.Fatalf("%s is rematerializeable and clobbers flags", v.name)
   343  				}
   344  				fmt.Fprintln(w, "rematerializeable: true,")
   345  			}
   346  			if v.commutative {
   347  				fmt.Fprintln(w, "commutative: true,")
   348  			}
   349  			if v.resultInArg0 {
   350  				fmt.Fprintln(w, "resultInArg0: true,")
   351  				// OpConvert's register mask is selected dynamically,
   352  				// so don't try to check it in the static table.
   353  				if v.name != "Convert" && v.reg.inputs[0] != v.reg.outputs[0] {
   354  					log.Fatalf("%s: input[0] and output[0] must use the same registers for %s", a.name, v.name)
   355  				}
   356  				if v.name != "Convert" && v.commutative && v.reg.inputs[1] != v.reg.outputs[0] {
   357  					log.Fatalf("%s: input[1] and output[0] must use the same registers for %s", a.name, v.name)
   358  				}
   359  			}
   360  			if v.resultNotInArgs {
   361  				fmt.Fprintln(w, "resultNotInArgs: true,")
   362  			}
   363  			if v.clobberFlags {
   364  				fmt.Fprintln(w, "clobberFlags: true,")
   365  			}
   366  			if v.needIntTemp {
   367  				fmt.Fprintln(w, "needIntTemp: true,")
   368  			}
   369  			if v.call {
   370  				fmt.Fprintln(w, "call: true,")
   371  			}
   372  			if v.tailCall {
   373  				fmt.Fprintln(w, "tailCall: true,")
   374  			}
   375  			if v.nilCheck {
   376  				fmt.Fprintln(w, "nilCheck: true,")
   377  			}
   378  			if v.faultOnNilArg0 {
   379  				fmt.Fprintln(w, "faultOnNilArg0: true,")
   380  				if v.aux != "Sym" && v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "SizeAndAlign" && v.aux != "" {
   381  					log.Fatalf("faultOnNilArg0 with aux %s not allowed", v.aux)
   382  				}
   383  			}
   384  			if v.faultOnNilArg1 {
   385  				fmt.Fprintln(w, "faultOnNilArg1: true,")
   386  				if v.aux != "Sym" && v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "SizeAndAlign" && v.aux != "" {
   387  					log.Fatalf("faultOnNilArg1 with aux %s not allowed", v.aux)
   388  				}
   389  			}
   390  			if v.hasSideEffects {
   391  				fmt.Fprintln(w, "hasSideEffects: true,")
   392  			}
   393  			if v.zeroWidth {
   394  				fmt.Fprintln(w, "zeroWidth: true,")
   395  			}
   396  			if v.fixedReg {
   397  				fmt.Fprintln(w, "fixedReg: true,")
   398  			}
   399  			if v.earlyOk {
   400  				fmt.Fprintln(w, "earlyOk: true,")
   401  			}
   402  			if v.addrSinkArg0 {
   403  				fmt.Fprintln(w, "addrSinkArg0: true,")
   404  			}
   405  			if v.addrSinkArg1 {
   406  				fmt.Fprintln(w, "addrSinkArg1: true,")
   407  			}
   408  			if v.unsafePoint {
   409  				fmt.Fprintln(w, "unsafePoint: true,")
   410  			}
   411  			needEffect := strings.HasPrefix(v.aux, "Sym")
   412  			if v.symEffect != "" {
   413  				if !needEffect {
   414  					log.Fatalf("symEffect with aux %s not allowed", v.aux)
   415  				}
   416  				fmt.Fprintf(w, "symEffect: Sym%s,\n", strings.ReplaceAll(v.symEffect, ",", "|Sym"))
   417  			} else if needEffect {
   418  				log.Fatalf("symEffect needed for aux %s", v.aux)
   419  			}
   420  			if a.name == "generic" {
   421  				fmt.Fprintln(w, "generic:true,")
   422  				fmt.Fprintln(w, "},") // close op
   423  				// generic ops have no reg info or asm
   424  				continue
   425  			}
   426  			if v.asm != "" {
   427  				fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm)
   428  			}
   429  			if v.scale != 0 {
   430  				fmt.Fprintf(w, "scale: %d,\n", v.scale)
   431  			}
   432  			fmt.Fprintln(w, "reg:regInfo{")
   433  
   434  			// Compute input allocation order. We allocate from the
   435  			// most to the least constrained input. This order guarantees
   436  			// that we will always be able to find a register.
   437  			var s []intPair
   438  			for i, r := range v.reg.inputs {
   439  				if !r.empty() {
   440  					s = append(s, intPair{countRegs(r), i})
   441  				}
   442  			}
   443  			if len(s) > 0 {
   444  				sort.Sort(byKey(s))
   445  				fmt.Fprintln(w, "inputs: []inputInfo{")
   446  				for _, p := range s {
   447  					r := v.reg.inputs[p.val]
   448  					fmt.Fprintf(w, "{%d,regMask{v1: %d, v2: %d}},%s\n", p.val, r.v1, r.v2, a.regMaskComment(r))
   449  				}
   450  				fmt.Fprintln(w, "},")
   451  			}
   452  
   453  			if !v.reg.clobbers.empty() {
   454  				fmt.Fprintf(w, "clobbers: regMask{v1: %d, v2: %d},%s\n", v.reg.clobbers.v1, v.reg.clobbers.v2, a.regMaskComment(v.reg.clobbers))
   455  			}
   456  			if v.reg.clobbersArg0 {
   457  				fmt.Fprintf(w, "clobbersArg0: true,\n")
   458  			}
   459  			if v.reg.clobbersArg1 {
   460  				fmt.Fprintf(w, "clobbersArg1: true,\n")
   461  			}
   462  
   463  			// reg outputs
   464  			s = s[:0]
   465  			for i, r := range v.reg.outputs {
   466  				s = append(s, intPair{countRegs(r), i})
   467  			}
   468  			if len(s) > 0 {
   469  				sort.Sort(byKey(s))
   470  				fmt.Fprintln(w, "outputs: []outputInfo{")
   471  				for _, p := range s {
   472  					r := v.reg.outputs[p.val]
   473  					fmt.Fprintf(w, "{%d,regMask{v1: %d, v2: %d}},%s\n", p.val, r.v1, r.v2, a.regMaskComment(r))
   474  				}
   475  				fmt.Fprintln(w, "},")
   476  			}
   477  			fmt.Fprintln(w, "},") // close reg info
   478  			fmt.Fprintln(w, "},") // close op
   479  		}
   480  	}
   481  	fmt.Fprintln(w, "}")
   482  
   483  	fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}")
   484  	fmt.Fprintln(w, "func (o Op) Scale() int16 {return int16(opcodeTable[o].scale)}")
   485  
   486  	// generate op string method
   487  	fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
   488  
   489  	fmt.Fprintln(w, "func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }")
   490  	fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }")
   491  	fmt.Fprintln(w, "func (o Op) IsTailCall() bool { return opcodeTable[o].tailCall }")
   492  	fmt.Fprintln(w, "func (o Op) HasSideEffects() bool { return opcodeTable[o].hasSideEffects }")
   493  	fmt.Fprintln(w, "func (o Op) UnsafePoint() bool { return opcodeTable[o].unsafePoint }")
   494  	fmt.Fprintln(w, "func (o Op) ResultInArg0() bool { return opcodeTable[o].resultInArg0 }")
   495  
   496  	// generate registers
   497  	for _, a := range archs {
   498  		if a.generic {
   499  			continue
   500  		}
   501  		fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name)
   502  		num := map[string]int8{}
   503  		for i, r := range a.regnames {
   504  			num[r] = int8(i)
   505  			pkg := a.pkg[len("cmd/internal/obj/"):]
   506  			var objname string // name in cmd/internal/obj/$ARCH
   507  			switch r {
   508  			case "SB":
   509  				// SB isn't a real register.  cmd/internal/obj expects 0 in this case.
   510  				objname = "0"
   511  			case "SP":
   512  				objname = pkg + ".REGSP"
   513  			case "g":
   514  				objname = pkg + ".REGG"
   515  			case "ZERO":
   516  				objname = pkg + ".REGZERO"
   517  			default:
   518  				objname = pkg + ".REG_" + r
   519  			}
   520  			fmt.Fprintf(w, "  {%d, %s, \"%s\"},\n", i, objname, r)
   521  		}
   522  		parameterRegisterList := func(paramNamesString string) []int8 {
   523  			paramNamesString = strings.TrimSpace(paramNamesString)
   524  			if paramNamesString == "" {
   525  				return nil
   526  			}
   527  			paramNames := strings.Split(paramNamesString, " ")
   528  			var paramRegs []int8
   529  			for _, regName := range paramNames {
   530  				if regName == "" {
   531  					// forgive extra spaces
   532  					continue
   533  				}
   534  				if regNum, ok := num[regName]; ok {
   535  					paramRegs = append(paramRegs, regNum)
   536  					delete(num, regName)
   537  				} else {
   538  					log.Fatalf("parameter register %s for architecture %s not a register name (or repeated in parameter list)", regName, a.name)
   539  				}
   540  			}
   541  			return paramRegs
   542  		}
   543  
   544  		paramIntRegs := parameterRegisterList(a.ParamIntRegNames)
   545  		paramFloatRegs := parameterRegisterList(a.ParamFloatRegNames)
   546  
   547  		fmt.Fprintln(w, "}")
   548  		fmt.Fprintf(w, "var paramIntReg%s = %#v\n", a.name, paramIntRegs)
   549  		fmt.Fprintf(w, "var paramFloatReg%s = %#v\n", a.name, paramFloatRegs)
   550  		fmt.Fprintf(w, "var gpRegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.gpregmask.v1, a.gpregmask.v2)
   551  		fmt.Fprintf(w, "var fpRegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.fpregmask.v1, a.fpregmask.v2)
   552  		if !a.fp32regmask.empty() {
   553  			fmt.Fprintf(w, "var fp32RegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.fp32regmask.v1, a.fp32regmask.v2)
   554  		}
   555  		if !a.fp64regmask.empty() {
   556  			fmt.Fprintf(w, "var fp64RegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.fp64regmask.v1, a.fp64regmask.v2)
   557  		}
   558  		if !a.simdregmask.empty() {
   559  			fmt.Fprintf(w, "var simdRegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.simdregmask.v1, a.simdregmask.v2)
   560  		}
   561  		fmt.Fprintf(w, "var specialRegMask%s = regMask{v1: %d, v2: %d}\n", a.name, a.specialregmask.v1, a.specialregmask.v2)
   562  		fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg)
   563  		fmt.Fprintf(w, "var linkReg%s = int8(%d)\n", a.name, a.linkreg)
   564  	}
   565  
   566  	// gofmt result
   567  	b := w.Bytes()
   568  	var err error
   569  	b, err = format.Source(b)
   570  	if err != nil {
   571  		fmt.Printf("%s\n", w.Bytes())
   572  		panic(err)
   573  	}
   574  
   575  	if err := os.WriteFile(outFile("opGen.go"), b, 0666); err != nil {
   576  		log.Fatalf("can't write output: %v\n", err)
   577  	}
   578  
   579  	// Check that the arch genfile handles all the arch-specific opcodes.
   580  	// This is very much a hack, but it is better than nothing.
   581  	//
   582  	// Do a single regexp pass to record all ops being handled in a map, and
   583  	// then compare that with the ops list. This is much faster than one
   584  	// regexp pass per opcode.
   585  	for _, a := range archs {
   586  		if a.genfile == "" {
   587  			continue
   588  		}
   589  
   590  		pattern := fmt.Sprintf(`\Wssa\.Op%s([a-zA-Z0-9_]+)\W`, a.name)
   591  		rxOp, err := regexp.Compile(pattern)
   592  		if err != nil {
   593  			log.Fatalf("bad opcode regexp %s: %v", pattern, err)
   594  		}
   595  
   596  		src, err := os.ReadFile(a.genfile)
   597  		if err != nil {
   598  			log.Fatalf("can't read %s: %v", a.genfile, err)
   599  		}
   600  		// Append the file of simd operations, too
   601  		if a.genSIMDfile != "" {
   602  			simdSrc, err := os.ReadFile(a.genSIMDfile)
   603  			if err != nil {
   604  				log.Fatalf("can't read %s: %v", a.genSIMDfile, err)
   605  			}
   606  			src = append(src, simdSrc...)
   607  		}
   608  
   609  		seen := make(map[string]bool, len(a.ops))
   610  		for _, m := range rxOp.FindAllSubmatch(src, -1) {
   611  			seen[string(m[1])] = true
   612  		}
   613  		for _, op := range a.ops {
   614  			if !seen[op.name] {
   615  				log.Fatalf("Op%s%s has no code generation in %s", a.name, op.name, a.genfile)
   616  			}
   617  		}
   618  	}
   619  }
   620  
   621  // Name returns the name of the architecture for use in Op* and Block* enumerations.
   622  func (a arch) Name() string {
   623  	s := a.name
   624  	if s == "generic" {
   625  		s = ""
   626  	}
   627  	return s
   628  }
   629  
   630  // countRegs returns the number of set bits in the register mask.
   631  func countRegs(r regMask) int {
   632  	return bits.OnesCount64(r.v1) + bits.OnesCount64(r.v2)
   633  }
   634  
   635  // for sorting a pair of integers by key
   636  type intPair struct {
   637  	key, val int
   638  }
   639  type byKey []intPair
   640  
   641  func (a byKey) Len() int           { return len(a) }
   642  func (a byKey) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   643  func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }
   644  

View as plain text