...

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

View as plain text