...

Source file src/golang.org/x/arch/ppc64/ppc64map/map.go

Documentation: golang.org/x/arch/ppc64/ppc64map

     1  // Copyright 2014 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  // ppc64map constructs the ppc64 opcode map from the instruction set CSV file.
     6  //
     7  // Usage:
     8  //
     9  //	ppc64map [-fmt=format] ppc64.csv
    10  //
    11  // The known output formats are:
    12  //
    13  //	text (default) - print decoding tree in text form
    14  //	decoder - print decoding tables for the ppc64asm package
    15  //	encoder - generate a self-contained file which can be used to encode
    16  //		  go obj.Progs into machine code
    17  //	asm - generate a gnu asm file which can be compiled by gcc containing
    18  //	      all opcodes discovered in ppc64.csv using macro friendly arguments.
    19  package main
    20  
    21  import (
    22  	"bytes"
    23  	"encoding/csv"
    24  	"flag"
    25  	"fmt"
    26  	gofmt "go/format"
    27  	asm "golang.org/x/arch/ppc64/ppc64asm"
    28  	"log"
    29  	"math/bits"
    30  	"os"
    31  	"regexp"
    32  	"sort"
    33  	"strconv"
    34  	"strings"
    35  	"text/template"
    36  )
    37  
    38  var format = flag.String("fmt", "text", "output format: text, decoder, asm")
    39  var debug = flag.Bool("debug", false, "enable debugging output")
    40  
    41  var inputFile string
    42  
    43  type isaversion uint32
    44  
    45  const (
    46  	// Sort as supersets of each other. Generally speaking, each newer ISA
    47  	// supports a superset of the previous instructions with a few exceptions
    48  	// throughout.
    49  	ISA_P1 isaversion = iota
    50  	ISA_P2
    51  	ISA_PPC
    52  	ISA_V200
    53  	ISA_V201
    54  	ISA_V202
    55  	ISA_V203
    56  	ISA_V205
    57  	ISA_V206
    58  	ISA_V207
    59  	ISA_V30
    60  	ISA_V30B
    61  	ISA_V30C
    62  	ISA_V31
    63  	ISA_V31B
    64  )
    65  
    66  var isaToISA = map[string]isaversion{
    67  	"P1":    ISA_P1,
    68  	"P2":    ISA_P2,
    69  	"PPC":   ISA_PPC,
    70  	"v2.00": ISA_V200,
    71  	"v2.01": ISA_V201,
    72  	"v2.02": ISA_V202,
    73  	"v2.03": ISA_V203,
    74  	"v2.05": ISA_V205,
    75  	"v2.06": ISA_V206,
    76  	"v2.07": ISA_V207,
    77  	"v3.0":  ISA_V30,
    78  	"v3.0B": ISA_V30B,
    79  	"v3.0C": ISA_V30C,
    80  	"v3.1":  ISA_V31,
    81  	"v3.1B": ISA_V31B,
    82  }
    83  
    84  func usage() {
    85  	fmt.Fprintf(os.Stderr, "usage: ppc64map [-fmt=format] ppc64.csv\n")
    86  	os.Exit(2)
    87  }
    88  
    89  func main() {
    90  	log.SetFlags(0)
    91  	log.SetPrefix("ppc64map: ")
    92  
    93  	flag.Usage = usage
    94  	flag.Parse()
    95  	if flag.NArg() != 1 {
    96  		usage()
    97  	}
    98  
    99  	inputFile = flag.Arg(0)
   100  
   101  	var print func(*Prog)
   102  	switch *format {
   103  	default:
   104  		log.Fatalf("unknown output format %q", *format)
   105  	case "text":
   106  		print = printText
   107  	case "decoder":
   108  		print = printDecoder
   109  	case "asm":
   110  		print = printASM
   111  	case "encoder":
   112  		print = printEncoder
   113  	}
   114  
   115  	p, err := readCSV(flag.Arg(0))
   116  	if err != nil {
   117  		log.Fatal(err)
   118  	}
   119  	log.Printf("Parsed %d instruction forms.", len(p.Insts))
   120  	print(p)
   121  }
   122  
   123  // readCSV reads the CSV file and returns the corresponding Prog.
   124  // It may print details about problems to standard error using the log package.
   125  func readCSV(file string) (*Prog, error) {
   126  	// Read input.
   127  	// Skip leading blank and # comment lines.
   128  	f, err := os.Open(file)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	csvReader := csv.NewReader(f)
   133  	csvReader.Comment = '#'
   134  	table, err := csvReader.ReadAll()
   135  	if err != nil {
   136  		return nil, fmt.Errorf("parsing %s: %v", file, err)
   137  	}
   138  	if len(table) == 0 {
   139  		return nil, fmt.Errorf("empty csv input")
   140  	}
   141  	if len(table[0]) < 4 {
   142  		return nil, fmt.Errorf("csv too narrow: need at least four columns")
   143  	}
   144  
   145  	p := &Prog{}
   146  	for _, row := range table {
   147  		add(p, row[0], row[1], row[2], row[3])
   148  	}
   149  	return p, nil
   150  }
   151  
   152  type Prog struct {
   153  	Insts     []Inst
   154  	OpRanges  map[string]string
   155  	nextOrder int // Next position value (used for Insts[x].order)
   156  }
   157  
   158  type Field struct {
   159  	Name          string
   160  	BitFields     asm.BitFields
   161  	BitFieldNames []string
   162  	Type          asm.ArgType
   163  	Shift         uint8
   164  }
   165  
   166  func (f Field) String() string {
   167  	return fmt.Sprintf("%v(%s%v)", f.Type, f.Name, f.BitFields)
   168  }
   169  
   170  type Inst struct {
   171  	Text      string
   172  	Encoding  string
   173  	Op        string
   174  	Mask      uint32
   175  	Value     uint32
   176  	DontCare  uint32
   177  	SMask     uint32 // The opcode Mask of the suffix word
   178  	SValue    uint32 // Likewise for the Value
   179  	SDontCare uint32 // Likewise for the DontCare bits
   180  	Fields    []Field
   181  	Words     int // Number of words instruction encodes to.
   182  	Isa       isaversion
   183  	memOp     bool // Is this a memory operation?
   184  	memOpX    bool // Is this an x-form memory operation?
   185  	memOpSt   bool // Is this a store memory operations?
   186  	order     int  // Position in pp64.csv.
   187  }
   188  
   189  func (i Inst) String() string {
   190  	return fmt.Sprintf("%s (%s) %08x/%08x[%08x] %v (%s)", i.Op, i.Encoding, i.Value, i.Mask, i.DontCare, i.Fields, i.Text)
   191  }
   192  
   193  type Arg struct {
   194  	Name string
   195  	Bits int8
   196  	Offs int8
   197  	// Instruction word position.  0 for single word instructions (all < ISA 3.1 insn)
   198  	// For prefixed instructions, 0 for the prefix word, 1 for the second insn word.
   199  	Word int8
   200  }
   201  
   202  func (a Arg) String() string {
   203  	return fmt.Sprintf("%s[%d:%d]", a.Name, a.Offs, a.Offs+a.Bits-1)
   204  }
   205  
   206  func (a Arg) Maximum() int {
   207  	return 1<<uint8(a.Bits) - 1
   208  }
   209  
   210  func (a Arg) BitMask() uint32 {
   211  	return uint32(a.Maximum()) << a.Shift()
   212  }
   213  
   214  func (a Arg) Shift() uint8 {
   215  	return uint8(32 - a.Offs - a.Bits)
   216  }
   217  
   218  type Args []Arg
   219  
   220  func (as Args) String() string {
   221  	ss := make([]string, len(as))
   222  	for i := range as {
   223  		ss[i] = as[i].String()
   224  	}
   225  	return strings.Join(ss, "|")
   226  }
   227  
   228  func (as Args) Find(name string) int {
   229  	for i := range as {
   230  		if as[i].Name == name {
   231  			return i
   232  		}
   233  	}
   234  	return -1
   235  }
   236  
   237  func (as *Args) Append(a Arg) {
   238  	*as = append(*as, a)
   239  }
   240  
   241  func (as *Args) Delete(i int) {
   242  	*as = append((*as)[:i], (*as)[i+1:]...)
   243  }
   244  
   245  func (as Args) Clone() Args {
   246  	return append(Args{}, as...)
   247  }
   248  
   249  func (a Arg) isDontCare() bool {
   250  	return a.Name[0] == '/' && a.Name == strings.Repeat("/", len(a.Name))
   251  }
   252  
   253  type instArray []Inst
   254  
   255  func (i instArray) Len() int {
   256  	return len(i)
   257  }
   258  
   259  func (i instArray) Swap(j, k int) {
   260  	i[j], i[k] = i[k], i[j]
   261  }
   262  
   263  // Sort by decreasing number of mask bits to ensure extended mnemonics
   264  // are always found first when scanning the table.
   265  func (i instArray) Less(j, k int) bool {
   266  	return bits.OnesCount32(i[j].Mask) > bits.OnesCount32(i[k].Mask)
   267  }
   268  
   269  // Split the string encoding into an Args. The encoding string loosely matches the regex
   270  // (arg@bitpos|)+
   271  func parseFields(encoding, text string, word int8) Args {
   272  	var err error
   273  	var args Args
   274  
   275  	fields := strings.Split(encoding, "|")
   276  
   277  	for i, f := range fields {
   278  		name, off := "", -1
   279  		if f == "" {
   280  			off = 32
   281  			if i == 0 || i != len(fields)-1 {
   282  				fmt.Fprintf(os.Stderr, "%s: wrong %d-th encoding field: %q\n", text, i, f)
   283  				panic("Invalid encoding entry.")
   284  			}
   285  		} else {
   286  			j := strings.Index(f, "@")
   287  			if j < 0 {
   288  				fmt.Fprintf(os.Stderr, "%s: wrong %d-th encoding field: %q\n", text, i, f)
   289  				panic("Invalid encoding entry.")
   290  				continue
   291  			}
   292  			k := strings.Index(f[j+1:], " ")
   293  			if k >= 0 {
   294  				if strings.HasSuffix(f[j+1:], " 31") {
   295  					f = f[:len(f)-3]
   296  				}
   297  			}
   298  			off, err = strconv.Atoi(f[j+1:])
   299  			if err != nil {
   300  				fmt.Fprintf(os.Stderr, "err for: %s has: %s for %s\n", f[:j], err, f[j+1:])
   301  			}
   302  			name = f[:j]
   303  		}
   304  		if len(args) > 0 {
   305  			args[len(args)-1].Bits += int8(off)
   306  		}
   307  		if name != "" {
   308  			arg := Arg{Name: name, Offs: int8(off), Bits: int8(-off), Word: word}
   309  			args.Append(arg)
   310  		}
   311  	}
   312  
   313  	return args
   314  }
   315  
   316  // Compute the Mask (usually Opcode + secondary Opcode bitfields),
   317  // the Value (the expected value under the mask), and
   318  // reserved bits (i.e the // fields which should be set to 0)
   319  func computeMaskValueReserved(args Args, text string) (mask, value, reserved uint32) {
   320  	for i := 0; i < len(args); i++ {
   321  		arg := args[i]
   322  		v, err := strconv.Atoi(arg.Name)
   323  		switch {
   324  		case err == nil: // is a numbered field
   325  			if v < 0 || v > arg.Maximum() {
   326  				fmt.Fprintf(os.Stderr, "%s: field %s value (%d) is out of range (%d-bit)\n", text, arg, v, arg.Bits)
   327  			}
   328  			mask |= arg.BitMask()
   329  			value |= uint32(v) << arg.Shift()
   330  			args.Delete(i)
   331  			i--
   332  		case arg.Name[0] == '/': // is don't care
   333  			if arg.Name != strings.Repeat("/", len(arg.Name)) {
   334  				log.Fatalf("%s: arg %v named like a don't care bit, but it's not", text, arg)
   335  			}
   336  			reserved |= arg.BitMask()
   337  			args.Delete(i)
   338  			i--
   339  		default:
   340  			continue
   341  		}
   342  	}
   343  
   344  	// rename duplicated fields (e.g. 30@0|RS@6|RA@11|sh@16|mb@21|0@27|sh@30|Rc@31|)
   345  	// but only support two duplicated fields
   346  	for i := 1; i < len(args); i++ {
   347  		if args[:i].Find(args[i].Name) >= 0 {
   348  			args[i].Name += "2"
   349  		}
   350  		if args[:i].Find(args[i].Name) >= 0 {
   351  			log.Fatalf("%s: more than one duplicated fields: %s", text, args)
   352  		}
   353  	}
   354  
   355  	// sanity checks
   356  	if mask&reserved != 0 {
   357  		log.Fatalf("%s: mask (%08x) and don't care (%08x) collide", text, mask, reserved)
   358  	}
   359  	if value&^mask != 0 {
   360  		log.Fatalf("%s: value (%08x) out of range of mask (%08x)", text, value, mask)
   361  	}
   362  
   363  	var argMask uint32
   364  	for _, arg := range args {
   365  		if arg.Bits <= 0 || arg.Bits > 32 || arg.Offs > 31 || arg.Offs <= 0 {
   366  			log.Fatalf("%s: arg %v has wrong bit field spec", text, arg)
   367  		}
   368  		if mask&arg.BitMask() != 0 {
   369  			log.Fatalf("%s: mask (%08x) intersect with arg %v", text, mask, arg)
   370  		}
   371  		if argMask&arg.BitMask() != 0 {
   372  			log.Fatalf("%s: arg %v overlap with other args %v", text, arg, args)
   373  		}
   374  		argMask |= arg.BitMask()
   375  	}
   376  	if 1<<32-1 != mask|reserved|argMask {
   377  		log.Fatalf("%s: args %v fail to cover all 32 bits", text, args)
   378  	}
   379  
   380  	return
   381  }
   382  
   383  // Parse a row from the CSV describing the instructions, and place the
   384  // detected instructions into p. One entry may generate multiple intruction
   385  // entries as each extended mnemonic listed in text is treated like a unique
   386  // instruction.
   387  func add(p *Prog, text, mnemonics, encoding, isa string) {
   388  	// Parse encoding, building size and offset of each field.
   389  	// The first field in the encoding is the smallest offset.
   390  	// And note the MSB is bit 0, not bit 31.
   391  	// Example: "31@0|RS@6|RA@11|///@16|26@21|Rc@31|"
   392  	var args, pargs Args
   393  	var pmask, pvalue, presv, resv uint32
   394  	iword := int8(0)
   395  	ispfx := false
   396  
   397  	isaLevel, fnd := isaToISA[isa]
   398  	if !fnd {
   399  		log.Fatalf("%s: ISA level '%s' is unknown\n", text, isa)
   400  		return
   401  	}
   402  
   403  	// Is this a prefixed instruction?
   404  	if encoding[0] == ',' {
   405  		pfields := strings.Split(encoding, ",")[1:]
   406  
   407  		if len(pfields) != 2 {
   408  			log.Fatalf("%s: Prefixed instruction must be 2 words long.\n", text)
   409  			return
   410  		}
   411  		pargs = parseFields(pfields[0], text, iword)
   412  		pmask, pvalue, presv = computeMaskValueReserved(pargs, text)
   413  		// Move to next instruction word
   414  		iword++
   415  		encoding = pfields[1]
   416  		ispfx = true
   417  	}
   418  
   419  	args = parseFields(encoding, text, iword)
   420  	mask, value, dontCare := computeMaskValueReserved(args, text)
   421  
   422  	if ispfx {
   423  		args = append(args, pargs...)
   424  	}
   425  
   426  	// split mnemonics into individual instructions
   427  	// example: "b target_addr (AA=0 LK=0)|ba target_addr (AA=1 LK=0)|bl target_addr (AA=0 LK=1)|bla target_addr (AA=1 LK=1)"
   428  	insts := strings.Split(categoryRe.ReplaceAllString(mnemonics, ""), "|")
   429  	foundInst := []Inst{}
   430  	for _, inst := range insts {
   431  		value, mask := value, mask
   432  		pvalue, pmask := pvalue, pmask
   433  		args := args.Clone()
   434  		if inst == "" {
   435  			continue
   436  		}
   437  		// amend mask and value
   438  		parts := instRe.FindStringSubmatch(inst)
   439  		if parts == nil {
   440  			log.Fatalf("%v couldn't match %s", instRe, inst)
   441  		}
   442  		conds := condRe.FindAllStringSubmatch(parts[2], -1)
   443  		isPCRel := true
   444  		for _, cond := range conds {
   445  			i := args.Find(cond[1])
   446  			v, _ := strconv.ParseInt(cond[2], 16, 32) // the regular expression has checked the number format
   447  			if i < 0 {
   448  				log.Fatalf("%s: %s don't contain arg %s used in %s", text, args, cond[1], inst)
   449  			}
   450  			if cond[1] == "AA" && v == 1 {
   451  				isPCRel = false
   452  			}
   453  			mask |= args[i].BitMask()
   454  			value |= uint32(v) << args[i].Shift()
   455  			args.Delete(i)
   456  		}
   457  		inst := Inst{Text: text, Encoding: parts[1], Value: value, Mask: mask, DontCare: dontCare}
   458  		if ispfx {
   459  			inst = Inst{Text: text, Encoding: parts[1], Value: pvalue, Mask: pmask, DontCare: presv, SValue: value, SMask: mask, SDontCare: resv}
   460  		}
   461  
   462  		// order inst.Args according to mnemonics order
   463  		for i, opr := range operandRe.FindAllString(parts[1], -1) {
   464  			if i == 0 { // operation
   465  				inst.Op = opr
   466  				continue
   467  			}
   468  			field := Field{Name: opr}
   469  			typ := asm.TypeUnknown
   470  			var shift uint8
   471  			opr2 := ""
   472  			opr3 := ""
   473  			switch opr {
   474  			case "target_addr":
   475  				shift = 2
   476  				if isPCRel {
   477  					typ = asm.TypePCRel
   478  				} else {
   479  					typ = asm.TypeLabel
   480  				}
   481  				if args.Find("LI") >= 0 {
   482  					opr = "LI"
   483  				} else {
   484  					opr = "BD"
   485  				}
   486  
   487  			case "offset":
   488  				switch inst.Op {
   489  				// These encode a 6 bit displacement in the format of an X-form opcode.
   490  				// Allowable displaments are -8 to -8*64 in 8B increments.
   491  				case "hashchk", "hashchkp", "hashst", "hashstp":
   492  					typ = asm.TypeNegOffset
   493  					opr = "DX"
   494  					opr2 = "D"
   495  					shift = 3
   496  
   497  				}
   498  
   499  			case "XMSK", "YMSK", "PMSK", "IX", "BHRBE":
   500  				typ = asm.TypeImmUnsigned
   501  
   502  			case "IMM32":
   503  				typ = asm.TypeImmUnsigned
   504  				opr = "imm0"
   505  				opr2 = "imm1"
   506  
   507  			// Handle these cases specially. Note IMM is used on
   508  			// prefixed MMA instructions as a bitmask. Usually, it is a signed value.
   509  			case "R", "UIM", "IMM":
   510  				if ispfx {
   511  					typ = asm.TypeImmUnsigned
   512  					break
   513  				}
   514  				fallthrough
   515  
   516  			case "UI", "BO", "BH", "TH", "LEV", "NB", "L", "TO", "FXM", "FC", "U", "W", "FLM", "IMM8", "RIC", "PRS", "SHB", "SHW", "ST", "SIX", "PS", "DCM", "DGM", "RMC", "SP", "S", "DM", "CT", "EH", "E", "MO", "WC", "A", "IH", "OC", "DUI", "DUIS", "CY", "SC", "PL", "MP", "N", "DRM", "RM":
   517  				typ = asm.TypeImmUnsigned
   518  				if i := args.Find(opr); i < 0 {
   519  					log.Printf("coerce to D: %s: couldn't find extended field %s in %s", text, opr, args)
   520  					opr = "D"
   521  				}
   522  			case "bm":
   523  				opr = "b0"
   524  				opr2 = "b1"
   525  				opr3 = "b2"
   526  				typ = asm.TypeImmUnsigned
   527  
   528  			case "SH":
   529  				typ = asm.TypeImmUnsigned
   530  				if args.Find("sh2") >= 0 { // sh2 || sh
   531  					opr = "sh2"
   532  					opr2 = "sh"
   533  				}
   534  			case "MB", "ME":
   535  				typ = asm.TypeImmUnsigned
   536  				if n := strings.ToLower(opr); args.Find(n) >= 0 {
   537  					opr = n // xx[5] || xx[0:4]
   538  				}
   539  			case "SI", "SIM", "TE":
   540  				if ispfx {
   541  					typ = asm.TypeImmSigned
   542  					opr = "si0"
   543  					opr2 = "si1"
   544  					break
   545  				}
   546  				typ = asm.TypeImmSigned
   547  				if i := args.Find(opr); i < 0 {
   548  					opr = "D"
   549  				}
   550  			case "DCMX":
   551  				typ = asm.TypeImmUnsigned
   552  				// Some instructions encode this consecutively.
   553  				if i := args.Find(opr); i >= 0 {
   554  					break
   555  				}
   556  				typ = asm.TypeImmUnsigned
   557  				opr = "dc"
   558  				opr2 = "dm"
   559  				opr3 = "dx"
   560  			case "DS":
   561  				typ = asm.TypeOffset
   562  				shift = 2
   563  			case "DQ":
   564  				typ = asm.TypeOffset
   565  				shift = 4
   566  			case "D":
   567  				if ispfx {
   568  					typ = asm.TypeOffset
   569  					opr = "d0"
   570  					opr2 = "d1"
   571  					break
   572  				}
   573  				if i := args.Find(opr); i >= 0 {
   574  					typ = asm.TypeOffset
   575  					break
   576  				}
   577  				if i := args.Find("UI"); i >= 0 {
   578  					typ = asm.TypeImmUnsigned
   579  					opr = "UI"
   580  					break
   581  				}
   582  				if i := args.Find("SI"); i >= 0 {
   583  					typ = asm.TypeImmSigned
   584  					opr = "SI"
   585  					break
   586  				}
   587  				if i := args.Find("d0"); i >= 0 {
   588  					typ = asm.TypeImmSigned
   589  					// DX-form
   590  					opr = "d0"
   591  					opr2 = "d1"
   592  					opr3 = "d2"
   593  				}
   594  			case "RA", "RB", "RC", "RS", "RSp", "RT", "RTp":
   595  				typ = asm.TypeReg
   596  			case "BT", "BA", "BB", "BC", "BI":
   597  				if strings.HasPrefix(inst.Op, "mtfs") {
   598  					// mtfsb[01] instructions use BT, but they specify fields in the fpscr.
   599  					typ = asm.TypeImmUnsigned
   600  				} else {
   601  					typ = asm.TypeCondRegBit
   602  				}
   603  			case "BF", "BFA":
   604  				if strings.HasPrefix(inst.Op, "mtfs") {
   605  					// mtfsfi[.] instructions use BF, but they specify fields in the fpscr.
   606  					typ = asm.TypeImmUnsigned
   607  				} else {
   608  					typ = asm.TypeCondRegField
   609  				}
   610  			case "FRA", "FRB", "FRBp", "FRC", "FRS", "FRSp", "FRT", "FRTp", "FRAp":
   611  				typ = asm.TypeFPReg
   612  			case "XA", "XB", "XC", "XS", "XT": // 5-bit, split field
   613  				typ = asm.TypeVecSReg
   614  				opr2 = opr[1:]
   615  				opr = opr[1:] + "X"
   616  			case "XTp", "XSp": // 5-bit, split field
   617  				//XTp encodes 5 bits, VSR is XT*32 + TP<<1
   618  				typ = asm.TypeVecSpReg
   619  				opr2 = opr[1:2] + "p"
   620  				opr = opr[1:2] + "X"
   621  
   622  			case "XAp":
   623  				// XAp in MMA encodes a regular VSR, but is only valid
   624  				// if it is even, and does not overlap the accumulator.
   625  				typ = asm.TypeVecSReg
   626  				opr2 = opr[1:2] + "p"
   627  				opr = opr[1:2] + "X"
   628  
   629  			case "AT", "AS":
   630  				typ = asm.TypeMMAReg
   631  
   632  			case "VRA", "VRB", "VRC", "VRS", "VRT":
   633  				typ = asm.TypeVecReg
   634  
   635  			case "SPR", "TBR":
   636  				typ = asm.TypeSpReg
   637  				if n := strings.ToLower(opr); n != opr && args.Find(n) >= 0 {
   638  					opr = n // spr[5:9] || spr[0:4]
   639  				}
   640  			}
   641  			if typ == asm.TypeUnknown {
   642  				log.Fatalf("%s %s unknown type for opr %s", text, inst, opr)
   643  			}
   644  			field.Type = typ
   645  			field.Shift = shift
   646  			var f1, f2, f3 asm.BitField
   647  			switch {
   648  			case opr3 != "":
   649  				b0 := args.Find(opr)
   650  				b1 := args.Find(opr2)
   651  				b2 := args.Find(opr3)
   652  				f1.Offs, f1.Bits, f1.Word = uint8(args[b0].Offs), uint8(args[b0].Bits), uint8(args[b0].Word)
   653  				f2.Offs, f2.Bits, f2.Word = uint8(args[b1].Offs), uint8(args[b1].Bits), uint8(args[b1].Word)
   654  				f3.Offs, f3.Bits, f3.Word = uint8(args[b2].Offs), uint8(args[b2].Bits), uint8(args[b2].Word)
   655  
   656  			case opr2 != "":
   657  				ext := args.Find(opr)
   658  				if ext < 0 {
   659  					log.Fatalf("%s: couldn't find extended field %s in %s", text, opr, args)
   660  				}
   661  				f1.Offs, f1.Bits, f1.Word = uint8(args[ext].Offs), uint8(args[ext].Bits), uint8(args[ext].Word)
   662  				base := args.Find(opr2)
   663  				if base < 0 {
   664  					log.Fatalf("%s: couldn't find base field %s in %s", text, opr2, args)
   665  				}
   666  				f2.Offs, f2.Bits, f2.Word = uint8(args[base].Offs), uint8(args[base].Bits), uint8(args[base].Word)
   667  			case opr == "mb", opr == "me": // xx[5] || xx[0:4]
   668  				i := args.Find(opr)
   669  				if i < 0 {
   670  					log.Fatalf("%s: couldn't find special 'm[be]' field for %s in %s", text, opr, args)
   671  				}
   672  				f1.Offs, f1.Bits, f1.Word = uint8(args[i].Offs+args[i].Bits)-1, 1, uint8(args[i].Word)
   673  				f2.Offs, f2.Bits, f2.Word = uint8(args[i].Offs), uint8(args[i].Bits)-1, uint8(args[i].Word)
   674  			case opr == "spr", opr == "tbr", opr == "tmr", opr == "dcr": // spr[5:9] || spr[0:4]
   675  				i := args.Find(opr)
   676  				if i < 0 {
   677  					log.Fatalf("%s: couldn't find special 'spr' field for %s in %s", text, opr, args)
   678  				}
   679  				if args[i].Bits != 10 {
   680  					log.Fatalf("%s: special 'spr' field is not 10-bit: %s", text, args)
   681  				}
   682  				f1.Offs, f1.Bits, f2.Word = uint8(args[i].Offs)+5, 5, uint8(args[i].Word)
   683  				f2.Offs, f2.Bits, f2.Word = uint8(args[i].Offs), 5, uint8(args[i].Word)
   684  			default:
   685  				i := args.Find(opr)
   686  				if i < 0 {
   687  					log.Fatalf("%s: couldn't find %s in %s", text, opr, args)
   688  				}
   689  				f1.Offs, f1.Bits, f1.Word = uint8(args[i].Offs), uint8(args[i].Bits), uint8(args[i].Word)
   690  			}
   691  			field.BitFields.Append(f1)
   692  			field.BitFieldNames = append(field.BitFieldNames, opr)
   693  			if f2.Bits > 0 {
   694  				field.BitFields.Append(f2)
   695  				field.BitFieldNames = append(field.BitFieldNames, opr2)
   696  			}
   697  			if f3.Bits > 0 {
   698  				field.BitFields.Append(f3)
   699  				field.BitFieldNames = append(field.BitFieldNames, opr3)
   700  			}
   701  			inst.Fields = append(inst.Fields, field)
   702  		}
   703  		if *debug {
   704  			fmt.Printf("%v\n", inst)
   705  		}
   706  		inst.Isa = isaLevel
   707  		inst.memOp = hasMemoryArg(&inst)
   708  		inst.memOpX = inst.memOp && inst.Op[len(inst.Op)-1] == 'x'
   709  		inst.memOpSt = inst.memOp && strings.Contains(inst.Text, "Store")
   710  		inst.Words = 1
   711  		inst.order = p.nextOrder
   712  		p.nextOrder++
   713  		if ispfx {
   714  			inst.Words = 2
   715  		}
   716  		foundInst = append(foundInst, inst)
   717  	}
   718  
   719  	// Sort mnemonics by bitcount.  This ensures more specific mnemonics are picked
   720  	// up before generic ones (e.g li vs addi, or cmpld/cmplw vs cmpl)
   721  	sort.Sort(instArray(foundInst))
   722  
   723  	p.Insts = append(p.Insts, foundInst...)
   724  }
   725  
   726  // condRegexp is a regular expression that matches condition in mnemonics (e.g. "AA=1")
   727  const condRegexp = `\s*([[:alpha:]]+)=([0-9a-f]+)\s*`
   728  
   729  // condRe matches condition in mnemonics (e.g. "AA=1")
   730  var condRe = regexp.MustCompile(condRegexp)
   731  
   732  // instRe matches instruction with potentially multiple conditions in mnemonics
   733  var instRe = regexp.MustCompile(`^(.*?)\s?(\((` + condRegexp + `)+\))?$`)
   734  
   735  // categoryRe matches intruction category notices in mnemonics
   736  var categoryRe = regexp.MustCompile(`(\s*\[Category:[^]]*\]\s*)|(\s*\[Co-requisite[^]]*\]\s*)|(\s*\(\s*0[Xx][[0-9A-Fa-f_]{9}\s*\)\s*)`)
   737  
   738  // operandRe matches each operand (including opcode) in instruction mnemonics
   739  var operandRe = regexp.MustCompile(`([[:alpha:]][[:alnum:]_]*\.?)`)
   740  
   741  // printText implements the -fmt=text mode, which is not implemented (yet?).
   742  func printText(p *Prog) {
   743  	log.Fatal("-fmt=text not implemented")
   744  }
   745  
   746  // Some ISA instructions look like memory ops, but are not.
   747  var isNotMemopMap = map[string]bool{
   748  	"lxvkq": true,
   749  	"lvsl":  true,
   750  	"lvsr":  true,
   751  }
   752  
   753  // Some ISA instructions are memops, but are not described like "Load ..." or "Store ..."
   754  var isMemopMap = map[string]bool{
   755  	"hashst":   true,
   756  	"hashstp":  true,
   757  	"hashchk":  true,
   758  	"hashchkp": true,
   759  }
   760  
   761  // Does this instruction contain a memory argument (e.g x-form load or d-form store)
   762  func hasMemoryArg(insn *Inst) bool {
   763  	return ((strings.HasPrefix(insn.Text, "Load") || strings.HasPrefix(insn.Text, "Store") ||
   764  		strings.HasPrefix(insn.Text, "Prefixed Load") || strings.HasPrefix(insn.Text, "Prefixed Store")) && !isNotMemopMap[insn.Op]) ||
   765  		isMemopMap[insn.Op]
   766  }
   767  
   768  // Generate a function which takes an obj.Proj and convert it into
   769  // machine code in the supplied buffer. These functions are used
   770  // by asm9.go.
   771  func insnEncFuncStr(insn *Inst, firstName [2]string) string {
   772  	buf := new(bytes.Buffer)
   773  	// Argument packing order.
   774  	// Note, if a2 is not a register type, it is skipped.
   775  	argOrder := []string{
   776  		"p.To",               // a6
   777  		"p.From",             // a1
   778  		"p",                  // a2
   779  		"p.RestArgs[0].Addr", // a3
   780  		"p.RestArgs[1].Addr", // a4
   781  		"p.RestArgs[2].Addr", // a5
   782  	}
   783  	if len(insn.Fields) > len(argOrder) {
   784  		log.Fatalf("cannot handle %v. Only %d args supported.", insn, len(argOrder))
   785  	}
   786  
   787  	// Does this field require an obj.Addr.Offset?
   788  	isImmediate := func(t asm.ArgType) bool {
   789  		return t == asm.TypeImmUnsigned || t == asm.TypeSpReg || t == asm.TypeImmSigned || t == asm.TypeOffset || t == asm.TypeNegOffset
   790  	}
   791  
   792  	if insn.memOp {
   793  		// Swap to/from arguments if we are generating
   794  		// for a store operation.
   795  		if insn.memOpSt {
   796  			// Otherwise, order first three args as: p.From, p.To, p.To
   797  			argOrder[0], argOrder[1] = argOrder[1], argOrder[0]
   798  		}
   799  		argOrder[2] = argOrder[1] // p.Reg is either an Index or Offset (X or D-form)
   800  	} else if len(insn.Fields) > 2 && isImmediate(insn.Fields[2].Type) {
   801  		// Delete the a2 argument if it is not a register type.
   802  		argOrder = append(argOrder[0:2], argOrder[3:]...)
   803  	}
   804  
   805  	fmt.Fprintf(buf, "// %s\n", insn.Encoding)
   806  	fmt.Fprintf(buf, "func type_%s(c *ctxt9, p *obj.Prog, t *Optab, out *[5]uint32) {\n", insn.Op)
   807  	if insn.Words > 1 {
   808  		fmt.Fprintf(buf, "o0 := GenPfxOpcodes[p.As - A%s]\n", firstName[1])
   809  	}
   810  	fmt.Fprintf(buf, "o%d := GenOpcodes[p.As - A%s]\n", insn.Words-1, firstName[0])
   811  
   812  	errCheck := ""
   813  	for j, atype := range insn.Fields {
   814  		itype := ".Reg"
   815  		if isImmediate(atype.Type) {
   816  			itype = ".Offset"
   817  		} else if insn.memOpX && atype.Name == "RA" {
   818  			// X-form memory operations encode RA as the index register of memory type arg.
   819  			itype = ".Index"
   820  		}
   821  
   822  		bitPos := uint64(0)
   823  		// VecSpReg is encoded as an even numbered VSR. It is implicitly shifted by 1.
   824  		if atype.Type == asm.TypeVecSpReg {
   825  			bitPos += 1
   826  		}
   827  		// Count the total number of bits to work backwards when shifting
   828  		for _, f := range atype.BitFields {
   829  			bitPos += uint64(f.Bits)
   830  		}
   831  		// Adjust for any shifting (e.g DQ/DS shifted instructions)
   832  		bitPos += uint64(atype.Shift)
   833  		bits := bitPos
   834  
   835  		// Generate code to twirl the respective bits into the correct position, and mask off extras.
   836  		for i, f := range atype.BitFields {
   837  			bitPos -= uint64(f.Bits)
   838  			argStr := argOrder[j] + itype
   839  			if bitPos != 0 {
   840  				argStr = fmt.Sprintf("(%s>>%d)", argStr, bitPos)
   841  			}
   842  			mask := (1 << uint64(f.Bits)) - 1
   843  			shift := 32 - uint64(f.Offs) - uint64(f.Bits)
   844  			fmt.Fprintf(buf, "o%d |= uint32(%s&0x%x)<<%d // %s\n", f.Word, argStr, mask, shift, atype.BitFieldNames[i])
   845  		}
   846  
   847  		// Generate a check to verify shifted inputs satisfy their constraints.
   848  		// For historical reasons this is not needed for 16 bit values shifted by 16. (i.e SI/UI constants in addis/xoris)
   849  		if atype.Type != asm.TypeNegOffset && atype.Shift != 0 && atype.Shift != 16 && bits != 32 {
   850  			arg := argOrder[j] + itype
   851  			mod := (1 << atype.Shift) - 1
   852  			errCheck += fmt.Sprintf("if %s & 0x%x != 0 {\n", arg, mod)
   853  			errCheck += fmt.Sprintf("c.ctxt.Diag(\"Constant 0x%%x (%%d) is not a multiple of %d\\n%%v\",%s,%s,p)\n", mod+1, arg, arg)
   854  			errCheck += fmt.Sprintf("}\n")
   855  		}
   856  		// NegOffset requires a stronger offset check
   857  		if atype.Type == asm.TypeNegOffset {
   858  			arg := argOrder[j] + itype
   859  			mask := -1 << (atype.BitFields.NumBits() + int(atype.Shift))
   860  			maskl := mask // Sign bits are implied in this type.
   861  			mask |= (1 << atype.Shift) - 1
   862  			min := maskl
   863  			max := maskl | (^mask)
   864  			step := 1 << atype.Shift
   865  			errCheck += fmt.Sprintf("if %s & 0x%x != 0x%x {\n", arg, uint32(mask), uint32(maskl))
   866  			errCheck += fmt.Sprintf("c.ctxt.Diag(\"Constant(%%d) must within the range of [%d,%d] in steps of %d\\n%%v\",%s,p)\n", min, max, step, arg)
   867  			errCheck += fmt.Sprintf("}\n")
   868  		}
   869  		j++
   870  	}
   871  	buf.WriteString(errCheck)
   872  	if insn.Words > 1 {
   873  		fmt.Fprintf(buf, "out[1] = o1\n")
   874  	}
   875  	fmt.Fprintf(buf, "out[0] = o0\n")
   876  	fmt.Fprintf(buf, "}\n")
   877  	return buf.String()
   878  }
   879  
   880  // Generate a stringed name representing the type of arguments ISA
   881  // instruction needs to be encoded into a usable machine instruction
   882  func insnTypeStr(insn *Inst, uniqueRegTypes bool) string {
   883  	if len(insn.Fields) == 0 {
   884  		return "type_none"
   885  	}
   886  
   887  	ret := "type_"
   888  
   889  	// Tag store opcodes to give special treatment when generating
   890  	// assembler function. They encode similarly to their load analogues.
   891  	if insn.memOp {
   892  		if insn.memOpSt {
   893  			ret += "st_"
   894  		} else {
   895  			ret += "ld_"
   896  		}
   897  	}
   898  
   899  	// TODO: this is only sufficient for ISA3.1.
   900  	for _, atype := range insn.Fields {
   901  		switch atype.Type {
   902  		// Simple, register like 5 bit field (CR bit, FPR, GPR, VR)
   903  		case asm.TypeReg, asm.TypeFPReg, asm.TypeVecReg, asm.TypeCondRegBit:
   904  			if uniqueRegTypes {
   905  				ret += map[asm.ArgType]string{asm.TypeReg: "R", asm.TypeFPReg: "F", asm.TypeVecReg: "V", asm.TypeCondRegBit: "C"}[atype.Type]
   906  				// Handle even/odd pairs in FPR/GPR args. They encode as 5 bits too, but odd values are invalid.
   907  				if atype.Name[len(atype.Name)-1] == 'p' {
   908  					ret += "p"
   909  				}
   910  			} else {
   911  				ret += "R"
   912  			}
   913  		case asm.TypeMMAReg, asm.TypeCondRegField: // 3 bit register fields (MMA or CR field)
   914  			ret += "M"
   915  		case asm.TypeSpReg:
   916  			ret += "P"
   917  		case asm.TypeVecSReg: // VSX register (6 bits, usually split into 2 fields)
   918  			ret += "X"
   919  		case asm.TypeVecSpReg: // VSX register pair (5 bits, maybe split fields)
   920  			ret += "Y"
   921  		case asm.TypeImmSigned, asm.TypeOffset, asm.TypeImmUnsigned:
   922  			if atype.Type == asm.TypeImmUnsigned {
   923  				ret += "I"
   924  			} else {
   925  				ret += "S"
   926  			}
   927  			if atype.Shift != 0 {
   928  				ret += fmt.Sprintf("%d", atype.Shift)
   929  			}
   930  		case asm.TypeNegOffset: // e.g offset in hashst rb, offset(ra)
   931  			ret += "N"
   932  		default:
   933  			log.Fatalf("Unhandled type in insnTypeStr: %v\n", atype)
   934  		}
   935  
   936  		// And add bit packing info
   937  		for _, bf := range atype.BitFields {
   938  			ret += fmt.Sprintf("_%d_%d", bf.Word*32+bf.Offs, bf.Bits)
   939  		}
   940  	}
   941  	return ret
   942  }
   943  
   944  type AggInfo struct {
   945  	Insns []*Inst // List of instructions sharing this type
   946  	Typef string  // The generated function name matching this
   947  }
   948  
   949  // Generate an Optab entry for a set of instructions with identical argument types
   950  // and write it to buf.
   951  func genOptabEntry(ta *AggInfo, typeMap map[string]*Inst) string {
   952  	buf := new(bytes.Buffer)
   953  	fitArg := func(f *Field, i *Inst) string {
   954  		argToRegType := map[asm.ArgType]string{
   955  			// TODO: only complete for ISA 3.1
   956  			asm.TypeReg:          "C_REG",
   957  			asm.TypeCondRegField: "C_CREG",
   958  			asm.TypeCondRegBit:   "C_CRBIT",
   959  			asm.TypeFPReg:        "C_FREG",
   960  			asm.TypeVecReg:       "C_VREG",
   961  			asm.TypeVecSReg:      "C_VSREG",
   962  			asm.TypeVecSpReg:     "C_VSREG",
   963  			asm.TypeMMAReg:       "C_AREG",
   964  			asm.TypeSpReg:        "C_SPR",
   965  		}
   966  		if t, fnd := argToRegType[f.Type]; fnd {
   967  			if f.Name[len(f.Name)-1] == 'p' {
   968  				return t + "P"
   969  			}
   970  			return t
   971  		}
   972  		bits := f.Shift
   973  		for _, sf := range f.BitFields {
   974  			bits += sf.Bits
   975  		}
   976  		shift := ""
   977  		if f.Shift != 0 {
   978  			shift = fmt.Sprintf("S%d", f.Shift)
   979  		}
   980  		sign := "U"
   981  		if f.Type == asm.TypeImmSigned || f.Type == asm.TypeOffset {
   982  			sign = "S"
   983  			// DS/DQ offsets should explicitly test their offsets to ensure
   984  			// they are aligned correctly. This makes tracking down bad offset
   985  			// passed to the compiler more straightfoward.
   986  			if f.Type == asm.TypeOffset {
   987  				shift = ""
   988  			}
   989  		}
   990  		if f.Type == asm.TypeNegOffset {
   991  			// This is a hack, but allows hashchk and like to correctly
   992  			// merge there argument into a C_SOREG memory location type
   993  			// argument a little later.
   994  			sign = "S"
   995  			bits = 16
   996  			shift = ""
   997  		}
   998  		return fmt.Sprintf("C_%s%d%sCON", sign, bits, shift)
   999  	}
  1000  	insn := ta.Insns[0]
  1001  	args := [6]string{}
  1002  	// Note, a2 is skipped if the second input argument does not map to a reg.
  1003  	argOrder := []int{
  1004  		5,
  1005  		0,
  1006  		1,
  1007  		2,
  1008  		3,
  1009  		4}
  1010  
  1011  	i := 0
  1012  	for _, j := range insn.Fields {
  1013  		// skip a2 if it isn't a reg type.
  1014  		at := fitArg(&j, insn)
  1015  		if argOrder[i] == 1 && !strings.HasSuffix(at, "REG") {
  1016  			i++
  1017  		}
  1018  		args[argOrder[i]] = at
  1019  		i++
  1020  	}
  1021  
  1022  	// Likewise, fixup memory operations. Combine imm + reg, reg + reg
  1023  	// operations into memory type arguments.
  1024  	if insn.memOp {
  1025  		switch args[0] + " " + args[1] {
  1026  		case "C_REG C_REG":
  1027  			args[0] = "C_XOREG"
  1028  		case "C_S16CON C_REG":
  1029  			args[0] = "C_SOREG"
  1030  		case "C_S34CON C_REG":
  1031  			args[0] = "C_LOREG"
  1032  		}
  1033  		args[1] = ""
  1034  		// Finally, fixup store operand ordering to match golang
  1035  		if insn.memOpSt {
  1036  			args[0], args[5] = args[5], args[0]
  1037  		}
  1038  
  1039  	}
  1040  	fmt.Fprintf(buf, "{as: A%s,", opName(insn.Op))
  1041  	for i, s := range args {
  1042  		if len(s) <= 0 {
  1043  			continue
  1044  		}
  1045  		fmt.Fprintf(buf, "a%d: %s, ", i+1, s)
  1046  	}
  1047  	typef := typeMap[ta.Typef].Op
  1048  
  1049  	pfx := ""
  1050  	if insn.Words > 1 {
  1051  		pfx = " ispfx: true,"
  1052  	}
  1053  	fmt.Fprintf(buf, "asmout: type_%s,%s size: %d},\n", typef, pfx, insn.Words*4)
  1054  	return buf.String()
  1055  }
  1056  
  1057  // printEncoder implements the -fmt=encoder mode. This generates a go file named
  1058  // asm9_gtables.go.new. It is self-contained and is called into by the PPC64
  1059  // assembler routines.
  1060  //
  1061  // For now it is restricted to generating code for ISA 3.1 and newer, but it could
  1062  // support older ISA versions with some work, and integration effort.
  1063  func printEncoder(p *Prog) {
  1064  	const minISA = ISA_V31
  1065  
  1066  	// The type map separates based on obj.Addr to a bit field.  Register types
  1067  	// for GPR, FPR, VR pack identically, but are classified differently.
  1068  	typeMap := map[string]*Inst{}
  1069  	typeAggMap := map[string]*AggInfo{}
  1070  	var oplistBuf bytes.Buffer
  1071  	var opnameBuf bytes.Buffer
  1072  
  1073  	// The first opcode of 32 or 64 bits to appear in the opcode tables.
  1074  	firstInsn := [2]string{}
  1075  
  1076  	// Sort the instructions by word size, then by ISA version, oldest to newest.
  1077  	sort.Slice(p.Insts, func(i, j int) bool {
  1078  		if p.Insts[i].Words != p.Insts[j].Words {
  1079  			return p.Insts[i].Words < p.Insts[j].Words
  1080  		}
  1081  		return p.Insts[i].order > p.Insts[j].order
  1082  	})
  1083  
  1084  	// Classify each opcode and it's arguments, and generate opcode name/enum values.
  1085  	for i, insn := range p.Insts {
  1086  		if insn.Isa < minISA {
  1087  			continue
  1088  		}
  1089  		extra := ""
  1090  		if firstInsn[insn.Words-1] == "" {
  1091  			firstInsn[insn.Words-1] = opName(insn.Op)
  1092  			if insn.Words == 1 {
  1093  				extra = " = ALASTAOUT + iota"
  1094  			}
  1095  		}
  1096  		opType := insnTypeStr(&insn, false)
  1097  		opTypeOptab := insnTypeStr(&insn, true)
  1098  		fmt.Fprintf(&oplistBuf, "A%s%s\n", opName(insn.Op), extra)
  1099  		fmt.Fprintf(&opnameBuf, "\"%s\",\n", opName(insn.Op))
  1100  		// Use the oldest instruction to name the encoder function.  Some names
  1101  		// may change if minISA is lowered.
  1102  		if _, fnd := typeMap[opType]; !fnd {
  1103  			typeMap[opType] = &p.Insts[i]
  1104  		}
  1105  		at, fnd := typeAggMap[opTypeOptab]
  1106  		if !fnd {
  1107  			typeAggMap[opTypeOptab] = &AggInfo{[]*Inst{&p.Insts[i]}, opType}
  1108  		} else {
  1109  			at.Insns = append(at.Insns, &p.Insts[i])
  1110  		}
  1111  	}
  1112  	fmt.Fprintf(&oplistBuf, "ALASTGEN\n")
  1113  	fmt.Fprintf(&oplistBuf, "AFIRSTGEN = A%s\n", firstInsn[0])
  1114  
  1115  	// Sort type information before outputing to ensure stable ordering
  1116  	targ := struct {
  1117  		InputFile   string
  1118  		Insts       []Inst
  1119  		MinISA      isaversion
  1120  		TypeAggList []*AggInfo
  1121  		TypeList    []*Inst
  1122  		FirstInsn   [2]string
  1123  		TypeMap     map[string]*Inst
  1124  		Oplist      string
  1125  		Opnames     string
  1126  	}{InputFile: inputFile, Insts: p.Insts, MinISA: minISA, FirstInsn: firstInsn, TypeMap: typeMap, Oplist: oplistBuf.String(), Opnames: opnameBuf.String()}
  1127  	for _, v := range typeAggMap {
  1128  		targ.TypeAggList = append(targ.TypeAggList, v)
  1129  	}
  1130  	for _, v := range typeMap {
  1131  		targ.TypeList = append(targ.TypeList, v)
  1132  	}
  1133  	sort.Slice(targ.TypeAggList, func(i, j int) bool {
  1134  		// Sort based on the first entry, it is the last to appear in Appendix F.
  1135  		return targ.TypeAggList[i].Insns[0].Op < targ.TypeAggList[j].Insns[0].Op
  1136  	})
  1137  	sort.Slice(targ.TypeList, func(i, j int) bool {
  1138  		return targ.TypeList[i].Op < targ.TypeList[j].Op
  1139  	})
  1140  
  1141  	// Generate asm9_gtable.go from the following template.
  1142  	asm9_gtable_go := `
  1143  		// DO NOT EDIT
  1144  		// generated by: ppc64map -fmt=encoder {{.InputFile}}
  1145  
  1146  		package ppc64
  1147  
  1148  		import (
  1149  			"cmd/internal/obj"
  1150  		)
  1151  
  1152  		const (
  1153  			{{print $.Oplist -}}
  1154  		)
  1155  
  1156  		var GenAnames = []string {
  1157  			{{print $.Opnames -}}
  1158  		}
  1159  
  1160  		var GenOpcodes = [...]uint32 {
  1161  			{{range $v := .Insts}}{{if ge $v.Isa $.MinISA -}}
  1162  			{{if (eq $v.Words 1)}}{{printf "0x%08x, // A%s" $v.Value  (opname $v.Op)}}
  1163  			{{else}}              {{printf "0x%08x, // A%s" $v.SValue (opname $v.Op)}}
  1164  			{{end}}{{end}}{{end -}}
  1165  		}
  1166  
  1167  		var GenPfxOpcodes = [...]uint32 {
  1168  			{{range $v := .Insts}}{{if and (ge $v.Isa $.MinISA) (eq $v.Words 2) -}}
  1169  			{{printf "0x%08x, // A%s" $v.Value (opname $v.Op)}}
  1170  			{{end}}{{end -}}
  1171  		}
  1172  
  1173  		var optabGen = []Optab {
  1174  			{{range $v := .TypeAggList -}}
  1175  			{{genoptabentry $v $.TypeMap -}}
  1176  			{{end -}}
  1177  		}
  1178  
  1179  		{{range $v := .TypeList}}
  1180  		{{genencoderfunc $v $.FirstInsn}}
  1181  		{{end}}
  1182  
  1183  		func opsetGen(from obj.As) bool {
  1184  			r0 := from & obj.AMask
  1185  			switch from {
  1186  			{{range $v := .TypeAggList -}}
  1187  			case A{{opname (index $v.Insns 0).Op}}:
  1188  				{{range $w := (slice $v.Insns 1) -}}
  1189  				opset(A{{opname $w.Op}},r0)
  1190  				{{end -}}
  1191  			{{end -}}
  1192  			default:
  1193  				return false
  1194  			}
  1195  			return true
  1196  		}
  1197  	`
  1198  	tmpl := template.New("asm9_gtable.go")
  1199  	tmpl.Funcs(template.FuncMap{
  1200  		"opname":         opName,
  1201  		"genencoderfunc": insnEncFuncStr,
  1202  		"genoptabentry":  genOptabEntry,
  1203  	})
  1204  	tmpl.Parse(asm9_gtable_go)
  1205  
  1206  	// Write and gofmt the new file.
  1207  	var tbuf bytes.Buffer
  1208  	if err := tmpl.Execute(&tbuf, targ); err != nil {
  1209  		log.Fatal(err)
  1210  	}
  1211  	tout, err := gofmt.Source(tbuf.Bytes())
  1212  	if err != nil {
  1213  		fmt.Printf("%s", tbuf.Bytes())
  1214  		log.Fatalf("gofmt error: %v", err)
  1215  	}
  1216  	if err := os.WriteFile("asm9_gtables.go.new", tout, 0666); err != nil {
  1217  		log.Fatalf("Failed to create asm9_gtables.new: %v", err)
  1218  	}
  1219  }
  1220  
  1221  // printASM implements the -fmt=asm mode.  This prints out a gnu assembler file
  1222  // which can be used to used to generate test output to verify the golang
  1223  // disassembler's gnu output matches gnu binutils. This is used as an input to
  1224  // ppc64util to generate the decode_generated.txt test case.
  1225  func printASM(p *Prog) {
  1226  	fmt.Printf("#include \"hack.h\"\n")
  1227  	fmt.Printf(".text\n")
  1228  	for _, inst := range p.Insts {
  1229  		// Prefixed load/stores have extra restrictions with D(RA) and R. Rename them
  1230  		// To simplify generation.
  1231  		str := inst.Encoding
  1232  		if str[0] == 'p' && str[len(str)-1] == 'R' {
  1233  			str = strings.Replace(str, "D(RA),R", "Dpfx(RApfx),Rpfx", 1)
  1234  			str = strings.Replace(str, "RA,SI,R", "RApfx,SIpfx,Rpfx", 1)
  1235  		}
  1236  		fmt.Printf("\t%s\n", str)
  1237  	}
  1238  }
  1239  
  1240  // opName translate an opcode to a valid Go identifier all-cap op name.
  1241  func opName(op string) string {
  1242  	return strings.ToUpper(strings.Replace(op, ".", "CC", 1))
  1243  }
  1244  
  1245  // argFieldName constructs a name for the argField
  1246  func argFieldName(f Field) string {
  1247  	ns := []string{"ap", f.Type.String()}
  1248  	for _, b := range f.BitFields {
  1249  		ns = append(ns, fmt.Sprintf("%d_%d", b.Word*32+b.Offs, b.Word*32+b.Offs+b.Bits-1))
  1250  	}
  1251  	if f.Shift > 0 {
  1252  		ns = append(ns, fmt.Sprintf("shift%d", f.Shift))
  1253  	}
  1254  	return strings.Join(ns, "_")
  1255  }
  1256  
  1257  var funcBodyTmpl = template.Must(template.New("funcBody").Parse(``))
  1258  
  1259  // printDecoder implements the -fmt=decoder mode.
  1260  // It emits the tables.go for package armasm's decoder.
  1261  func printDecoder(p *Prog) {
  1262  	var buf bytes.Buffer
  1263  
  1264  	fmt.Fprintf(&buf, "// Code generated by ppc64map -fmt=decoder %s DO NOT EDIT.\n", inputFile)
  1265  	fmt.Fprintf(&buf, "\n")
  1266  
  1267  	fmt.Fprintf(&buf, "package ppc64asm\n\n")
  1268  
  1269  	// Build list of opcodes, using the csv order (which corresponds to ISA docs order)
  1270  	m := map[string]bool{}
  1271  	fmt.Fprintf(&buf, "const (\n\t_ Op = iota\n")
  1272  	for _, inst := range p.Insts {
  1273  		name := opName(inst.Op)
  1274  		if ok := m[name]; ok {
  1275  			continue
  1276  		}
  1277  		m[name] = true
  1278  		fmt.Fprintf(&buf, "\t%s\n", name)
  1279  	}
  1280  	fmt.Fprint(&buf, ")\n\n\n")
  1281  
  1282  	// Emit slice mapping opcode number to name string.
  1283  	m = map[string]bool{}
  1284  	fmt.Fprintf(&buf, "var opstr = [...]string{\n")
  1285  	for _, inst := range p.Insts {
  1286  		name := opName(inst.Op)
  1287  		if ok := m[name]; ok {
  1288  			continue
  1289  		}
  1290  		m[name] = true
  1291  		fmt.Fprintf(&buf, "\t%s: %q,\n", opName(inst.Op), inst.Op)
  1292  	}
  1293  	fmt.Fprint(&buf, "}\n\n\n")
  1294  
  1295  	// print out argFields
  1296  	fmt.Fprintf(&buf, "var (\n")
  1297  	m = map[string]bool{}
  1298  	for _, inst := range p.Insts {
  1299  		for _, f := range inst.Fields {
  1300  			name := argFieldName(f)
  1301  			if ok := m[name]; ok {
  1302  				continue
  1303  			}
  1304  			m[name] = true
  1305  			fmt.Fprintf(&buf, "\t%s = &argField{Type: %#v, Shift: %d, BitFields: BitFields{", name, f.Type, f.Shift)
  1306  			for _, b := range f.BitFields {
  1307  				fmt.Fprintf(&buf, "{%d, %d, %d},", b.Offs, b.Bits, b.Word)
  1308  			}
  1309  			fmt.Fprintf(&buf, "}}\n")
  1310  		}
  1311  	}
  1312  	fmt.Fprint(&buf, ")\n\n\n")
  1313  
  1314  	// Emit decoding table.
  1315  	fmt.Fprintf(&buf, "var instFormats = [...]instFormat{\n")
  1316  	for _, inst := range p.Insts {
  1317  		m, v, dc := uint64(inst.Mask)<<32, uint64(inst.Value)<<32, uint64(inst.DontCare)<<32
  1318  		m, v, dc = uint64(inst.SMask)|m, uint64(inst.SValue)|v, uint64(inst.SDontCare)|dc
  1319  		fmt.Fprintf(&buf, "\t{ %s, %#x, %#x, %#x,", opName(inst.Op), m, v, dc)
  1320  		fmt.Fprintf(&buf, " // %s (%s)\n\t\t[6]*argField{", inst.Text, inst.Encoding)
  1321  		for _, f := range inst.Fields {
  1322  			fmt.Fprintf(&buf, "%s, ", argFieldName(f))
  1323  		}
  1324  		fmt.Fprintf(&buf, "}},\n")
  1325  	}
  1326  	fmt.Fprint(&buf, "}\n\n")
  1327  
  1328  	out, err := gofmt.Source(buf.Bytes())
  1329  	if err != nil {
  1330  		log.Fatalf("gofmt error: %v", err)
  1331  		fmt.Printf("%s", buf.Bytes())
  1332  	} else {
  1333  		fmt.Printf("%s", out)
  1334  	}
  1335  }
  1336  

View as plain text