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