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