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