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