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