github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/cmd/compile/internal/ssa/gen/rulegen.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 gen
     6  
     7  // This program generates Go code that applies rewrite rules to a Value.
     8  // The generated code implements a function of type func (v *Value) bool
     9  // which returns true iff if did something.
    10  // Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html
    11  
    12  package main
    13  
    14  import (
    15  	"bufio"
    16  	"bytes"
    17  	"flag"
    18  	"fmt"
    19  	"go/format"
    20  	"io"
    21  	"io/ioutil"
    22  	"log"
    23  	"os"
    24  	"regexp"
    25  	"sort"
    26  	"strings"
    27  )
    28  
    29  // rule syntax:
    30  //  sexpr [&& extra conditions] -> [@block] sexpr
    31  //
    32  // sexpr are s-expressions (lisp-like parenthesized groupings)
    33  // sexpr ::= [variable:](opcode sexpr*)
    34  //         | variable
    35  //         | <type>
    36  //         | [auxint]
    37  //         | {aux}
    38  //
    39  // aux      ::= variable | {code}
    40  // type     ::= variable | {code}
    41  // variable ::= some token
    42  // opcode   ::= one of the opcodes from the *Ops.go files
    43  
    44  // extra conditions is just a chunk of Go that evaluates to a boolean. It may use
    45  // variables declared in the matching sexpr. The variable "v" is predefined to be
    46  // the value matched by the entire rule.
    47  
    48  // If multiple rules match, the first one in file order is selected.
    49  
    50  var (
    51  	genLog = flag.Bool("log", false, "generate code that logs; for debugging only")
    52  )
    53  
    54  type Rule struct {
    55  	rule string
    56  	loc  string // file name & line number
    57  }
    58  
    59  func (r Rule) String() string {
    60  	return fmt.Sprintf("rule %q at %s", r.rule, r.loc)
    61  }
    62  
    63  // parse returns the matching part of the rule, additional conditions, and the result.
    64  func (r Rule) parse() (match, cond, result string) {
    65  	s := strings.Split(r.rule, "->")
    66  	if len(s) != 2 {
    67  		log.Fatalf("no arrow in %s", r)
    68  	}
    69  	match = strings.TrimSpace(s[0])
    70  	result = strings.TrimSpace(s[1])
    71  	cond = ""
    72  	if i := strings.Index(match, "&&"); i >= 0 {
    73  		cond = strings.TrimSpace(match[i+2:])
    74  		match = strings.TrimSpace(match[:i])
    75  	}
    76  	return match, cond, result
    77  }
    78  
    79  func genRules(arch arch) {
    80  	// Open input file.
    81  	text, err := os.Open(arch.name + ".rules")
    82  	if err != nil {
    83  		log.Fatalf("can't read rule file: %v", err)
    84  	}
    85  
    86  	// oprules contains a list of rules for each block and opcode
    87  	blockrules := map[string][]Rule{}
    88  	oprules := map[string][]Rule{}
    89  
    90  	// read rule file
    91  	scanner := bufio.NewScanner(text)
    92  	rule := ""
    93  	var lineno int
    94  	var ruleLineno int // line number of "->"
    95  	for scanner.Scan() {
    96  		lineno++
    97  		line := scanner.Text()
    98  		if i := strings.Index(line, "//"); i >= 0 {
    99  			// Remove comments. Note that this isn't string safe, so
   100  			// it will truncate lines with // inside strings. Oh well.
   101  			line = line[:i]
   102  		}
   103  		rule += " " + line
   104  		rule = strings.TrimSpace(rule)
   105  		if rule == "" {
   106  			continue
   107  		}
   108  		if !strings.Contains(rule, "->") {
   109  			continue
   110  		}
   111  		if ruleLineno == 0 {
   112  			ruleLineno = lineno
   113  		}
   114  		if strings.HasSuffix(rule, "->") {
   115  			continue
   116  		}
   117  		if unbalanced(rule) {
   118  			continue
   119  		}
   120  
   121  		loc := fmt.Sprintf("%s.rules:%d", arch.name, ruleLineno)
   122  		for _, crule := range commute(rule, arch) {
   123  			r := Rule{rule: crule, loc: loc}
   124  			if rawop := strings.Split(crule, " ")[0][1:]; isBlock(rawop, arch) {
   125  				blockrules[rawop] = append(blockrules[rawop], r)
   126  			} else {
   127  				// Do fancier value op matching.
   128  				match, _, _ := r.parse()
   129  				op, oparch, _, _, _, _ := parseValue(match, arch, loc)
   130  				opname := fmt.Sprintf("Op%s%s", oparch, op.name)
   131  				oprules[opname] = append(oprules[opname], r)
   132  			}
   133  		}
   134  		rule = ""
   135  		ruleLineno = 0
   136  	}
   137  	if err := scanner.Err(); err != nil {
   138  		log.Fatalf("scanner failed: %v\n", err)
   139  	}
   140  	if unbalanced(rule) {
   141  		log.Fatalf("%s.rules:%d: unbalanced rule: %v\n", arch.name, lineno, rule)
   142  	}
   143  
   144  	// Order all the ops.
   145  	var ops []string
   146  	for op := range oprules {
   147  		ops = append(ops, op)
   148  	}
   149  	sort.Strings(ops)
   150  
   151  	// Start output buffer, write header.
   152  	w := new(bytes.Buffer)
   153  	fmt.Fprintf(w, "// Code generated from gen/%s.rules; DO NOT EDIT.\n", arch.name)
   154  	fmt.Fprintln(w, "// generated with: cd gen; go run *.go")
   155  	fmt.Fprintln(w)
   156  	fmt.Fprintln(w, "package ssa")
   157  	fmt.Fprintln(w, "import \"math\"")
   158  	fmt.Fprintln(w, "import \"cmd/internal/obj\"")
   159  	fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used")
   160  	fmt.Fprintln(w, "var _ = obj.ANOP     // in case not otherwise used")
   161  
   162  	// Main rewrite routine is a switch on v.Op.
   163  	fmt.Fprintf(w, "func rewriteValue%s(v *Value) bool {\n", arch.name)
   164  	fmt.Fprintf(w, "switch v.Op {\n")
   165  	for _, op := range ops {
   166  		fmt.Fprintf(w, "case %s:\n", op)
   167  		fmt.Fprintf(w, "return rewriteValue%s_%s(v)\n", arch.name, op)
   168  	}
   169  	fmt.Fprintf(w, "}\n")
   170  	fmt.Fprintf(w, "return false\n")
   171  	fmt.Fprintf(w, "}\n")
   172  
   173  	// Generate a routine per op. Note that we don't make one giant routine
   174  	// because it is too big for some compilers.
   175  	for _, op := range ops {
   176  		buf := new(bytes.Buffer)
   177  		var canFail bool
   178  		for i, rule := range oprules[op] {
   179  			match, cond, result := rule.parse()
   180  			fmt.Fprintf(buf, "// match: %s\n", match)
   181  			fmt.Fprintf(buf, "// cond: %s\n", cond)
   182  			fmt.Fprintf(buf, "// result: %s\n", result)
   183  
   184  			canFail = false
   185  			fmt.Fprintf(buf, "for {\n")
   186  			if genMatch(buf, arch, match, rule.loc) {
   187  				canFail = true
   188  			}
   189  
   190  			if cond != "" {
   191  				fmt.Fprintf(buf, "if !(%s) {\nbreak\n}\n", cond)
   192  				canFail = true
   193  			}
   194  			if !canFail && i != len(oprules[op])-1 {
   195  				log.Fatalf("unconditional rule %s is followed by other rules", match)
   196  			}
   197  
   198  			genResult(buf, arch, result, rule.loc)
   199  			if *genLog {
   200  				fmt.Fprintf(buf, "logRule(\"%s\")\n", rule.loc)
   201  			}
   202  			fmt.Fprintf(buf, "return true\n")
   203  
   204  			fmt.Fprintf(buf, "}\n")
   205  		}
   206  		if canFail {
   207  			fmt.Fprintf(buf, "return false\n")
   208  		}
   209  
   210  		body := buf.String()
   211  		// Do a rough match to predict whether we need b, config, fe, and/or types.
   212  		// It's not precise--thus the blank assignments--but it's good enough
   213  		// to avoid generating needless code and doing pointless nil checks.
   214  		hasb := strings.Contains(body, "b.")
   215  		hasconfig := strings.Contains(body, "config.") || strings.Contains(body, "config)")
   216  		hasfe := strings.Contains(body, "fe.")
   217  		hasts := strings.Contains(body, "types.")
   218  		fmt.Fprintf(w, "func rewriteValue%s_%s(v *Value) bool {\n", arch.name, op)
   219  		if hasb || hasconfig || hasfe {
   220  			fmt.Fprintln(w, "b := v.Block")
   221  			fmt.Fprintln(w, "_ = b")
   222  		}
   223  		if hasconfig {
   224  			fmt.Fprintln(w, "config := b.Func.Config")
   225  			fmt.Fprintln(w, "_ = config")
   226  		}
   227  		if hasfe {
   228  			fmt.Fprintln(w, "fe := b.Func.fe")
   229  			fmt.Fprintln(w, "_ = fe")
   230  		}
   231  		if hasts {
   232  			fmt.Fprintln(w, "types := &b.Func.Config.Types")
   233  			fmt.Fprintln(w, "_ = types")
   234  		}
   235  		fmt.Fprint(w, body)
   236  		fmt.Fprintf(w, "}\n")
   237  	}
   238  
   239  	// Generate block rewrite function. There are only a few block types
   240  	// so we can make this one function with a switch.
   241  	fmt.Fprintf(w, "func rewriteBlock%s(b *Block) bool {\n", arch.name)
   242  	fmt.Fprintln(w, "config := b.Func.Config")
   243  	fmt.Fprintln(w, "_ = config")
   244  	fmt.Fprintln(w, "fe := b.Func.fe")
   245  	fmt.Fprintln(w, "_ = fe")
   246  	fmt.Fprintln(w, "types := &config.Types")
   247  	fmt.Fprintln(w, "_ = types")
   248  	fmt.Fprintf(w, "switch b.Kind {\n")
   249  	ops = nil
   250  	for op := range blockrules {
   251  		ops = append(ops, op)
   252  	}
   253  	sort.Strings(ops)
   254  	for _, op := range ops {
   255  		fmt.Fprintf(w, "case %s:\n", blockName(op, arch))
   256  		for _, rule := range blockrules[op] {
   257  			match, cond, result := rule.parse()
   258  			fmt.Fprintf(w, "// match: %s\n", match)
   259  			fmt.Fprintf(w, "// cond: %s\n", cond)
   260  			fmt.Fprintf(w, "// result: %s\n", result)
   261  
   262  			fmt.Fprintf(w, "for {\n")
   263  
   264  			s := split(match[1 : len(match)-1]) // remove parens, then split
   265  
   266  			// check match of control value
   267  			if s[1] != "nil" {
   268  				fmt.Fprintf(w, "v := b.Control\n")
   269  				if strings.Contains(s[1], "(") {
   270  					genMatch0(w, arch, s[1], "v", map[string]struct{}{}, false, rule.loc)
   271  				} else {
   272  					fmt.Fprintf(w, "_ = v\n") // in case we don't use v
   273  					fmt.Fprintf(w, "%s := b.Control\n", s[1])
   274  				}
   275  			}
   276  
   277  			// assign successor names
   278  			succs := s[2:]
   279  			for i, a := range succs {
   280  				if a != "_" {
   281  					fmt.Fprintf(w, "%s := b.Succs[%d]\n", a, i)
   282  				}
   283  			}
   284  
   285  			if cond != "" {
   286  				fmt.Fprintf(w, "if !(%s) {\nbreak\n}\n", cond)
   287  			}
   288  
   289  			// Rule matches. Generate result.
   290  			t := split(result[1 : len(result)-1]) // remove parens, then split
   291  			newsuccs := t[2:]
   292  
   293  			// Check if newsuccs is the same set as succs.
   294  			m := map[string]bool{}
   295  			for _, succ := range succs {
   296  				if m[succ] {
   297  					log.Fatalf("can't have a repeat successor name %s in %s", succ, rule)
   298  				}
   299  				m[succ] = true
   300  			}
   301  			for _, succ := range newsuccs {
   302  				if !m[succ] {
   303  					log.Fatalf("unknown successor %s in %s", succ, rule)
   304  				}
   305  				delete(m, succ)
   306  			}
   307  			if len(m) != 0 {
   308  				log.Fatalf("unmatched successors %v in %s", m, rule)
   309  			}
   310  
   311  			fmt.Fprintf(w, "b.Kind = %s\n", blockName(t[0], arch))
   312  			if t[1] == "nil" {
   313  				fmt.Fprintf(w, "b.SetControl(nil)\n")
   314  			} else {
   315  				fmt.Fprintf(w, "b.SetControl(%s)\n", genResult0(w, arch, t[1], new(int), false, false, rule.loc))
   316  			}
   317  
   318  			succChanged := false
   319  			for i := 0; i < len(succs); i++ {
   320  				if succs[i] != newsuccs[i] {
   321  					succChanged = true
   322  				}
   323  			}
   324  			if succChanged {
   325  				if len(succs) != 2 {
   326  					log.Fatalf("changed successors, len!=2 in %s", rule)
   327  				}
   328  				if succs[0] != newsuccs[1] || succs[1] != newsuccs[0] {
   329  					log.Fatalf("can only handle swapped successors in %s", rule)
   330  				}
   331  				fmt.Fprintln(w, "b.swapSuccessors()")
   332  			}
   333  			for i := 0; i < len(succs); i++ {
   334  				fmt.Fprintf(w, "_ = %s\n", newsuccs[i])
   335  			}
   336  
   337  			if *genLog {
   338  				fmt.Fprintf(w, "logRule(\"%s\")\n", rule.loc)
   339  			}
   340  			fmt.Fprintf(w, "return true\n")
   341  
   342  			fmt.Fprintf(w, "}\n")
   343  		}
   344  	}
   345  	fmt.Fprintf(w, "}\n")
   346  	fmt.Fprintf(w, "return false\n")
   347  	fmt.Fprintf(w, "}\n")
   348  
   349  	// gofmt result
   350  	b := w.Bytes()
   351  	src, err := format.Source(b)
   352  	if err != nil {
   353  		fmt.Printf("%s\n", b)
   354  		panic(err)
   355  	}
   356  
   357  	// Write to file
   358  	err = ioutil.WriteFile("../rewrite"+arch.name+".go", src, 0666)
   359  	if err != nil {
   360  		log.Fatalf("can't write output: %v\n", err)
   361  	}
   362  }
   363  
   364  // genMatch returns true if the match can fail.
   365  func genMatch(w io.Writer, arch arch, match string, loc string) bool {
   366  	return genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc)
   367  }
   368  
   369  func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, top bool, loc string) bool {
   370  	if match[0] != '(' || match[len(match)-1] != ')' {
   371  		panic("non-compound expr in genMatch0: " + match)
   372  	}
   373  	canFail := false
   374  
   375  	op, oparch, typ, auxint, aux, args := parseValue(match, arch, loc)
   376  
   377  	// check op
   378  	if !top {
   379  		fmt.Fprintf(w, "if %s.Op != Op%s%s {\nbreak\n}\n", v, oparch, op.name)
   380  		canFail = true
   381  	}
   382  
   383  	if typ != "" {
   384  		if !isVariable(typ) {
   385  			// code. We must match the results of this code.
   386  			fmt.Fprintf(w, "if %s.Type != %s {\nbreak\n}\n", v, typ)
   387  			canFail = true
   388  		} else {
   389  			// variable
   390  			if _, ok := m[typ]; ok {
   391  				// must match previous variable
   392  				fmt.Fprintf(w, "if %s.Type != %s {\nbreak\n}\n", v, typ)
   393  				canFail = true
   394  			} else {
   395  				m[typ] = struct{}{}
   396  				fmt.Fprintf(w, "%s := %s.Type\n", typ, v)
   397  			}
   398  		}
   399  	}
   400  
   401  	if auxint != "" {
   402  		if !isVariable(auxint) {
   403  			// code
   404  			fmt.Fprintf(w, "if %s.AuxInt != %s {\nbreak\n}\n", v, auxint)
   405  			canFail = true
   406  		} else {
   407  			// variable
   408  			if _, ok := m[auxint]; ok {
   409  				fmt.Fprintf(w, "if %s.AuxInt != %s {\nbreak\n}\n", v, auxint)
   410  				canFail = true
   411  			} else {
   412  				m[auxint] = struct{}{}
   413  				fmt.Fprintf(w, "%s := %s.AuxInt\n", auxint, v)
   414  			}
   415  		}
   416  	}
   417  
   418  	if aux != "" {
   419  
   420  		if !isVariable(aux) {
   421  			// code
   422  			fmt.Fprintf(w, "if %s.Aux != %s {\nbreak\n}\n", v, aux)
   423  			canFail = true
   424  		} else {
   425  			// variable
   426  			if _, ok := m[aux]; ok {
   427  				fmt.Fprintf(w, "if %s.Aux != %s {\nbreak\n}\n", v, aux)
   428  				canFail = true
   429  			} else {
   430  				m[aux] = struct{}{}
   431  				fmt.Fprintf(w, "%s := %s.Aux\n", aux, v)
   432  			}
   433  		}
   434  	}
   435  
   436  	for i, arg := range args {
   437  		if arg == "_" {
   438  			continue
   439  		}
   440  		if !strings.Contains(arg, "(") {
   441  			// leaf variable
   442  			if _, ok := m[arg]; ok {
   443  				// variable already has a definition. Check whether
   444  				// the old definition and the new definition match.
   445  				// For example, (add x x).  Equality is just pointer equality
   446  				// on Values (so cse is important to do before lowering).
   447  				fmt.Fprintf(w, "if %s != %s.Args[%d] {\nbreak\n}\n", arg, v, i)
   448  				canFail = true
   449  			} else {
   450  				// remember that this variable references the given value
   451  				m[arg] = struct{}{}
   452  				fmt.Fprintf(w, "%s := %s.Args[%d]\n", arg, v, i)
   453  			}
   454  			continue
   455  		}
   456  		// compound sexpr
   457  		var argname string
   458  		colon := strings.Index(arg, ":")
   459  		openparen := strings.Index(arg, "(")
   460  		if colon >= 0 && openparen >= 0 && colon < openparen {
   461  			// rule-specified name
   462  			argname = arg[:colon]
   463  			arg = arg[colon+1:]
   464  		} else {
   465  			// autogenerated name
   466  			argname = fmt.Sprintf("%s_%d", v, i)
   467  		}
   468  		fmt.Fprintf(w, "%s := %s.Args[%d]\n", argname, v, i)
   469  		if genMatch0(w, arch, arg, argname, m, false, loc) {
   470  			canFail = true
   471  		}
   472  	}
   473  
   474  	if op.argLength == -1 {
   475  		fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, len(args))
   476  		canFail = true
   477  	}
   478  	return canFail
   479  }
   480  
   481  func genResult(w io.Writer, arch arch, result string, loc string) {
   482  	move := false
   483  	if result[0] == '@' {
   484  		// parse @block directive
   485  		s := strings.SplitN(result[1:], " ", 2)
   486  		fmt.Fprintf(w, "b = %s\n", s[0])
   487  		result = s[1]
   488  		move = true
   489  	}
   490  	genResult0(w, arch, result, new(int), true, move, loc)
   491  }
   492  func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move bool, loc string) string {
   493  	// TODO: when generating a constant result, use f.constVal to avoid
   494  	// introducing copies just to clean them up again.
   495  	if result[0] != '(' {
   496  		// variable
   497  		if top {
   498  			// It in not safe in general to move a variable between blocks
   499  			// (and particularly not a phi node).
   500  			// Introduce a copy.
   501  			fmt.Fprintf(w, "v.reset(OpCopy)\n")
   502  			fmt.Fprintf(w, "v.Type = %s.Type\n", result)
   503  			fmt.Fprintf(w, "v.AddArg(%s)\n", result)
   504  		}
   505  		return result
   506  	}
   507  
   508  	op, oparch, typ, auxint, aux, args := parseValue(result, arch, loc)
   509  
   510  	// Find the type of the variable.
   511  	typeOverride := typ != ""
   512  	if typ == "" && op.typ != "" {
   513  		typ = typeName(op.typ)
   514  	}
   515  
   516  	var v string
   517  	if top && !move {
   518  		v = "v"
   519  		fmt.Fprintf(w, "v.reset(Op%s%s)\n", oparch, op.name)
   520  		if typeOverride {
   521  			fmt.Fprintf(w, "v.Type = %s\n", typ)
   522  		}
   523  	} else {
   524  		if typ == "" {
   525  			log.Fatalf("sub-expression %s (op=Op%s%s) must have a type", result, oparch, op.name)
   526  		}
   527  		v = fmt.Sprintf("v%d", *alloc)
   528  		*alloc++
   529  		fmt.Fprintf(w, "%s := b.NewValue0(v.Pos, Op%s%s, %s)\n", v, oparch, op.name, typ)
   530  		if move && top {
   531  			// Rewrite original into a copy
   532  			fmt.Fprintf(w, "v.reset(OpCopy)\n")
   533  			fmt.Fprintf(w, "v.AddArg(%s)\n", v)
   534  		}
   535  	}
   536  
   537  	if auxint != "" {
   538  		fmt.Fprintf(w, "%s.AuxInt = %s\n", v, auxint)
   539  	}
   540  	if aux != "" {
   541  		fmt.Fprintf(w, "%s.Aux = %s\n", v, aux)
   542  	}
   543  	for _, arg := range args {
   544  		x := genResult0(w, arch, arg, alloc, false, move, loc)
   545  		fmt.Fprintf(w, "%s.AddArg(%s)\n", v, x)
   546  	}
   547  
   548  	return v
   549  }
   550  
   551  func split(s string) []string {
   552  	var r []string
   553  
   554  outer:
   555  	for s != "" {
   556  		d := 0               // depth of ({[<
   557  		var open, close byte // opening and closing markers ({[< or )}]>
   558  		nonsp := false       // found a non-space char so far
   559  		for i := 0; i < len(s); i++ {
   560  			switch {
   561  			case d == 0 && s[i] == '(':
   562  				open, close = '(', ')'
   563  				d++
   564  			case d == 0 && s[i] == '<':
   565  				open, close = '<', '>'
   566  				d++
   567  			case d == 0 && s[i] == '[':
   568  				open, close = '[', ']'
   569  				d++
   570  			case d == 0 && s[i] == '{':
   571  				open, close = '{', '}'
   572  				d++
   573  			case d == 0 && (s[i] == ' ' || s[i] == '\t'):
   574  				if nonsp {
   575  					r = append(r, strings.TrimSpace(s[:i]))
   576  					s = s[i:]
   577  					continue outer
   578  				}
   579  			case d > 0 && s[i] == open:
   580  				d++
   581  			case d > 0 && s[i] == close:
   582  				d--
   583  			default:
   584  				nonsp = true
   585  			}
   586  		}
   587  		if d != 0 {
   588  			panic("imbalanced expression: " + s)
   589  		}
   590  		if nonsp {
   591  			r = append(r, strings.TrimSpace(s))
   592  		}
   593  		break
   594  	}
   595  	return r
   596  }
   597  
   598  // isBlock returns true if this op is a block opcode.
   599  func isBlock(name string, arch arch) bool {
   600  	for _, b := range genericBlocks {
   601  		if b.name == name {
   602  			return true
   603  		}
   604  	}
   605  	for _, b := range arch.blocks {
   606  		if b.name == name {
   607  			return true
   608  		}
   609  	}
   610  	return false
   611  }
   612  
   613  // parseValue parses a parenthesized value from a rule.
   614  // The value can be from the match or the result side.
   615  // It returns the op and unparsed strings for typ, auxint, and aux restrictions and for all args.
   616  // oparch is the architecture that op is located in, or "" for generic.
   617  func parseValue(val string, arch arch, loc string) (op opData, oparch string, typ string, auxint string, aux string, args []string) {
   618  	val = val[1 : len(val)-1] // remove ()
   619  
   620  	// Split val up into regions.
   621  	// Split by spaces/tabs, except those contained in (), {}, [], or <>.
   622  	s := split(val)
   623  
   624  	// Extract restrictions and args.
   625  	for _, a := range s[1:] {
   626  		switch a[0] {
   627  		case '<':
   628  			typ = a[1 : len(a)-1] // remove <>
   629  		case '[':
   630  			auxint = a[1 : len(a)-1] // remove []
   631  		case '{':
   632  			aux = a[1 : len(a)-1] // remove {}
   633  		default:
   634  			args = append(args, a)
   635  		}
   636  	}
   637  
   638  	// Resolve the op.
   639  
   640  	// match reports whether x is a good op to select.
   641  	// If strict is true, rule generation might succeed.
   642  	// If strict is false, rule generation has failed,
   643  	// but we're trying to generate a useful error.
   644  	// Doing strict=true then strict=false allows
   645  	// precise op matching while retaining good error messages.
   646  	match := func(x opData, strict bool, archname string) bool {
   647  		if x.name != s[0] {
   648  			return false
   649  		}
   650  		if x.argLength != -1 && int(x.argLength) != len(args) {
   651  			if strict {
   652  				return false
   653  			} else {
   654  				log.Printf("%s: op %s (%s) should have %d args, has %d", loc, s[0], archname, x.argLength, len(args))
   655  			}
   656  		}
   657  		return true
   658  	}
   659  
   660  	for _, x := range genericOps {
   661  		if match(x, true, "generic") {
   662  			op = x
   663  			break
   664  		}
   665  	}
   666  	if arch.name != "generic" {
   667  		for _, x := range arch.ops {
   668  			if match(x, true, arch.name) {
   669  				if op.name != "" {
   670  					log.Fatalf("%s: matches for op %s found in both generic and %s", loc, op.name, arch.name)
   671  				}
   672  				op = x
   673  				oparch = arch.name
   674  				break
   675  			}
   676  		}
   677  	}
   678  
   679  	if op.name == "" {
   680  		// Failed to find the op.
   681  		// Run through everything again with strict=false
   682  		// to generate useful diagnosic messages before failing.
   683  		for _, x := range genericOps {
   684  			match(x, false, "generic")
   685  		}
   686  		for _, x := range arch.ops {
   687  			match(x, false, arch.name)
   688  		}
   689  		log.Fatalf("%s: unknown op %s", loc, s)
   690  	}
   691  
   692  	// Sanity check aux, auxint.
   693  	if auxint != "" {
   694  		switch op.aux {
   695  		case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32", "TypSize":
   696  		default:
   697  			log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
   698  		}
   699  	}
   700  	if aux != "" {
   701  		switch op.aux {
   702  		case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32", "Typ", "TypSize":
   703  		default:
   704  			log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
   705  		}
   706  	}
   707  
   708  	return
   709  }
   710  
   711  func blockName(name string, arch arch) string {
   712  	for _, b := range genericBlocks {
   713  		if b.name == name {
   714  			return "Block" + name
   715  		}
   716  	}
   717  	return "Block" + arch.name + name
   718  }
   719  
   720  // typeName returns the string to use to generate a type.
   721  func typeName(typ string) string {
   722  	if typ[0] == '(' {
   723  		ts := strings.Split(typ[1:len(typ)-1], ",")
   724  		if len(ts) != 2 {
   725  			panic("Tuple expect 2 arguments")
   726  		}
   727  		return "MakeTuple(" + typeName(ts[0]) + ", " + typeName(ts[1]) + ")"
   728  	}
   729  	switch typ {
   730  	case "Flags", "Mem", "Void", "Int128":
   731  		return "Type" + typ
   732  	default:
   733  		return "types." + typ
   734  	}
   735  }
   736  
   737  // unbalanced returns true if there aren't the same number of ( and ) in the string.
   738  func unbalanced(s string) bool {
   739  	var left, right int
   740  	for _, c := range s {
   741  		if c == '(' {
   742  			left++
   743  		}
   744  		if c == ')' {
   745  			right++
   746  		}
   747  	}
   748  	return left != right
   749  }
   750  
   751  // isVariable reports whether s is a single Go alphanumeric identifier.
   752  func isVariable(s string) bool {
   753  	b, err := regexp.MatchString("^[A-Za-z_][A-Za-z_0-9]*$", s)
   754  	if err != nil {
   755  		panic("bad variable regexp")
   756  	}
   757  	return b
   758  }
   759  
   760  // commute returns all equivalent rules to r after applying all possible
   761  // argument swaps to the commutable ops in r.
   762  // Potentially exponential, be careful.
   763  func commute(r string, arch arch) []string {
   764  	match, cond, result := Rule{rule: r}.parse()
   765  	a := commute1(match, varCount(match), arch)
   766  	for i, m := range a {
   767  		if cond != "" {
   768  			m += " && " + cond
   769  		}
   770  		m += " -> " + result
   771  		a[i] = m
   772  	}
   773  	if len(a) == 1 && normalizeWhitespace(r) != normalizeWhitespace(a[0]) {
   774  		fmt.Println(normalizeWhitespace(r))
   775  		fmt.Println(normalizeWhitespace(a[0]))
   776  		panic("commute() is not the identity for noncommuting rule")
   777  	}
   778  	if false && len(a) > 1 {
   779  		fmt.Println(r)
   780  		for _, x := range a {
   781  			fmt.Println("  " + x)
   782  		}
   783  	}
   784  	return a
   785  }
   786  
   787  func commute1(m string, cnt map[string]int, arch arch) []string {
   788  	if m[0] == '<' || m[0] == '[' || m[0] == '{' || isVariable(m) {
   789  		return []string{m}
   790  	}
   791  	// Split up input.
   792  	var prefix string
   793  	colon := strings.Index(m, ":")
   794  	if colon >= 0 && isVariable(m[:colon]) {
   795  		prefix = m[:colon+1]
   796  		m = m[colon+1:]
   797  	}
   798  	if m[0] != '(' || m[len(m)-1] != ')' {
   799  		panic("non-compound expr in commute1: " + m)
   800  	}
   801  	s := split(m[1 : len(m)-1])
   802  	op := s[0]
   803  
   804  	// Figure out if the op is commutative or not.
   805  	commutative := false
   806  	for _, x := range genericOps {
   807  		if op == x.name {
   808  			if x.commutative {
   809  				commutative = true
   810  			}
   811  			break
   812  		}
   813  	}
   814  	if arch.name != "generic" {
   815  		for _, x := range arch.ops {
   816  			if op == x.name {
   817  				if x.commutative {
   818  					commutative = true
   819  				}
   820  				break
   821  			}
   822  		}
   823  	}
   824  	var idx0, idx1 int
   825  	if commutative {
   826  		// Find indexes of two args we can swap.
   827  		for i, arg := range s {
   828  			if i == 0 || arg[0] == '<' || arg[0] == '[' || arg[0] == '{' {
   829  				continue
   830  			}
   831  			if idx0 == 0 {
   832  				idx0 = i
   833  				continue
   834  			}
   835  			if idx1 == 0 {
   836  				idx1 = i
   837  				break
   838  			}
   839  		}
   840  		if idx1 == 0 {
   841  			panic("couldn't find first two args of commutative op " + s[0])
   842  		}
   843  		if cnt[s[idx0]] == 1 && cnt[s[idx1]] == 1 || s[idx0] == s[idx1] && cnt[s[idx0]] == 2 {
   844  			// When we have (Add x y) with no ther uses of x and y in the matching rule,
   845  			// then we can skip the commutative match (Add y x).
   846  			commutative = false
   847  		}
   848  	}
   849  
   850  	// Recursively commute arguments.
   851  	a := make([][]string, len(s))
   852  	for i, arg := range s {
   853  		a[i] = commute1(arg, cnt, arch)
   854  	}
   855  
   856  	// Choose all possibilities from all args.
   857  	r := crossProduct(a)
   858  
   859  	// If commutative, do that again with its two args reversed.
   860  	if commutative {
   861  		a[idx0], a[idx1] = a[idx1], a[idx0]
   862  		r = append(r, crossProduct(a)...)
   863  	}
   864  
   865  	// Construct result.
   866  	for i, x := range r {
   867  		r[i] = prefix + "(" + x + ")"
   868  	}
   869  	return r
   870  }
   871  
   872  // varCount returns a map which counts the number of occurrences of
   873  // Value variables in m.
   874  func varCount(m string) map[string]int {
   875  	cnt := map[string]int{}
   876  	varCount1(m, cnt)
   877  	return cnt
   878  }
   879  func varCount1(m string, cnt map[string]int) {
   880  	if m[0] == '<' || m[0] == '[' || m[0] == '{' {
   881  		return
   882  	}
   883  	if isVariable(m) {
   884  		cnt[m]++
   885  		return
   886  	}
   887  	// Split up input.
   888  	colon := strings.Index(m, ":")
   889  	if colon >= 0 && isVariable(m[:colon]) {
   890  		cnt[m[:colon]]++
   891  		m = m[colon+1:]
   892  	}
   893  	if m[0] != '(' || m[len(m)-1] != ')' {
   894  		panic("non-compound expr in commute1: " + m)
   895  	}
   896  	s := split(m[1 : len(m)-1])
   897  	for _, arg := range s[1:] {
   898  		varCount1(arg, cnt)
   899  	}
   900  }
   901  
   902  // crossProduct returns all possible values
   903  // x[0][i] + " " + x[1][j] + " " + ... + " " + x[len(x)-1][k]
   904  // for all valid values of i, j, ..., k.
   905  func crossProduct(x [][]string) []string {
   906  	if len(x) == 1 {
   907  		return x[0]
   908  	}
   909  	var r []string
   910  	for _, tail := range crossProduct(x[1:]) {
   911  		for _, first := range x[0] {
   912  			r = append(r, first+" "+tail)
   913  		}
   914  	}
   915  	return r
   916  }
   917  
   918  // normalizeWhitespace replaces 2+ whitespace sequences with a single space.
   919  func normalizeWhitespace(x string) string {
   920  	x = strings.Join(strings.Fields(x), " ")
   921  	x = strings.Replace(x, "( ", "(", -1)
   922  	x = strings.Replace(x, " )", ")", -1)
   923  	return x
   924  }