github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/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  
   663  	// Resolve the op.
   664  	var s string
   665  	s, typ, auxint, aux, args = extract(val)
   666  
   667  	// match reports whether x is a good op to select.
   668  	// If strict is true, rule generation might succeed.
   669  	// If strict is false, rule generation has failed,
   670  	// but we're trying to generate a useful error.
   671  	// Doing strict=true then strict=false allows
   672  	// precise op matching while retaining good error messages.
   673  	match := func(x opData, strict bool, archname string) bool {
   674  		if x.name != s {
   675  			return false
   676  		}
   677  		if x.argLength != -1 && int(x.argLength) != len(args) {
   678  			if strict {
   679  				return false
   680  			} else {
   681  				log.Printf("%s: op %s (%s) should have %d args, has %d", loc, s, archname, x.argLength, len(args))
   682  			}
   683  		}
   684  		return true
   685  	}
   686  
   687  	for _, x := range genericOps {
   688  		if match(x, true, "generic") {
   689  			op = x
   690  			break
   691  		}
   692  	}
   693  	if arch.name != "generic" {
   694  		for _, x := range arch.ops {
   695  			if match(x, true, arch.name) {
   696  				if op.name != "" {
   697  					log.Fatalf("%s: matches for op %s found in both generic and %s", loc, op.name, arch.name)
   698  				}
   699  				op = x
   700  				oparch = arch.name
   701  				break
   702  			}
   703  		}
   704  	}
   705  
   706  	if op.name == "" {
   707  		// Failed to find the op.
   708  		// Run through everything again with strict=false
   709  		// to generate useful diagnosic messages before failing.
   710  		for _, x := range genericOps {
   711  			match(x, false, "generic")
   712  		}
   713  		for _, x := range arch.ops {
   714  			match(x, false, arch.name)
   715  		}
   716  		log.Fatalf("%s: unknown op %s", loc, s)
   717  	}
   718  
   719  	// Sanity check aux, auxint.
   720  	if auxint != "" {
   721  		switch op.aux {
   722  		case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32", "TypSize":
   723  		default:
   724  			log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
   725  		}
   726  	}
   727  	if aux != "" {
   728  		switch op.aux {
   729  		case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32", "Typ", "TypSize":
   730  		default:
   731  			log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
   732  		}
   733  	}
   734  
   735  	return
   736  }
   737  
   738  func blockName(name string, arch arch) string {
   739  	for _, b := range genericBlocks {
   740  		if b.name == name {
   741  			return "Block" + name
   742  		}
   743  	}
   744  	return "Block" + arch.name + name
   745  }
   746  
   747  // typeName returns the string to use to generate a type.
   748  func typeName(typ string) string {
   749  	if typ[0] == '(' {
   750  		ts := strings.Split(typ[1:len(typ)-1], ",")
   751  		if len(ts) != 2 {
   752  			panic("Tuple expect 2 arguments")
   753  		}
   754  		return "types.NewTuple(" + typeName(ts[0]) + ", " + typeName(ts[1]) + ")"
   755  	}
   756  	switch typ {
   757  	case "Flags", "Mem", "Void", "Int128":
   758  		return "types.Type" + typ
   759  	default:
   760  		return "typ." + typ
   761  	}
   762  }
   763  
   764  // unbalanced returns true if there aren't the same number of ( and ) in the string.
   765  func unbalanced(s string) bool {
   766  	var left, right int
   767  	for _, c := range s {
   768  		if c == '(' {
   769  			left++
   770  		}
   771  		if c == ')' {
   772  			right++
   773  		}
   774  	}
   775  	return left != right
   776  }
   777  
   778  // isVariable reports whether s is a single Go alphanumeric identifier.
   779  func isVariable(s string) bool {
   780  	b, err := regexp.MatchString("^[A-Za-z_][A-Za-z_0-9]*$", s)
   781  	if err != nil {
   782  		panic("bad variable regexp")
   783  	}
   784  	return b
   785  }
   786  
   787  // commute returns all equivalent rules to r after applying all possible
   788  // argument swaps to the commutable ops in r.
   789  // Potentially exponential, be careful.
   790  func commute(r string, arch arch) []string {
   791  	match, cond, result := Rule{rule: r}.parse()
   792  	a := commute1(match, varCount(match), arch)
   793  	for i, m := range a {
   794  		if cond != "" {
   795  			m += " && " + cond
   796  		}
   797  		m += " -> " + result
   798  		a[i] = m
   799  	}
   800  	if len(a) == 1 && normalizeWhitespace(r) != normalizeWhitespace(a[0]) {
   801  		fmt.Println(normalizeWhitespace(r))
   802  		fmt.Println(normalizeWhitespace(a[0]))
   803  		panic("commute() is not the identity for noncommuting rule")
   804  	}
   805  	if false && len(a) > 1 {
   806  		fmt.Println(r)
   807  		for _, x := range a {
   808  			fmt.Println("  " + x)
   809  		}
   810  	}
   811  	return a
   812  }
   813  
   814  func commute1(m string, cnt map[string]int, arch arch) []string {
   815  	if m[0] == '<' || m[0] == '[' || m[0] == '{' || isVariable(m) {
   816  		return []string{m}
   817  	}
   818  	// Split up input.
   819  	var prefix string
   820  	colon := strings.Index(m, ":")
   821  	if colon >= 0 && isVariable(m[:colon]) {
   822  		prefix = m[:colon+1]
   823  		m = m[colon+1:]
   824  	}
   825  	if m[0] != '(' || m[len(m)-1] != ')' {
   826  		panic("non-compound expr in commute1: " + m)
   827  	}
   828  	s := split(m[1 : len(m)-1])
   829  	op := s[0]
   830  
   831  	// Figure out if the op is commutative or not.
   832  	commutative := false
   833  	for _, x := range genericOps {
   834  		if op == x.name {
   835  			if x.commutative {
   836  				commutative = true
   837  			}
   838  			break
   839  		}
   840  	}
   841  	if arch.name != "generic" {
   842  		for _, x := range arch.ops {
   843  			if op == x.name {
   844  				if x.commutative {
   845  					commutative = true
   846  				}
   847  				break
   848  			}
   849  		}
   850  	}
   851  	var idx0, idx1 int
   852  	if commutative {
   853  		// Find indexes of two args we can swap.
   854  		for i, arg := range s {
   855  			if i == 0 || arg[0] == '<' || arg[0] == '[' || arg[0] == '{' {
   856  				continue
   857  			}
   858  			if idx0 == 0 {
   859  				idx0 = i
   860  				continue
   861  			}
   862  			if idx1 == 0 {
   863  				idx1 = i
   864  				break
   865  			}
   866  		}
   867  		if idx1 == 0 {
   868  			panic("couldn't find first two args of commutative op " + s[0])
   869  		}
   870  		if cnt[s[idx0]] == 1 && cnt[s[idx1]] == 1 || s[idx0] == s[idx1] && cnt[s[idx0]] == 2 {
   871  			// When we have (Add x y) with no ther uses of x and y in the matching rule,
   872  			// then we can skip the commutative match (Add y x).
   873  			commutative = false
   874  		}
   875  	}
   876  
   877  	// Recursively commute arguments.
   878  	a := make([][]string, len(s))
   879  	for i, arg := range s {
   880  		a[i] = commute1(arg, cnt, arch)
   881  	}
   882  
   883  	// Choose all possibilities from all args.
   884  	r := crossProduct(a)
   885  
   886  	// If commutative, do that again with its two args reversed.
   887  	if commutative {
   888  		a[idx0], a[idx1] = a[idx1], a[idx0]
   889  		r = append(r, crossProduct(a)...)
   890  	}
   891  
   892  	// Construct result.
   893  	for i, x := range r {
   894  		r[i] = prefix + "(" + x + ")"
   895  	}
   896  	return r
   897  }
   898  
   899  // varCount returns a map which counts the number of occurrences of
   900  // Value variables in m.
   901  func varCount(m string) map[string]int {
   902  	cnt := map[string]int{}
   903  	varCount1(m, cnt)
   904  	return cnt
   905  }
   906  func varCount1(m string, cnt map[string]int) {
   907  	if m[0] == '<' || m[0] == '[' || m[0] == '{' {
   908  		return
   909  	}
   910  	if isVariable(m) {
   911  		cnt[m]++
   912  		return
   913  	}
   914  	// Split up input.
   915  	colon := strings.Index(m, ":")
   916  	if colon >= 0 && isVariable(m[:colon]) {
   917  		cnt[m[:colon]]++
   918  		m = m[colon+1:]
   919  	}
   920  	if m[0] != '(' || m[len(m)-1] != ')' {
   921  		panic("non-compound expr in commute1: " + m)
   922  	}
   923  	s := split(m[1 : len(m)-1])
   924  	for _, arg := range s[1:] {
   925  		varCount1(arg, cnt)
   926  	}
   927  }
   928  
   929  // crossProduct returns all possible values
   930  // x[0][i] + " " + x[1][j] + " " + ... + " " + x[len(x)-1][k]
   931  // for all valid values of i, j, ..., k.
   932  func crossProduct(x [][]string) []string {
   933  	if len(x) == 1 {
   934  		return x[0]
   935  	}
   936  	var r []string
   937  	for _, tail := range crossProduct(x[1:]) {
   938  		for _, first := range x[0] {
   939  			r = append(r, first+" "+tail)
   940  		}
   941  	}
   942  	return r
   943  }
   944  
   945  // normalizeWhitespace replaces 2+ whitespace sequences with a single space.
   946  func normalizeWhitespace(x string) string {
   947  	x = strings.Join(strings.Fields(x), " ")
   948  	x = strings.Replace(x, "( ", "(", -1)
   949  	x = strings.Replace(x, " )", ")", -1)
   950  	return x
   951  }