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// This program generates Go code that applies rewrite rules to a Value.
6// The generated code implements a function of type func (v *Value) bool
7// which reports whether if did something.
8// Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html
9
10package main
11
12import (
13	"bufio"
14	"bytes"
15	"flag"
16	"fmt"
17	"go/ast"
18	"go/format"
19	"go/parser"
20	"go/printer"
21	"go/token"
22	"io"
23	"log"
24	"os"
25	"path"
26	"regexp"
27	"sort"
28	"strconv"
29	"strings"
30
31	"golang.org/x/tools/go/ast/astutil"
32)
33
34// rule syntax:
35//  sexpr [&& extra conditions] => [@block] sexpr
36//
37// sexpr are s-expressions (lisp-like parenthesized groupings)
38// sexpr ::= [variable:](opcode sexpr*)
39//         | variable
40//         | <type>
41//         | [auxint]
42//         | {aux}
43//
44// aux      ::= variable | {code}
45// type     ::= variable | {code}
46// variable ::= some token
47// opcode   ::= one of the opcodes from the *Ops.go files
48
49// special rules: trailing ellipsis "..." (in the outermost sexpr?) must match on both sides of a rule.
50//                trailing three underscore "___" in the outermost match sexpr indicate the presence of
51//                   extra ignored args that need not appear in the replacement
52
53// extra conditions is just a chunk of Go that evaluates to a boolean. It may use
54// variables declared in the matching tsexpr. The variable "v" is predefined to be
55// the value matched by the entire rule.
56
57// If multiple rules match, the first one in file order is selected.
58
59var (
60	genLog  = flag.Bool("log", false, "generate code that logs; for debugging only")
61	addLine = flag.Bool("line", false, "add line number comment to generated rules; for debugging only")
62)
63
64type Rule struct {
65	Rule string
66	Loc  string // file name & line number
67}
68
69func (r Rule) String() string {
70	return fmt.Sprintf("rule %q at %s", r.Rule, r.Loc)
71}
72
73func normalizeSpaces(s string) string {
74	return strings.Join(strings.Fields(strings.TrimSpace(s)), " ")
75}
76
77// parse returns the matching part of the rule, additional conditions, and the result.
78func (r Rule) parse() (match, cond, result string) {
79	s := strings.Split(r.Rule, "=>")
80	match = normalizeSpaces(s[0])
81	result = normalizeSpaces(s[1])
82	cond = ""
83	if i := strings.Index(match, "&&"); i >= 0 {
84		cond = normalizeSpaces(match[i+2:])
85		match = normalizeSpaces(match[:i])
86	}
87	return match, cond, result
88}
89
90func genRules(arch arch)          { genRulesSuffix(arch, "") }
91func genSplitLoadRules(arch arch) { genRulesSuffix(arch, "splitload") }
92func genLateLowerRules(arch arch) { genRulesSuffix(arch, "latelower") }
93
94func genRulesSuffix(arch arch, suff string) {
95	// Open input file.
96	text, err := os.Open(arch.name + suff + ".rules")
97	if err != nil {
98		if suff == "" {
99			// All architectures must have a plain rules file.
100			log.Fatalf("can't read rule file: %v", err)
101		}
102		// Some architectures have bonus rules files that others don't share. That's fine.
103		return
104	}
105
106	// oprules contains a list of rules for each block and opcode
107	blockrules := map[string][]Rule{}
108	oprules := map[string][]Rule{}
109
110	// read rule file
111	scanner := bufio.NewScanner(text)
112	rule := ""
113	var lineno int
114	var ruleLineno int // line number of "=>"
115	for scanner.Scan() {
116		lineno++
117		line := scanner.Text()
118		if i := strings.Index(line, "//"); i >= 0 {
119			// Remove comments. Note that this isn't string safe, so
120			// it will truncate lines with // inside strings. Oh well.
121			line = line[:i]
122		}
123		rule += " " + line
124		rule = strings.TrimSpace(rule)
125		if rule == "" {
126			continue
127		}
128		if !strings.Contains(rule, "=>") {
129			continue
130		}
131		if ruleLineno == 0 {
132			ruleLineno = lineno
133		}
134		if strings.HasSuffix(rule, "=>") {
135			continue // continue on the next line
136		}
137		if n := balance(rule); n > 0 {
138			continue // open parentheses remain, continue on the next line
139		} else if n < 0 {
140			break // continuing the line can't help, and it will only make errors worse
141		}
142
143		loc := fmt.Sprintf("%s%s.rules:%d", arch.name, suff, ruleLineno)
144		for _, rule2 := range expandOr(rule) {
145			r := Rule{Rule: rule2, Loc: loc}
146			if rawop := strings.Split(rule2, " ")[0][1:]; isBlock(rawop, arch) {
147				blockrules[rawop] = append(blockrules[rawop], r)
148				continue
149			}
150			// Do fancier value op matching.
151			match, _, _ := r.parse()
152			op, oparch, _, _, _, _ := parseValue(match, arch, loc)
153			opname := fmt.Sprintf("Op%s%s", oparch, op.name)
154			oprules[opname] = append(oprules[opname], r)
155		}
156		rule = ""
157		ruleLineno = 0
158	}
159	if err := scanner.Err(); err != nil {
160		log.Fatalf("scanner failed: %v\n", err)
161	}
162	if balance(rule) != 0 {
163		log.Fatalf("%s.rules:%d: unbalanced rule: %v\n", arch.name, lineno, rule)
164	}
165
166	// Order all the ops.
167	var ops []string
168	for op := range oprules {
169		ops = append(ops, op)
170	}
171	sort.Strings(ops)
172
173	genFile := &File{Arch: arch, Suffix: suff}
174	// Main rewrite routine is a switch on v.Op.
175	fn := &Func{Kind: "Value", ArgLen: -1}
176
177	sw := &Switch{Expr: exprf("v.Op")}
178	for _, op := range ops {
179		eop, ok := parseEllipsisRules(oprules[op], arch)
180		if ok {
181			if strings.Contains(oprules[op][0].Rule, "=>") && opByName(arch, op).aux != opByName(arch, eop).aux {
182				panic(fmt.Sprintf("can't use ... for ops that have different aux types: %s and %s", op, eop))
183			}
184			swc := &Case{Expr: exprf("%s", op)}
185			swc.add(stmtf("v.Op = %s", eop))
186			swc.add(stmtf("return true"))
187			sw.add(swc)
188			continue
189		}
190
191		swc := &Case{Expr: exprf("%s", op)}
192		swc.add(stmtf("return rewriteValue%s%s_%s(v)", arch.name, suff, op))
193		sw.add(swc)
194	}
195	if len(sw.List) > 0 { // skip if empty
196		fn.add(sw)
197	}
198	fn.add(stmtf("return false"))
199	genFile.add(fn)
200
201	// Generate a routine per op. Note that we don't make one giant routine
202	// because it is too big for some compilers.
203	for _, op := range ops {
204		rules := oprules[op]
205		_, ok := parseEllipsisRules(oprules[op], arch)
206		if ok {
207			continue
208		}
209
210		// rr is kept between iterations, so that each rule can check
211		// that the previous rule wasn't unconditional.
212		var rr *RuleRewrite
213		fn := &Func{
214			Kind:   "Value",
215			Suffix: fmt.Sprintf("_%s", op),
216			ArgLen: opByName(arch, op).argLength,
217		}
218		fn.add(declReserved("b", "v.Block"))
219		fn.add(declReserved("config", "b.Func.Config"))
220		fn.add(declReserved("fe", "b.Func.fe"))
221		fn.add(declReserved("typ", "&b.Func.Config.Types"))
222		for _, rule := range rules {
223			if rr != nil && !rr.CanFail {
224				log.Fatalf("unconditional rule %s is followed by other rules", rr.Match)
225			}
226			rr = &RuleRewrite{Loc: rule.Loc}
227			rr.Match, rr.Cond, rr.Result = rule.parse()
228			pos, _ := genMatch(rr, arch, rr.Match, fn.ArgLen >= 0)
229			if pos == "" {
230				pos = "v.Pos"
231			}
232			if rr.Cond != "" {
233				rr.add(breakf("!(%s)", rr.Cond))
234			}
235			genResult(rr, arch, rr.Result, pos)
236			if *genLog {
237				rr.add(stmtf("logRule(%q)", rule.Loc))
238			}
239			fn.add(rr)
240		}
241		if rr.CanFail {
242			fn.add(stmtf("return false"))
243		}
244		genFile.add(fn)
245	}
246
247	// Generate block rewrite function. There are only a few block types
248	// so we can make this one function with a switch.
249	fn = &Func{Kind: "Block"}
250	fn.add(declReserved("config", "b.Func.Config"))
251	fn.add(declReserved("typ", "&b.Func.Config.Types"))
252
253	sw = &Switch{Expr: exprf("b.Kind")}
254	ops = ops[:0]
255	for op := range blockrules {
256		ops = append(ops, op)
257	}
258	sort.Strings(ops)
259	for _, op := range ops {
260		name, data := getBlockInfo(op, arch)
261		swc := &Case{Expr: exprf("%s", name)}
262		for _, rule := range blockrules[op] {
263			swc.add(genBlockRewrite(rule, arch, data))
264		}
265		sw.add(swc)
266	}
267	if len(sw.List) > 0 { // skip if empty
268		fn.add(sw)
269	}
270	fn.add(stmtf("return false"))
271	genFile.add(fn)
272
273	// Remove unused imports and variables.
274	buf := new(bytes.Buffer)
275	fprint(buf, genFile)
276	fset := token.NewFileSet()
277	file, err := parser.ParseFile(fset, "", buf, parser.ParseComments)
278	if err != nil {
279		filename := fmt.Sprintf("%s_broken.go", arch.name)
280		if err := os.WriteFile(filename, buf.Bytes(), 0644); err != nil {
281			log.Printf("failed to dump broken code to %s: %v", filename, err)
282		} else {
283			log.Printf("dumped broken code to %s", filename)
284		}
285		log.Fatalf("failed to parse generated code for arch %s: %v", arch.name, err)
286	}
287	tfile := fset.File(file.Pos())
288
289	// First, use unusedInspector to find the unused declarations by their
290	// start position.
291	u := unusedInspector{unused: make(map[token.Pos]bool)}
292	u.node(file)
293
294	// Then, delete said nodes via astutil.Apply.
295	pre := func(c *astutil.Cursor) bool {
296		node := c.Node()
297		if node == nil {
298			return true
299		}
300		if u.unused[node.Pos()] {
301			c.Delete()
302			// Unused imports and declarations use exactly
303			// one line. Prevent leaving an empty line.
304			tfile.MergeLine(tfile.Position(node.Pos()).Line)
305			return false
306		}
307		return true
308	}
309	post := func(c *astutil.Cursor) bool {
310		switch node := c.Node().(type) {
311		case *ast.GenDecl:
312			if len(node.Specs) == 0 {
313				// Don't leave a broken or empty GenDecl behind,
314				// such as "import ()".
315				c.Delete()
316			}
317		}
318		return true
319	}
320	file = astutil.Apply(file, pre, post).(*ast.File)
321
322	// Write the well-formatted source to file
323	f, err := os.Create("../rewrite" + arch.name + suff + ".go")
324	if err != nil {
325		log.Fatalf("can't write output: %v", err)
326	}
327	defer f.Close()
328	// gofmt result; use a buffered writer, as otherwise go/format spends
329	// far too much time in syscalls.
330	bw := bufio.NewWriter(f)
331	if err := format.Node(bw, fset, file); err != nil {
332		log.Fatalf("can't format output: %v", err)
333	}
334	if err := bw.Flush(); err != nil {
335		log.Fatalf("can't write output: %v", err)
336	}
337	if err := f.Close(); err != nil {
338		log.Fatalf("can't write output: %v", err)
339	}
340}
341
342// unusedInspector can be used to detect unused variables and imports in an
343// ast.Node via its node method. The result is available in the "unused" map.
344//
345// note that unusedInspector is lazy and best-effort; it only supports the node
346// types and patterns used by the rulegen program.
347type unusedInspector struct {
348	// scope is the current scope, which can never be nil when a declaration
349	// is encountered. That is, the unusedInspector.node entrypoint should
350	// generally be an entire file or block.
351	scope *scope
352
353	// unused is the resulting set of unused declared names, indexed by the
354	// starting position of the node that declared the name.
355	unused map[token.Pos]bool
356
357	// defining is the object currently being defined; this is useful so
358	// that if "foo := bar" is unused and removed, we can then detect if
359	// "bar" becomes unused as well.
360	defining *object
361}
362
363// scoped opens a new scope when called, and returns a function which closes
364// that same scope. When a scope is closed, unused variables are recorded.
365func (u *unusedInspector) scoped() func() {
366	outer := u.scope
367	u.scope = &scope{outer: outer, objects: map[string]*object{}}
368	return func() {
369		for anyUnused := true; anyUnused; {
370			anyUnused = false
371			for _, obj := range u.scope.objects {
372				if obj.numUses > 0 {
373					continue
374				}
375				u.unused[obj.pos] = true
376				for _, used := range obj.used {
377					if used.numUses--; used.numUses == 0 {
378						anyUnused = true
379					}
380				}
381				// We've decremented numUses for each of the
382				// objects in used. Zero this slice too, to keep
383				// everything consistent.
384				obj.used = nil
385			}
386		}
387		u.scope = outer
388	}
389}
390
391func (u *unusedInspector) exprs(list []ast.Expr) {
392	for _, x := range list {
393		u.node(x)
394	}
395}
396
397func (u *unusedInspector) node(node ast.Node) {
398	switch node := node.(type) {
399	case *ast.File:
400		defer u.scoped()()
401		for _, decl := range node.Decls {
402			u.node(decl)
403		}
404	case *ast.GenDecl:
405		for _, spec := range node.Specs {
406			u.node(spec)
407		}
408	case *ast.ImportSpec:
409		impPath, _ := strconv.Unquote(node.Path.Value)
410		name := path.Base(impPath)
411		u.scope.objects[name] = &object{
412			name: name,
413			pos:  node.Pos(),
414		}
415	case *ast.FuncDecl:
416		u.node(node.Type)
417		if node.Body != nil {
418			u.node(node.Body)
419		}
420	case *ast.FuncType:
421		if node.Params != nil {
422			u.node(node.Params)
423		}
424		if node.Results != nil {
425			u.node(node.Results)
426		}
427	case *ast.FieldList:
428		for _, field := range node.List {
429			u.node(field)
430		}
431	case *ast.Field:
432		u.node(node.Type)
433
434	// statements
435
436	case *ast.BlockStmt:
437		defer u.scoped()()
438		for _, stmt := range node.List {
439			u.node(stmt)
440		}
441	case *ast.DeclStmt:
442		u.node(node.Decl)
443	case *ast.IfStmt:
444		if node.Init != nil {
445			u.node(node.Init)
446		}
447		u.node(node.Cond)
448		u.node(node.Body)
449		if node.Else != nil {
450			u.node(node.Else)
451		}
452	case *ast.ForStmt:
453		if node.Init != nil {
454			u.node(node.Init)
455		}
456		if node.Cond != nil {
457			u.node(node.Cond)
458		}
459		if node.Post != nil {
460			u.node(node.Post)
461		}
462		u.node(node.Body)
463	case *ast.SwitchStmt:
464		if node.Init != nil {
465			u.node(node.Init)
466		}
467		if node.Tag != nil {
468			u.node(node.Tag)
469		}
470		u.node(node.Body)
471	case *ast.CaseClause:
472		u.exprs(node.List)
473		defer u.scoped()()
474		for _, stmt := range node.Body {
475			u.node(stmt)
476		}
477	case *ast.BranchStmt:
478	case *ast.ExprStmt:
479		u.node(node.X)
480	case *ast.AssignStmt:
481		if node.Tok != token.DEFINE {
482			u.exprs(node.Rhs)
483			u.exprs(node.Lhs)
484			break
485		}
486		lhs := node.Lhs
487		if len(lhs) == 2 && lhs[1].(*ast.Ident).Name == "_" {
488			lhs = lhs[:1]
489		}
490		if len(lhs) != 1 {
491			panic("no support for := with multiple names")
492		}
493
494		name := lhs[0].(*ast.Ident)
495		obj := &object{
496			name: name.Name,
497			pos:  name.NamePos,
498		}
499
500		old := u.defining
501		u.defining = obj
502		u.exprs(node.Rhs)
503		u.defining = old
504
505		u.scope.objects[name.Name] = obj
506	case *ast.ReturnStmt:
507		u.exprs(node.Results)
508	case *ast.IncDecStmt:
509		u.node(node.X)
510
511	// expressions
512
513	case *ast.CallExpr:
514		u.node(node.Fun)
515		u.exprs(node.Args)
516	case *ast.SelectorExpr:
517		u.node(node.X)
518	case *ast.UnaryExpr:
519		u.node(node.X)
520	case *ast.BinaryExpr:
521		u.node(node.X)
522		u.node(node.Y)
523	case *ast.StarExpr:
524		u.node(node.X)
525	case *ast.ParenExpr:
526		u.node(node.X)
527	case *ast.IndexExpr:
528		u.node(node.X)
529		u.node(node.Index)
530	case *ast.TypeAssertExpr:
531		u.node(node.X)
532		u.node(node.Type)
533	case *ast.Ident:
534		if obj := u.scope.Lookup(node.Name); obj != nil {
535			obj.numUses++
536			if u.defining != nil {
537				u.defining.used = append(u.defining.used, obj)
538			}
539		}
540	case *ast.BasicLit:
541	case *ast.ValueSpec:
542		u.exprs(node.Values)
543	default:
544		panic(fmt.Sprintf("unhandled node: %T", node))
545	}
546}
547
548// scope keeps track of a certain scope and its declared names, as well as the
549// outer (parent) scope.
550type scope struct {
551	outer   *scope             // can be nil, if this is the top-level scope
552	objects map[string]*object // indexed by each declared name
553}
554
555func (s *scope) Lookup(name string) *object {
556	if obj := s.objects[name]; obj != nil {
557		return obj
558	}
559	if s.outer == nil {
560		return nil
561	}
562	return s.outer.Lookup(name)
563}
564
565// object keeps track of a declared name, such as a variable or import.
566type object struct {
567	name string
568	pos  token.Pos // start position of the node declaring the object
569
570	numUses int       // number of times this object is used
571	used    []*object // objects that its declaration makes use of
572}
573
574func fprint(w io.Writer, n Node) {
575	switch n := n.(type) {
576	case *File:
577		file := n
578		seenRewrite := make(map[[3]string]string)
579		fmt.Fprintf(w, "// Code generated from _gen/%s%s.rules using 'go generate'; DO NOT EDIT.\n", n.Arch.name, n.Suffix)
580		fmt.Fprintf(w, "\npackage ssa\n")
581		for _, path := range append([]string{
582			"fmt",
583			"internal/buildcfg",
584			"math",
585			"cmd/internal/obj",
586			"cmd/compile/internal/base",
587			"cmd/compile/internal/types",
588			"cmd/compile/internal/ir",
589		}, n.Arch.imports...) {
590			fmt.Fprintf(w, "import %q\n", path)
591		}
592		for _, f := range n.List {
593			f := f.(*Func)
594			fmt.Fprintf(w, "func rewrite%s%s%s%s(", f.Kind, n.Arch.name, n.Suffix, f.Suffix)
595			fmt.Fprintf(w, "%c *%s) bool {\n", strings.ToLower(f.Kind)[0], f.Kind)
596			if f.Kind == "Value" && f.ArgLen > 0 {
597				for i := f.ArgLen - 1; i >= 0; i-- {
598					fmt.Fprintf(w, "v_%d := v.Args[%d]\n", i, i)
599				}
600			}
601			for _, n := range f.List {
602				fprint(w, n)
603
604				if rr, ok := n.(*RuleRewrite); ok {
605					k := [3]string{
606						normalizeMatch(rr.Match, file.Arch),
607						normalizeWhitespace(rr.Cond),
608						normalizeWhitespace(rr.Result),
609					}
610					if prev, ok := seenRewrite[k]; ok {
611						log.Fatalf("duplicate rule %s, previously seen at %s\n", rr.Loc, prev)
612					}
613					seenRewrite[k] = rr.Loc
614				}
615			}
616			fmt.Fprintf(w, "}\n")
617		}
618	case *Switch:
619		fmt.Fprintf(w, "switch ")
620		fprint(w, n.Expr)
621		fmt.Fprintf(w, " {\n")
622		for _, n := range n.List {
623			fprint(w, n)
624		}
625		fmt.Fprintf(w, "}\n")
626	case *Case:
627		fmt.Fprintf(w, "case ")
628		fprint(w, n.Expr)
629		fmt.Fprintf(w, ":\n")
630		for _, n := range n.List {
631			fprint(w, n)
632		}
633	case *RuleRewrite:
634		if *addLine {
635			fmt.Fprintf(w, "// %s\n", n.Loc)
636		}
637		fmt.Fprintf(w, "// match: %s\n", n.Match)
638		if n.Cond != "" {
639			fmt.Fprintf(w, "// cond: %s\n", n.Cond)
640		}
641		fmt.Fprintf(w, "// result: %s\n", n.Result)
642		fmt.Fprintf(w, "for %s {\n", n.Check)
643		nCommutative := 0
644		for _, n := range n.List {
645			if b, ok := n.(*CondBreak); ok {
646				b.InsideCommuteLoop = nCommutative > 0
647			}
648			fprint(w, n)
649			if loop, ok := n.(StartCommuteLoop); ok {
650				if nCommutative != loop.Depth {
651					panic("mismatch commute loop depth")
652				}
653				nCommutative++
654			}
655		}
656		fmt.Fprintf(w, "return true\n")
657		for i := 0; i < nCommutative; i++ {
658			fmt.Fprintln(w, "}")
659		}
660		if n.CommuteDepth > 0 && n.CanFail {
661			fmt.Fprint(w, "break\n")
662		}
663		fmt.Fprintf(w, "}\n")
664	case *Declare:
665		fmt.Fprintf(w, "%s := ", n.Name)
666		fprint(w, n.Value)
667		fmt.Fprintln(w)
668	case *CondBreak:
669		fmt.Fprintf(w, "if ")
670		fprint(w, n.Cond)
671		fmt.Fprintf(w, " {\n")
672		if n.InsideCommuteLoop {
673			fmt.Fprintf(w, "continue")
674		} else {
675			fmt.Fprintf(w, "break")
676		}
677		fmt.Fprintf(w, "\n}\n")
678	case ast.Node:
679		printConfig.Fprint(w, emptyFset, n)
680		if _, ok := n.(ast.Stmt); ok {
681			fmt.Fprintln(w)
682		}
683	case StartCommuteLoop:
684		fmt.Fprintf(w, "for _i%[1]d := 0; _i%[1]d <= 1; _i%[1]d, %[2]s_0, %[2]s_1 = _i%[1]d + 1, %[2]s_1, %[2]s_0 {\n", n.Depth, n.V)
685	default:
686		log.Fatalf("cannot print %T", n)
687	}
688}
689
690var printConfig = printer.Config{
691	Mode: printer.RawFormat, // we use go/format later, so skip work here
692}
693
694var emptyFset = token.NewFileSet()
695
696// Node can be a Statement or an ast.Expr.
697type Node interface{}
698
699// Statement can be one of our high-level statement struct types, or an
700// ast.Stmt under some limited circumstances.
701type Statement interface{}
702
703// BodyBase is shared by all of our statement pseudo-node types which can
704// contain other statements.
705type BodyBase struct {
706	List    []Statement
707	CanFail bool
708}
709
710func (w *BodyBase) add(node Statement) {
711	var last Statement
712	if len(w.List) > 0 {
713		last = w.List[len(w.List)-1]
714	}
715	if node, ok := node.(*CondBreak); ok {
716		w.CanFail = true
717		if last, ok := last.(*CondBreak); ok {
718			// Add to the previous "if <cond> { break }" via a
719			// logical OR, which will save verbosity.
720			last.Cond = &ast.BinaryExpr{
721				Op: token.LOR,
722				X:  last.Cond,
723				Y:  node.Cond,
724			}
725			return
726		}
727	}
728
729	w.List = append(w.List, node)
730}
731
732// predeclared contains globally known tokens that should not be redefined.
733var predeclared = map[string]bool{
734	"nil":   true,
735	"false": true,
736	"true":  true,
737}
738
739// declared reports if the body contains a Declare with the given name.
740func (w *BodyBase) declared(name string) bool {
741	if predeclared[name] {
742		// Treat predeclared names as having already been declared.
743		// This lets us use nil to match an aux field or
744		// true and false to match an auxint field.
745		return true
746	}
747	for _, s := range w.List {
748		if decl, ok := s.(*Declare); ok && decl.Name == name {
749			return true
750		}
751	}
752	return false
753}
754
755// These types define some high-level statement struct types, which can be used
756// as a Statement. This allows us to keep some node structs simpler, and have
757// higher-level nodes such as an entire rule rewrite.
758//
759// Note that ast.Expr is always used as-is; we don't declare our own expression
760// nodes.
761type (
762	File struct {
763		BodyBase // []*Func
764		Arch     arch
765		Suffix   string
766	}
767	Func struct {
768		BodyBase
769		Kind   string // "Value" or "Block"
770		Suffix string
771		ArgLen int32 // if kind == "Value", number of args for this op
772	}
773	Switch struct {
774		BodyBase // []*Case
775		Expr     ast.Expr
776	}
777	Case struct {
778		BodyBase
779		Expr ast.Expr
780	}
781	RuleRewrite struct {
782		BodyBase
783		Match, Cond, Result string // top comments
784		Check               string // top-level boolean expression
785
786		Alloc        int    // for unique var names
787		Loc          string // file name & line number of the original rule
788		CommuteDepth int    // used to track depth of commute loops
789	}
790	Declare struct {
791		Name  string
792		Value ast.Expr
793	}
794	CondBreak struct {
795		Cond              ast.Expr
796		InsideCommuteLoop bool
797	}
798	StartCommuteLoop struct {
799		Depth int
800		V     string
801	}
802)
803
804// exprf parses a Go expression generated from fmt.Sprintf, panicking if an
805// error occurs.
806func exprf(format string, a ...interface{}) ast.Expr {
807	src := fmt.Sprintf(format, a...)
808	expr, err := parser.ParseExpr(src)
809	if err != nil {
810		log.Fatalf("expr parse error on %q: %v", src, err)
811	}
812	return expr
813}
814
815// stmtf parses a Go statement generated from fmt.Sprintf. This function is only
816// meant for simple statements that don't have a custom Statement node declared
817// in this package, such as ast.ReturnStmt or ast.ExprStmt.
818func stmtf(format string, a ...interface{}) Statement {
819	src := fmt.Sprintf(format, a...)
820	fsrc := "package p\nfunc _() {\n" + src + "\n}\n"
821	file, err := parser.ParseFile(token.NewFileSet(), "", fsrc, 0)
822	if err != nil {
823		log.Fatalf("stmt parse error on %q: %v", src, err)
824	}
825	return file.Decls[0].(*ast.FuncDecl).Body.List[0]
826}
827
828var reservedNames = map[string]bool{
829	"v":      true, // Values[i], etc
830	"b":      true, // v.Block
831	"config": true, // b.Func.Config
832	"fe":     true, // b.Func.fe
833	"typ":    true, // &b.Func.Config.Types
834}
835
836// declf constructs a simple "name := value" declaration,
837// using exprf for its value.
838//
839// name must not be one of reservedNames.
840// This helps prevent unintended shadowing and name clashes.
841// To declare a reserved name, use declReserved.
842func declf(loc, name, format string, a ...interface{}) *Declare {
843	if reservedNames[name] {
844		log.Fatalf("rule %s uses the reserved name %s", loc, name)
845	}
846	return &Declare{name, exprf(format, a...)}
847}
848
849// declReserved is like declf, but the name must be one of reservedNames.
850// Calls to declReserved should generally be static and top-level.
851func declReserved(name, value string) *Declare {
852	if !reservedNames[name] {
853		panic(fmt.Sprintf("declReserved call does not use a reserved name: %q", name))
854	}
855	return &Declare{name, exprf(value)}
856}
857
858// breakf constructs a simple "if cond { break }" statement, using exprf for its
859// condition.
860func breakf(format string, a ...interface{}) *CondBreak {
861	return &CondBreak{Cond: exprf(format, a...)}
862}
863
864func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
865	rr := &RuleRewrite{Loc: rule.Loc}
866	rr.Match, rr.Cond, rr.Result = rule.parse()
867	_, _, auxint, aux, s := extract(rr.Match) // remove parens, then split
868
869	// check match of control values
870	if len(s) < data.controls {
871		log.Fatalf("incorrect number of arguments in %s, got %v wanted at least %v", rule, len(s), data.controls)
872	}
873	controls := s[:data.controls]
874	pos := make([]string, data.controls)
875	for i, arg := range controls {
876		cname := fmt.Sprintf("b.Controls[%v]", i)
877		if strings.Contains(arg, "(") {
878			vname, expr := splitNameExpr(arg)
879			if vname == "" {
880				vname = fmt.Sprintf("v_%v", i)
881			}
882			rr.add(declf(rr.Loc, vname, cname))
883			p, op := genMatch0(rr, arch, expr, vname, nil, false) // TODO: pass non-nil cnt?
884			if op != "" {
885				check := fmt.Sprintf("%s.Op == %s", cname, op)
886				if rr.Check == "" {
887					rr.Check = check
888				} else {
889					rr.Check += " && " + check
890				}
891			}
892			if p == "" {
893				p = vname + ".Pos"
894			}
895			pos[i] = p
896		} else {
897			rr.add(declf(rr.Loc, arg, cname))
898			pos[i] = arg + ".Pos"
899		}
900	}
901	for _, e := range []struct {
902		name, field, dclType string
903	}{
904		{auxint, "AuxInt", data.auxIntType()},
905		{aux, "Aux", data.auxType()},
906	} {
907		if e.name == "" {
908			continue
909		}
910
911		if e.dclType == "" {
912			log.Fatalf("op %s has no declared type for %s", data.name, e.field)
913		}
914		if !token.IsIdentifier(e.name) || rr.declared(e.name) {
915			rr.add(breakf("%sTo%s(b.%s) != %s", unTitle(e.field), title(e.dclType), e.field, e.name))
916		} else {
917			rr.add(declf(rr.Loc, e.name, "%sTo%s(b.%s)", unTitle(e.field), title(e.dclType), e.field))
918		}
919	}
920	if rr.Cond != "" {
921		rr.add(breakf("!(%s)", rr.Cond))
922	}
923
924	// Rule matches. Generate result.
925	outop, _, auxint, aux, t := extract(rr.Result) // remove parens, then split
926	blockName, outdata := getBlockInfo(outop, arch)
927	if len(t) < outdata.controls {
928		log.Fatalf("incorrect number of output arguments in %s, got %v wanted at least %v", rule, len(s), outdata.controls)
929	}
930
931	// Check if newsuccs is the same set as succs.
932	succs := s[data.controls:]
933	newsuccs := t[outdata.controls:]
934	m := map[string]bool{}
935	for _, succ := range succs {
936		if m[succ] {
937			log.Fatalf("can't have a repeat successor name %s in %s", succ, rule)
938		}
939		m[succ] = true
940	}
941	for _, succ := range newsuccs {
942		if !m[succ] {
943			log.Fatalf("unknown successor %s in %s", succ, rule)
944		}
945		delete(m, succ)
946	}
947	if len(m) != 0 {
948		log.Fatalf("unmatched successors %v in %s", m, rule)
949	}
950
951	var genControls [2]string
952	for i, control := range t[:outdata.controls] {
953		// Select a source position for any new control values.
954		// TODO: does it always make sense to use the source position
955		// of the original control values or should we be using the
956		// block's source position in some cases?
957		newpos := "b.Pos" // default to block's source position
958		if i < len(pos) && pos[i] != "" {
959			// Use the previous control value's source position.
960			newpos = pos[i]
961		}
962
963		// Generate a new control value (or copy an existing value).
964		genControls[i] = genResult0(rr, arch, control, false, false, newpos, nil)
965	}
966	switch outdata.controls {
967	case 0:
968		rr.add(stmtf("b.Reset(%s)", blockName))
969	case 1:
970		rr.add(stmtf("b.resetWithControl(%s, %s)", blockName, genControls[0]))
971	case 2:
972		rr.add(stmtf("b.resetWithControl2(%s, %s, %s)", blockName, genControls[0], genControls[1]))
973	default:
974		log.Fatalf("too many controls: %d", outdata.controls)
975	}
976
977	if auxint != "" {
978		// Make sure auxint value has the right type.
979		rr.add(stmtf("b.AuxInt = %sToAuxInt(%s)", unTitle(outdata.auxIntType()), auxint))
980	}
981	if aux != "" {
982		// Make sure aux value has the right type.
983		rr.add(stmtf("b.Aux = %sToAux(%s)", unTitle(outdata.auxType()), aux))
984	}
985
986	succChanged := false
987	for i := 0; i < len(succs); i++ {
988		if succs[i] != newsuccs[i] {
989			succChanged = true
990		}
991	}
992	if succChanged {
993		if len(succs) != 2 {
994			log.Fatalf("changed successors, len!=2 in %s", rule)
995		}
996		if succs[0] != newsuccs[1] || succs[1] != newsuccs[0] {
997			log.Fatalf("can only handle swapped successors in %s", rule)
998		}
999		rr.add(stmtf("b.swapSuccessors()"))
1000	}
1001
1002	if *genLog {
1003		rr.add(stmtf("logRule(%q)", rule.Loc))
1004	}
1005	return rr
1006}
1007
1008// genMatch returns the variable whose source position should be used for the
1009// result (or "" if no opinion), and a boolean that reports whether the match can fail.
1010func genMatch(rr *RuleRewrite, arch arch, match string, pregenTop bool) (pos, checkOp string) {
1011	cnt := varCount(rr)
1012	return genMatch0(rr, arch, match, "v", cnt, pregenTop)
1013}
1014
1015func genMatch0(rr *RuleRewrite, arch arch, match, v string, cnt map[string]int, pregenTop bool) (pos, checkOp string) {
1016	if match[0] != '(' || match[len(match)-1] != ')' {
1017		log.Fatalf("%s: non-compound expr in genMatch0: %q", rr.Loc, match)
1018	}
1019	op, oparch, typ, auxint, aux, args := parseValue(match, arch, rr.Loc)
1020
1021	checkOp = fmt.Sprintf("Op%s%s", oparch, op.name)
1022
1023	if op.faultOnNilArg0 || op.faultOnNilArg1 {
1024		// Prefer the position of an instruction which could fault.
1025		pos = v + ".Pos"
1026	}
1027
1028	// If the last argument is ___, it means "don't care about trailing arguments, really"
1029	// The likely/intended use is for rewrites that are too tricky to express in the existing pattern language
1030	// Do a length check early because long patterns fed short (ultimately not-matching) inputs will
1031	// do an indexing error in pattern-matching.
1032	if op.argLength == -1 {
1033		l := len(args)
1034		if l == 0 || args[l-1] != "___" {
1035			rr.add(breakf("len(%s.Args) != %d", v, l))
1036		} else if l > 1 && args[l-1] == "___" {
1037			rr.add(breakf("len(%s.Args) < %d", v, l-1))
1038		}
1039	}
1040
1041	for _, e := range []struct {
1042		name, field, dclType string
1043	}{
1044		{typ, "Type", "*types.Type"},
1045		{auxint, "AuxInt", op.auxIntType()},
1046		{aux, "Aux", op.auxType()},
1047	} {
1048		if e.name == "" {
1049			continue
1050		}
1051
1052		if e.dclType == "" {
1053			log.Fatalf("op %s has no declared type for %s", op.name, e.field)
1054		}
1055		if !token.IsIdentifier(e.name) || rr.declared(e.name) {
1056			switch e.field {
1057			case "Aux":
1058				rr.add(breakf("auxTo%s(%s.%s) != %s", title(e.dclType), v, e.field, e.name))
1059			case "AuxInt":
1060				rr.add(breakf("auxIntTo%s(%s.%s) != %s", title(e.dclType), v, e.field, e.name))
1061			case "Type":
1062				rr.add(breakf("%s.%s != %s", v, e.field, e.name))
1063			}
1064		} else {
1065			switch e.field {
1066			case "Aux":
1067				rr.add(declf(rr.Loc, e.name, "auxTo%s(%s.%s)", title(e.dclType), v, e.field))
1068			case "AuxInt":
1069				rr.add(declf(rr.Loc, e.name, "auxIntTo%s(%s.%s)", title(e.dclType), v, e.field))
1070			case "Type":
1071				rr.add(declf(rr.Loc, e.name, "%s.%s", v, e.field))
1072			}
1073		}
1074	}
1075
1076	commutative := op.commutative
1077	if commutative {
1078		if args[0] == args[1] {
1079			// When we have (Add x x), for any x,
1080			// even if there are other uses of x besides these two,
1081			// and even if x is not a variable,
1082			// we can skip the commutative match.
1083			commutative = false
1084		}
1085		if cnt[args[0]] == 1 && cnt[args[1]] == 1 {
1086			// When we have (Add x y) with no other uses
1087			// of x and y in the matching rule and condition,
1088			// then we can skip the commutative match (Add y x).
1089			commutative = false
1090		}
1091	}
1092
1093	if !pregenTop {
1094		// Access last argument first to minimize bounds checks.
1095		for n := len(args) - 1; n > 0; n-- {
1096			a := args[n]
1097			if a == "_" {
1098				continue
1099			}
1100			if !rr.declared(a) && token.IsIdentifier(a) && !(commutative && len(args) == 2) {
1101				rr.add(declf(rr.Loc, a, "%s.Args[%d]", v, n))
1102				// delete the last argument so it is not reprocessed
1103				args = args[:n]
1104			} else {
1105				rr.add(stmtf("_ = %s.Args[%d]", v, n))
1106			}
1107			break
1108		}
1109	}
1110	if commutative && !pregenTop {
1111		for i := 0; i <= 1; i++ {
1112			vname := fmt.Sprintf("%s_%d", v, i)
1113			rr.add(declf(rr.Loc, vname, "%s.Args[%d]", v, i))
1114		}
1115	}
1116	if commutative {
1117		rr.add(StartCommuteLoop{rr.CommuteDepth, v})
1118		rr.CommuteDepth++
1119	}
1120	for i, arg := range args {
1121		if arg == "_" {
1122			continue
1123		}
1124		var rhs string
1125		if (commutative && i < 2) || pregenTop {
1126			rhs = fmt.Sprintf("%s_%d", v, i)
1127		} else {
1128			rhs = fmt.Sprintf("%s.Args[%d]", v, i)
1129		}
1130		if !strings.Contains(arg, "(") {
1131			// leaf variable
1132			if rr.declared(arg) {
1133				// variable already has a definition. Check whether
1134				// the old definition and the new definition match.
1135				// For example, (add x x).  Equality is just pointer equality
1136				// on Values (so cse is important to do before lowering).
1137				rr.add(breakf("%s != %s", arg, rhs))
1138			} else {
1139				if arg != rhs {
1140					rr.add(declf(rr.Loc, arg, "%s", rhs))
1141				}
1142			}
1143			continue
1144		}
1145		// compound sexpr
1146		argname, expr := splitNameExpr(arg)
1147		if argname == "" {
1148			argname = fmt.Sprintf("%s_%d", v, i)
1149		}
1150		if argname == "b" {
1151			log.Fatalf("don't name args 'b', it is ambiguous with blocks")
1152		}
1153
1154		if argname != rhs {
1155			rr.add(declf(rr.Loc, argname, "%s", rhs))
1156		}
1157		bexpr := exprf("%s.Op != addLater", argname)
1158		rr.add(&CondBreak{Cond: bexpr})
1159		argPos, argCheckOp := genMatch0(rr, arch, expr, argname, cnt, false)
1160		bexpr.(*ast.BinaryExpr).Y.(*ast.Ident).Name = argCheckOp
1161
1162		if argPos != "" {
1163			// Keep the argument in preference to the parent, as the
1164			// argument is normally earlier in program flow.
1165			// Keep the argument in preference to an earlier argument,
1166			// as that prefers the memory argument which is also earlier
1167			// in the program flow.
1168			pos = argPos
1169		}
1170	}
1171
1172	return pos, checkOp
1173}
1174
1175func genResult(rr *RuleRewrite, arch arch, result, pos string) {
1176	move := result[0] == '@'
1177	if move {
1178		// parse @block directive
1179		s := strings.SplitN(result[1:], " ", 2)
1180		rr.add(stmtf("b = %s", s[0]))
1181		result = s[1]
1182	}
1183	cse := make(map[string]string)
1184	genResult0(rr, arch, result, true, move, pos, cse)
1185}
1186
1187func genResult0(rr *RuleRewrite, arch arch, result string, top, move bool, pos string, cse map[string]string) string {
1188	resname, expr := splitNameExpr(result)
1189	result = expr
1190	// TODO: when generating a constant result, use f.constVal to avoid
1191	// introducing copies just to clean them up again.
1192	if result[0] != '(' {
1193		// variable
1194		if top {
1195			// It in not safe in general to move a variable between blocks
1196			// (and particularly not a phi node).
1197			// Introduce a copy.
1198			rr.add(stmtf("v.copyOf(%s)", result))
1199		}
1200		return result
1201	}
1202
1203	w := normalizeWhitespace(result)
1204	if prev := cse[w]; prev != "" {
1205		return prev
1206	}
1207
1208	op, oparch, typ, auxint, aux, args := parseValue(result, arch, rr.Loc)
1209
1210	// Find the type of the variable.
1211	typeOverride := typ != ""
1212	if typ == "" && op.typ != "" {
1213		typ = typeName(op.typ)
1214	}
1215
1216	v := "v"
1217	if top && !move {
1218		rr.add(stmtf("v.reset(Op%s%s)", oparch, op.name))
1219		if typeOverride {
1220			rr.add(stmtf("v.Type = %s", typ))
1221		}
1222	} else {
1223		if typ == "" {
1224			log.Fatalf("sub-expression %s (op=Op%s%s) at %s must have a type", result, oparch, op.name, rr.Loc)
1225		}
1226		if resname == "" {
1227			v = fmt.Sprintf("v%d", rr.Alloc)
1228		} else {
1229			v = resname
1230		}
1231		rr.Alloc++
1232		rr.add(declf(rr.Loc, v, "b.NewValue0(%s, Op%s%s, %s)", pos, oparch, op.name, typ))
1233		if move && top {
1234			// Rewrite original into a copy
1235			rr.add(stmtf("v.copyOf(%s)", v))
1236		}
1237	}
1238
1239	if auxint != "" {
1240		// Make sure auxint value has the right type.
1241		rr.add(stmtf("%s.AuxInt = %sToAuxInt(%s)", v, unTitle(op.auxIntType()), auxint))
1242	}
1243	if aux != "" {
1244		// Make sure aux value has the right type.
1245		rr.add(stmtf("%s.Aux = %sToAux(%s)", v, unTitle(op.auxType()), aux))
1246	}
1247	all := new(strings.Builder)
1248	for i, arg := range args {
1249		x := genResult0(rr, arch, arg, false, move, pos, cse)
1250		if i > 0 {
1251			all.WriteString(", ")
1252		}
1253		all.WriteString(x)
1254	}
1255	switch len(args) {
1256	case 0:
1257	case 1:
1258		rr.add(stmtf("%s.AddArg(%s)", v, all.String()))
1259	default:
1260		rr.add(stmtf("%s.AddArg%d(%s)", v, len(args), all.String()))
1261	}
1262
1263	if cse != nil {
1264		cse[w] = v
1265	}
1266	return v
1267}
1268
1269func split(s string) []string {
1270	var r []string
1271
1272outer:
1273	for s != "" {
1274		d := 0               // depth of ({[<
1275		var open, close byte // opening and closing markers ({[< or )}]>
1276		nonsp := false       // found a non-space char so far
1277		for i := 0; i < len(s); i++ {
1278			switch {
1279			case d == 0 && s[i] == '(':
1280				open, close = '(', ')'
1281				d++
1282			case d == 0 && s[i] == '<':
1283				open, close = '<', '>'
1284				d++
1285			case d == 0 && s[i] == '[':
1286				open, close = '[', ']'
1287				d++
1288			case d == 0 && s[i] == '{':
1289				open, close = '{', '}'
1290				d++
1291			case d == 0 && (s[i] == ' ' || s[i] == '\t'):
1292				if nonsp {
1293					r = append(r, strings.TrimSpace(s[:i]))
1294					s = s[i:]
1295					continue outer
1296				}
1297			case d > 0 && s[i] == open:
1298				d++
1299			case d > 0 && s[i] == close:
1300				d--
1301			default:
1302				nonsp = true
1303			}
1304		}
1305		if d != 0 {
1306			log.Fatalf("imbalanced expression: %q", s)
1307		}
1308		if nonsp {
1309			r = append(r, strings.TrimSpace(s))
1310		}
1311		break
1312	}
1313	return r
1314}
1315
1316// isBlock reports whether this op is a block opcode.
1317func isBlock(name string, arch arch) bool {
1318	for _, b := range genericBlocks {
1319		if b.name == name {
1320			return true
1321		}
1322	}
1323	for _, b := range arch.blocks {
1324		if b.name == name {
1325			return true
1326		}
1327	}
1328	return false
1329}
1330
1331func extract(val string) (op, typ, auxint, aux string, args []string) {
1332	val = val[1 : len(val)-1] // remove ()
1333
1334	// Split val up into regions.
1335	// Split by spaces/tabs, except those contained in (), {}, [], or <>.
1336	s := split(val)
1337
1338	// Extract restrictions and args.
1339	op = s[0]
1340	for _, a := range s[1:] {
1341		switch a[0] {
1342		case '<':
1343			typ = a[1 : len(a)-1] // remove <>
1344		case '[':
1345			auxint = a[1 : len(a)-1] // remove []
1346		case '{':
1347			aux = a[1 : len(a)-1] // remove {}
1348		default:
1349			args = append(args, a)
1350		}
1351	}
1352	return
1353}
1354
1355// parseValue parses a parenthesized value from a rule.
1356// The value can be from the match or the result side.
1357// It returns the op and unparsed strings for typ, auxint, and aux restrictions and for all args.
1358// oparch is the architecture that op is located in, or "" for generic.
1359func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxint, aux string, args []string) {
1360	// Resolve the op.
1361	var s string
1362	s, typ, auxint, aux, args = extract(val)
1363
1364	// match reports whether x is a good op to select.
1365	// If strict is true, rule generation might succeed.
1366	// If strict is false, rule generation has failed,
1367	// but we're trying to generate a useful error.
1368	// Doing strict=true then strict=false allows
1369	// precise op matching while retaining good error messages.
1370	match := func(x opData, strict bool, archname string) bool {
1371		if x.name != s {
1372			return false
1373		}
1374		if x.argLength != -1 && int(x.argLength) != len(args) && (len(args) != 1 || args[0] != "...") {
1375			if strict {
1376				return false
1377			}
1378			log.Printf("%s: op %s (%s) should have %d args, has %d", loc, s, archname, x.argLength, len(args))
1379		}
1380		return true
1381	}
1382
1383	for _, x := range genericOps {
1384		if match(x, true, "generic") {
1385			op = x
1386			break
1387		}
1388	}
1389	for _, x := range arch.ops {
1390		if arch.name != "generic" && match(x, true, arch.name) {
1391			if op.name != "" {
1392				log.Fatalf("%s: matches for op %s found in both generic and %s", loc, op.name, arch.name)
1393			}
1394			op = x
1395			oparch = arch.name
1396			break
1397		}
1398	}
1399
1400	if op.name == "" {
1401		// Failed to find the op.
1402		// Run through everything again with strict=false
1403		// to generate useful diagnostic messages before failing.
1404		for _, x := range genericOps {
1405			match(x, false, "generic")
1406		}
1407		for _, x := range arch.ops {
1408			match(x, false, arch.name)
1409		}
1410		log.Fatalf("%s: unknown op %s", loc, s)
1411	}
1412
1413	// Sanity check aux, auxint.
1414	if auxint != "" && !opHasAuxInt(op) {
1415		log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
1416	}
1417	if aux != "" && !opHasAux(op) {
1418		log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
1419	}
1420	return
1421}
1422
1423func opHasAuxInt(op opData) bool {
1424	switch op.aux {
1425	case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "UInt8", "Float32", "Float64",
1426		"SymOff", "CallOff", "SymValAndOff", "TypSize", "ARM64BitField", "FlagConstant", "CCop":
1427		return true
1428	}
1429	return false
1430}
1431
1432func opHasAux(op opData) bool {
1433	switch op.aux {
1434	case "String", "Sym", "SymOff", "Call", "CallOff", "SymValAndOff", "Typ", "TypSize",
1435		"S390XCCMask", "S390XRotateParams":
1436		return true
1437	}
1438	return false
1439}
1440
1441// splitNameExpr splits s-expr arg, possibly prefixed by "name:",
1442// into name and the unprefixed expression.
1443// For example, "x:(Foo)" yields "x", "(Foo)",
1444// and "(Foo)" yields "", "(Foo)".
1445func splitNameExpr(arg string) (name, expr string) {
1446	colon := strings.Index(arg, ":")
1447	if colon < 0 {
1448		return "", arg
1449	}
1450	openparen := strings.Index(arg, "(")
1451	if openparen < 0 {
1452		log.Fatalf("splitNameExpr(%q): colon but no open parens", arg)
1453	}
1454	if colon > openparen {
1455		// colon is inside the parens, such as in "(Foo x:(Bar))".
1456		return "", arg
1457	}
1458	return arg[:colon], arg[colon+1:]
1459}
1460
1461func getBlockInfo(op string, arch arch) (name string, data blockData) {
1462	for _, b := range genericBlocks {
1463		if b.name == op {
1464			return "Block" + op, b
1465		}
1466	}
1467	for _, b := range arch.blocks {
1468		if b.name == op {
1469			return "Block" + arch.name + op, b
1470		}
1471	}
1472	log.Fatalf("could not find block data for %s", op)
1473	panic("unreachable")
1474}
1475
1476// typeName returns the string to use to generate a type.
1477func typeName(typ string) string {
1478	if typ[0] == '(' {
1479		ts := strings.Split(typ[1:len(typ)-1], ",")
1480		if len(ts) != 2 {
1481			log.Fatalf("Tuple expect 2 arguments")
1482		}
1483		return "types.NewTuple(" + typeName(ts[0]) + ", " + typeName(ts[1]) + ")"
1484	}
1485	switch typ {
1486	case "Flags", "Mem", "Void", "Int128":
1487		return "types.Type" + typ
1488	default:
1489		return "typ." + typ
1490	}
1491}
1492
1493// balance returns the number of unclosed '(' characters in s.
1494// If a ')' appears without a corresponding '(', balance returns -1.
1495func balance(s string) int {
1496	balance := 0
1497	for _, c := range s {
1498		switch c {
1499		case '(':
1500			balance++
1501		case ')':
1502			balance--
1503			if balance < 0 {
1504				// don't allow ")(" to return 0
1505				return -1
1506			}
1507		}
1508	}
1509	return balance
1510}
1511
1512// findAllOpcode is a function to find the opcode portion of s-expressions.
1513var findAllOpcode = regexp.MustCompile(`[(](\w+[|])+\w+[)]`).FindAllStringIndex
1514
1515// excludeFromExpansion reports whether the substring s[idx[0]:idx[1]] in a rule
1516// should be disregarded as a candidate for | expansion.
1517// It uses simple syntactic checks to see whether the substring
1518// is inside an AuxInt expression or inside the && conditions.
1519func excludeFromExpansion(s string, idx []int) bool {
1520	left := s[:idx[0]]
1521	if strings.LastIndexByte(left, '[') > strings.LastIndexByte(left, ']') {
1522		// Inside an AuxInt expression.
1523		return true
1524	}
1525	right := s[idx[1]:]
1526	if strings.Contains(left, "&&") && strings.Contains(right, "=>") {
1527		// Inside && conditions.
1528		return true
1529	}
1530	return false
1531}
1532
1533// expandOr converts a rule into multiple rules by expanding | ops.
1534func expandOr(r string) []string {
1535	// Find every occurrence of |-separated things.
1536	// They look like MOV(B|W|L|Q|SS|SD)load or MOV(Q|L)loadidx(1|8).
1537	// Generate rules selecting one case from each |-form.
1538
1539	// Count width of |-forms.  They must match.
1540	n := 1
1541	for _, idx := range findAllOpcode(r, -1) {
1542		if excludeFromExpansion(r, idx) {
1543			continue
1544		}
1545		s := r[idx[0]:idx[1]]
1546		c := strings.Count(s, "|") + 1
1547		if c == 1 {
1548			continue
1549		}
1550		if n > 1 && n != c {
1551			log.Fatalf("'|' count doesn't match in %s: both %d and %d\n", r, n, c)
1552		}
1553		n = c
1554	}
1555	if n == 1 {
1556		// No |-form in this rule.
1557		return []string{r}
1558	}
1559	// Build each new rule.
1560	res := make([]string, n)
1561	for i := 0; i < n; i++ {
1562		buf := new(strings.Builder)
1563		x := 0
1564		for _, idx := range findAllOpcode(r, -1) {
1565			if excludeFromExpansion(r, idx) {
1566				continue
1567			}
1568			buf.WriteString(r[x:idx[0]])              // write bytes we've skipped over so far
1569			s := r[idx[0]+1 : idx[1]-1]               // remove leading "(" and trailing ")"
1570			buf.WriteString(strings.Split(s, "|")[i]) // write the op component for this rule
1571			x = idx[1]                                // note that we've written more bytes
1572		}
1573		buf.WriteString(r[x:])
1574		res[i] = buf.String()
1575	}
1576	return res
1577}
1578
1579// varCount returns a map which counts the number of occurrences of
1580// Value variables in the s-expression rr.Match and the Go expression rr.Cond.
1581func varCount(rr *RuleRewrite) map[string]int {
1582	cnt := map[string]int{}
1583	varCount1(rr.Loc, rr.Match, cnt)
1584	if rr.Cond != "" {
1585		expr, err := parser.ParseExpr(rr.Cond)
1586		if err != nil {
1587			log.Fatalf("%s: failed to parse cond %q: %v", rr.Loc, rr.Cond, err)
1588		}
1589		ast.Inspect(expr, func(n ast.Node) bool {
1590			if id, ok := n.(*ast.Ident); ok {
1591				cnt[id.Name]++
1592			}
1593			return true
1594		})
1595	}
1596	return cnt
1597}
1598
1599func varCount1(loc, m string, cnt map[string]int) {
1600	if m[0] == '<' || m[0] == '[' || m[0] == '{' {
1601		return
1602	}
1603	if token.IsIdentifier(m) {
1604		cnt[m]++
1605		return
1606	}
1607	// Split up input.
1608	name, expr := splitNameExpr(m)
1609	if name != "" {
1610		cnt[name]++
1611	}
1612	if expr[0] != '(' || expr[len(expr)-1] != ')' {
1613		log.Fatalf("%s: non-compound expr in varCount1: %q", loc, expr)
1614	}
1615	s := split(expr[1 : len(expr)-1])
1616	for _, arg := range s[1:] {
1617		varCount1(loc, arg, cnt)
1618	}
1619}
1620
1621// normalizeWhitespace replaces 2+ whitespace sequences with a single space.
1622func normalizeWhitespace(x string) string {
1623	x = strings.Join(strings.Fields(x), " ")
1624	x = strings.Replace(x, "( ", "(", -1)
1625	x = strings.Replace(x, " )", ")", -1)
1626	x = strings.Replace(x, "[ ", "[", -1)
1627	x = strings.Replace(x, " ]", "]", -1)
1628	x = strings.Replace(x, ")=>", ") =>", -1)
1629	return x
1630}
1631
1632// opIsCommutative reports whether op s is commutative.
1633func opIsCommutative(op string, arch arch) bool {
1634	for _, x := range genericOps {
1635		if op == x.name {
1636			if x.commutative {
1637				return true
1638			}
1639			break
1640		}
1641	}
1642	if arch.name != "generic" {
1643		for _, x := range arch.ops {
1644			if op == x.name {
1645				if x.commutative {
1646					return true
1647				}
1648				break
1649			}
1650		}
1651	}
1652	return false
1653}
1654
1655func normalizeMatch(m string, arch arch) string {
1656	if token.IsIdentifier(m) {
1657		return m
1658	}
1659	op, typ, auxint, aux, args := extract(m)
1660	if opIsCommutative(op, arch) {
1661		if args[1] < args[0] {
1662			args[0], args[1] = args[1], args[0]
1663		}
1664	}
1665	s := new(strings.Builder)
1666	fmt.Fprintf(s, "%s <%s> [%s] {%s}", op, typ, auxint, aux)
1667	for _, arg := range args {
1668		prefix, expr := splitNameExpr(arg)
1669		fmt.Fprint(s, " ", prefix, normalizeMatch(expr, arch))
1670	}
1671	return s.String()
1672}
1673
1674func parseEllipsisRules(rules []Rule, arch arch) (newop string, ok bool) {
1675	if len(rules) != 1 {
1676		for _, r := range rules {
1677			if strings.Contains(r.Rule, "...") {
1678				log.Fatalf("%s: found ellipsis in rule, but there are other rules with the same op", r.Loc)
1679			}
1680		}
1681		return "", false
1682	}
1683	rule := rules[0]
1684	match, cond, result := rule.parse()
1685	if cond != "" || !isEllipsisValue(match) || !isEllipsisValue(result) {
1686		if strings.Contains(rule.Rule, "...") {
1687			log.Fatalf("%s: found ellipsis in non-ellipsis rule", rule.Loc)
1688		}
1689		checkEllipsisRuleCandidate(rule, arch)
1690		return "", false
1691	}
1692	op, oparch, _, _, _, _ := parseValue(result, arch, rule.Loc)
1693	return fmt.Sprintf("Op%s%s", oparch, op.name), true
1694}
1695
1696// isEllipsisValue reports whether s is of the form (OpX ...).
1697func isEllipsisValue(s string) bool {
1698	if len(s) < 2 || s[0] != '(' || s[len(s)-1] != ')' {
1699		return false
1700	}
1701	c := split(s[1 : len(s)-1])
1702	if len(c) != 2 || c[1] != "..." {
1703		return false
1704	}
1705	return true
1706}
1707
1708func checkEllipsisRuleCandidate(rule Rule, arch arch) {
1709	match, cond, result := rule.parse()
1710	if cond != "" {
1711		return
1712	}
1713	op, _, _, auxint, aux, args := parseValue(match, arch, rule.Loc)
1714	var auxint2, aux2 string
1715	var args2 []string
1716	var usingCopy string
1717	var eop opData
1718	if result[0] != '(' {
1719		// Check for (Foo x) => x, which can be converted to (Foo ...) => (Copy ...).
1720		args2 = []string{result}
1721		usingCopy = " using Copy"
1722	} else {
1723		eop, _, _, auxint2, aux2, args2 = parseValue(result, arch, rule.Loc)
1724	}
1725	// Check that all restrictions in match are reproduced exactly in result.
1726	if aux != aux2 || auxint != auxint2 || len(args) != len(args2) {
1727		return
1728	}
1729	if strings.Contains(rule.Rule, "=>") && op.aux != eop.aux {
1730		return
1731	}
1732	for i := range args {
1733		if args[i] != args2[i] {
1734			return
1735		}
1736	}
1737	switch {
1738	case opHasAux(op) && aux == "" && aux2 == "":
1739		fmt.Printf("%s: rule silently zeros aux, either copy aux or explicitly zero\n", rule.Loc)
1740	case opHasAuxInt(op) && auxint == "" && auxint2 == "":
1741		fmt.Printf("%s: rule silently zeros auxint, either copy auxint or explicitly zero\n", rule.Loc)
1742	default:
1743		fmt.Printf("%s: possible ellipsis rule candidate%s: %q\n", rule.Loc, usingCopy, rule.Rule)
1744	}
1745}
1746
1747func opByName(arch arch, name string) opData {
1748	name = name[2:]
1749	for _, x := range genericOps {
1750		if name == x.name {
1751			return x
1752		}
1753	}
1754	if arch.name != "generic" {
1755		name = name[len(arch.name):]
1756		for _, x := range arch.ops {
1757			if name == x.name {
1758				return x
1759			}
1760		}
1761	}
1762	log.Fatalf("failed to find op named %s in arch %s", name, arch.name)
1763	panic("unreachable")
1764}
1765
1766// auxType returns the Go type that this operation should store in its aux field.
1767func (op opData) auxType() string {
1768	switch op.aux {
1769	case "String":
1770		return "string"
1771	case "Sym":
1772		// Note: a Sym can be an *obj.LSym, a *gc.Node, or nil.
1773		return "Sym"
1774	case "SymOff":
1775		return "Sym"
1776	case "Call":
1777		return "Call"
1778	case "CallOff":
1779		return "Call"
1780	case "SymValAndOff":
1781		return "Sym"
1782	case "Typ":
1783		return "*types.Type"
1784	case "TypSize":
1785		return "*types.Type"
1786	case "S390XCCMask":
1787		return "s390x.CCMask"
1788	case "S390XRotateParams":
1789		return "s390x.RotateParams"
1790	default:
1791		return "invalid"
1792	}
1793}
1794
1795// auxIntType returns the Go type that this operation should store in its auxInt field.
1796func (op opData) auxIntType() string {
1797	switch op.aux {
1798	case "Bool":
1799		return "bool"
1800	case "Int8":
1801		return "int8"
1802	case "Int16":
1803		return "int16"
1804	case "Int32":
1805		return "int32"
1806	case "Int64":
1807		return "int64"
1808	case "Int128":
1809		return "int128"
1810	case "UInt8":
1811		return "uint8"
1812	case "Float32":
1813		return "float32"
1814	case "Float64":
1815		return "float64"
1816	case "CallOff":
1817		return "int32"
1818	case "SymOff":
1819		return "int32"
1820	case "SymValAndOff":
1821		return "ValAndOff"
1822	case "TypSize":
1823		return "int64"
1824	case "CCop":
1825		return "Op"
1826	case "FlagConstant":
1827		return "flagConstant"
1828	case "ARM64BitField":
1829		return "arm64BitField"
1830	default:
1831		return "invalid"
1832	}
1833}
1834
1835// auxType returns the Go type that this block should store in its aux field.
1836func (b blockData) auxType() string {
1837	switch b.aux {
1838	case "Sym":
1839		return "Sym"
1840	case "S390XCCMask", "S390XCCMaskInt8", "S390XCCMaskUint8":
1841		return "s390x.CCMask"
1842	case "S390XRotateParams":
1843		return "s390x.RotateParams"
1844	default:
1845		return "invalid"
1846	}
1847}
1848
1849// auxIntType returns the Go type that this block should store in its auxInt field.
1850func (b blockData) auxIntType() string {
1851	switch b.aux {
1852	case "S390XCCMaskInt8":
1853		return "int8"
1854	case "S390XCCMaskUint8":
1855		return "uint8"
1856	case "Int64":
1857		return "int64"
1858	default:
1859		return "invalid"
1860	}
1861}
1862
1863func title(s string) string {
1864	if i := strings.Index(s, "."); i >= 0 {
1865		switch strings.ToLower(s[:i]) {
1866		case "s390x": // keep arch prefix for clarity
1867			s = s[:i] + s[i+1:]
1868		default:
1869			s = s[i+1:]
1870		}
1871	}
1872	return strings.Title(s)
1873}
1874
1875func unTitle(s string) string {
1876	if i := strings.Index(s, "."); i >= 0 {
1877		switch strings.ToLower(s[:i]) {
1878		case "s390x": // keep arch prefix for clarity
1879			s = s[:i] + s[i+1:]
1880		default:
1881			s = s[i+1:]
1882		}
1883	}
1884	return strings.ToLower(s[:1]) + s[1:]
1885}
1886