1
2
3
4
5
6
7
8
9
10 package main
11
12 import (
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
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 var (
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
64 type Rule struct {
65 Rule string
66 Loc string
67 }
68
69 func (r Rule) String() string {
70 return fmt.Sprintf("rule %q at %s", r.Rule, r.Loc)
71 }
72
73 func normalizeSpaces(s string) string {
74 return strings.Join(strings.Fields(strings.TrimSpace(s)), " ")
75 }
76
77
78 func (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
90 func genRules(arch arch) { genRulesSuffix(arch, "") }
91 func genSplitLoadRules(arch arch) { genRulesSuffix(arch, "splitload") }
92 func genLateLowerRules(arch arch) { genRulesSuffix(arch, "latelower") }
93
94 func genRulesSuffix(arch arch, suff string) {
95
96 text, err := os.Open(arch.name + suff + ".rules")
97 if err != nil {
98 if suff == "" {
99
100 log.Fatalf("can't read rule file: %v", err)
101 }
102
103 return
104 }
105
106
107 blockrules := map[string][]Rule{}
108 oprules := map[string][]Rule{}
109
110
111 scanner := bufio.NewScanner(text)
112 rule := ""
113 var lineno int
114 var ruleLineno int
115 for scanner.Scan() {
116 lineno++
117 line := scanner.Text()
118 if i := strings.Index(line, "//"); i >= 0 {
119
120
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
136 }
137 if n := balance(rule); n > 0 {
138 continue
139 } else if n < 0 {
140 break
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
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
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
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 {
196 fn.add(sw)
197 }
198 fn.add(stmtf("return false"))
199 genFile.add(fn)
200
201
202
203 for _, op := range ops {
204 rules := oprules[op]
205 _, ok := parseEllipsisRules(oprules[op], arch)
206 if ok {
207 continue
208 }
209
210
211
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
248
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 {
268 fn.add(sw)
269 }
270 fn.add(stmtf("return false"))
271 genFile.add(fn)
272
273
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
290
291 u := unusedInspector{unused: make(map[token.Pos]bool)}
292 u.node(file)
293
294
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
303
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
314
315 c.Delete()
316 }
317 }
318 return true
319 }
320 file = astutil.Apply(file, pre, post).(*ast.File)
321
322
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
329
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
343
344
345
346
347 type unusedInspector struct {
348
349
350
351 scope *scope
352
353
354
355 unused map[token.Pos]bool
356
357
358
359
360 defining *object
361 }
362
363
364
365 func (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
382
383
384 obj.used = nil
385 }
386 }
387 u.scope = outer
388 }
389 }
390
391 func (u *unusedInspector) exprs(list []ast.Expr) {
392 for _, x := range list {
393 u.node(x)
394 }
395 }
396
397 func (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
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
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
549
550 type scope struct {
551 outer *scope
552 objects map[string]*object
553 }
554
555 func (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
566 type object struct {
567 name string
568 pos token.Pos
569
570 numUses int
571 used []*object
572 }
573
574 func 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 "math/bits",
586 "cmd/internal/obj",
587 "cmd/compile/internal/base",
588 "cmd/compile/internal/types",
589 "cmd/compile/internal/ir",
590 }, n.Arch.imports...) {
591 fmt.Fprintf(w, "import %q\n", path)
592 }
593 for _, f := range n.List {
594 f := f.(*Func)
595 fmt.Fprintf(w, "func rewrite%s%s%s%s(", f.Kind, n.Arch.name, n.Suffix, f.Suffix)
596 fmt.Fprintf(w, "%c *%s) bool {\n", strings.ToLower(f.Kind)[0], f.Kind)
597 if f.Kind == "Value" && f.ArgLen > 0 {
598 for i := f.ArgLen - 1; i >= 0; i-- {
599 fmt.Fprintf(w, "v_%d := v.Args[%d]\n", i, i)
600 }
601 }
602 for _, n := range f.List {
603 fprint(w, n)
604
605 if rr, ok := n.(*RuleRewrite); ok {
606 k := [3]string{
607 normalizeMatch(rr.Match, file.Arch),
608 normalizeWhitespace(rr.Cond),
609 normalizeWhitespace(rr.Result),
610 }
611 if prev, ok := seenRewrite[k]; ok {
612 log.Fatalf("duplicate rule %s, previously seen at %s\n", rr.Loc, prev)
613 }
614 seenRewrite[k] = rr.Loc
615 }
616 }
617 fmt.Fprintf(w, "}\n")
618 }
619 case *Switch:
620 fmt.Fprintf(w, "switch ")
621 fprint(w, n.Expr)
622 fmt.Fprintf(w, " {\n")
623 for _, n := range n.List {
624 fprint(w, n)
625 }
626 fmt.Fprintf(w, "}\n")
627 case *Case:
628 fmt.Fprintf(w, "case ")
629 fprint(w, n.Expr)
630 fmt.Fprintf(w, ":\n")
631 for _, n := range n.List {
632 fprint(w, n)
633 }
634 case *RuleRewrite:
635 if *addLine {
636 fmt.Fprintf(w, "// %s\n", n.Loc)
637 }
638 fmt.Fprintf(w, "// match: %s\n", n.Match)
639 if n.Cond != "" {
640 fmt.Fprintf(w, "// cond: %s\n", n.Cond)
641 }
642 fmt.Fprintf(w, "// result: %s\n", n.Result)
643 fmt.Fprintf(w, "for %s {\n", n.Check)
644 nCommutative := 0
645 for _, n := range n.List {
646 if b, ok := n.(*CondBreak); ok {
647 b.InsideCommuteLoop = nCommutative > 0
648 }
649 fprint(w, n)
650 if loop, ok := n.(StartCommuteLoop); ok {
651 if nCommutative != loop.Depth {
652 panic("mismatch commute loop depth")
653 }
654 nCommutative++
655 }
656 }
657 fmt.Fprintf(w, "return true\n")
658 for i := 0; i < nCommutative; i++ {
659 fmt.Fprintln(w, "}")
660 }
661 if n.CommuteDepth > 0 && n.CanFail {
662 fmt.Fprint(w, "break\n")
663 }
664 fmt.Fprintf(w, "}\n")
665 case *Declare:
666 fmt.Fprintf(w, "%s := ", n.Name)
667 fprint(w, n.Value)
668 fmt.Fprintln(w)
669 case *CondBreak:
670 fmt.Fprintf(w, "if ")
671 fprint(w, n.Cond)
672 fmt.Fprintf(w, " {\n")
673 if n.InsideCommuteLoop {
674 fmt.Fprintf(w, "continue")
675 } else {
676 fmt.Fprintf(w, "break")
677 }
678 fmt.Fprintf(w, "\n}\n")
679 case ast.Node:
680 printConfig.Fprint(w, emptyFset, n)
681 if _, ok := n.(ast.Stmt); ok {
682 fmt.Fprintln(w)
683 }
684 case StartCommuteLoop:
685 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)
686 default:
687 log.Fatalf("cannot print %T", n)
688 }
689 }
690
691 var printConfig = printer.Config{
692 Mode: printer.RawFormat,
693 }
694
695 var emptyFset = token.NewFileSet()
696
697
698 type Node interface{}
699
700
701
702 type Statement interface{}
703
704
705
706 type BodyBase struct {
707 List []Statement
708 CanFail bool
709 }
710
711 func (w *BodyBase) add(node Statement) {
712 var last Statement
713 if len(w.List) > 0 {
714 last = w.List[len(w.List)-1]
715 }
716 if node, ok := node.(*CondBreak); ok {
717 w.CanFail = true
718 if last, ok := last.(*CondBreak); ok {
719
720
721 last.Cond = &ast.BinaryExpr{
722 Op: token.LOR,
723 X: last.Cond,
724 Y: node.Cond,
725 }
726 return
727 }
728 }
729
730 w.List = append(w.List, node)
731 }
732
733
734 var predeclared = map[string]bool{
735 "nil": true,
736 "false": true,
737 "true": true,
738 }
739
740
741 func (w *BodyBase) declared(name string) bool {
742 if predeclared[name] {
743
744
745
746 return true
747 }
748 for _, s := range w.List {
749 if decl, ok := s.(*Declare); ok && decl.Name == name {
750 return true
751 }
752 }
753 return false
754 }
755
756
757
758
759
760
761
762 type (
763 File struct {
764 BodyBase
765 Arch arch
766 Suffix string
767 }
768 Func struct {
769 BodyBase
770 Kind string
771 Suffix string
772 ArgLen int32
773 }
774 Switch struct {
775 BodyBase
776 Expr ast.Expr
777 }
778 Case struct {
779 BodyBase
780 Expr ast.Expr
781 }
782 RuleRewrite struct {
783 BodyBase
784 Match, Cond, Result string
785 Check string
786
787 Alloc int
788 Loc string
789 CommuteDepth int
790 }
791 Declare struct {
792 Name string
793 Value ast.Expr
794 }
795 CondBreak struct {
796 Cond ast.Expr
797 InsideCommuteLoop bool
798 }
799 StartCommuteLoop struct {
800 Depth int
801 V string
802 }
803 )
804
805
806
807 func exprf(format string, a ...interface{}) ast.Expr {
808 src := fmt.Sprintf(format, a...)
809 expr, err := parser.ParseExpr(src)
810 if err != nil {
811 log.Fatalf("expr parse error on %q: %v", src, err)
812 }
813 return expr
814 }
815
816
817
818
819 func stmtf(format string, a ...interface{}) Statement {
820 src := fmt.Sprintf(format, a...)
821 fsrc := "package p\nfunc _() {\n" + src + "\n}\n"
822 file, err := parser.ParseFile(token.NewFileSet(), "", fsrc, 0)
823 if err != nil {
824 log.Fatalf("stmt parse error on %q: %v", src, err)
825 }
826 return file.Decls[0].(*ast.FuncDecl).Body.List[0]
827 }
828
829 var reservedNames = map[string]bool{
830 "v": true,
831 "b": true,
832 "config": true,
833 "fe": true,
834 "typ": true,
835 }
836
837
838
839
840
841
842
843 func declf(loc, name, format string, a ...interface{}) *Declare {
844 if reservedNames[name] {
845 log.Fatalf("rule %s uses the reserved name %s", loc, name)
846 }
847 return &Declare{name, exprf(format, a...)}
848 }
849
850
851
852 func declReserved(name, value string) *Declare {
853 if !reservedNames[name] {
854 panic(fmt.Sprintf("declReserved call does not use a reserved name: %q", name))
855 }
856 return &Declare{name, exprf(value)}
857 }
858
859
860
861 func breakf(format string, a ...interface{}) *CondBreak {
862 return &CondBreak{Cond: exprf(format, a...)}
863 }
864
865 func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
866 rr := &RuleRewrite{Loc: rule.Loc}
867 rr.Match, rr.Cond, rr.Result = rule.parse()
868 _, _, auxint, aux, s := extract(rr.Match)
869
870
871 if len(s) < data.controls {
872 log.Fatalf("incorrect number of arguments in %s, got %v wanted at least %v", rule, len(s), data.controls)
873 }
874 controls := s[:data.controls]
875 pos := make([]string, data.controls)
876 for i, arg := range controls {
877 cname := fmt.Sprintf("b.Controls[%v]", i)
878 if strings.Contains(arg, "(") {
879 vname, expr := splitNameExpr(arg)
880 if vname == "" {
881 vname = fmt.Sprintf("v_%v", i)
882 }
883 rr.add(declf(rr.Loc, vname, cname))
884 p, op := genMatch0(rr, arch, expr, vname, nil, false)
885 if op != "" {
886 check := fmt.Sprintf("%s.Op == %s", cname, op)
887 if rr.Check == "" {
888 rr.Check = check
889 } else {
890 rr.Check += " && " + check
891 }
892 }
893 if p == "" {
894 p = vname + ".Pos"
895 }
896 pos[i] = p
897 } else {
898 rr.add(declf(rr.Loc, arg, cname))
899 pos[i] = arg + ".Pos"
900 }
901 }
902 for _, e := range []struct {
903 name, field, dclType string
904 }{
905 {auxint, "AuxInt", data.auxIntType()},
906 {aux, "Aux", data.auxType()},
907 } {
908 if e.name == "" {
909 continue
910 }
911
912 if e.dclType == "" {
913 log.Fatalf("op %s has no declared type for %s", data.name, e.field)
914 }
915 if !token.IsIdentifier(e.name) || rr.declared(e.name) {
916 rr.add(breakf("%sTo%s(b.%s) != %s", unTitle(e.field), title(e.dclType), e.field, e.name))
917 } else {
918 rr.add(declf(rr.Loc, e.name, "%sTo%s(b.%s)", unTitle(e.field), title(e.dclType), e.field))
919 }
920 }
921 if rr.Cond != "" {
922 rr.add(breakf("!(%s)", rr.Cond))
923 }
924
925
926 outop, _, auxint, aux, t := extract(rr.Result)
927 blockName, outdata := getBlockInfo(outop, arch)
928 if len(t) < outdata.controls {
929 log.Fatalf("incorrect number of output arguments in %s, got %v wanted at least %v", rule, len(s), outdata.controls)
930 }
931
932
933 succs := s[data.controls:]
934 newsuccs := t[outdata.controls:]
935 m := map[string]bool{}
936 for _, succ := range succs {
937 if m[succ] {
938 log.Fatalf("can't have a repeat successor name %s in %s", succ, rule)
939 }
940 m[succ] = true
941 }
942 for _, succ := range newsuccs {
943 if !m[succ] {
944 log.Fatalf("unknown successor %s in %s", succ, rule)
945 }
946 delete(m, succ)
947 }
948 if len(m) != 0 {
949 log.Fatalf("unmatched successors %v in %s", m, rule)
950 }
951
952 var genControls [2]string
953 for i, control := range t[:outdata.controls] {
954
955
956
957
958 newpos := "b.Pos"
959 if i < len(pos) && pos[i] != "" {
960
961 newpos = pos[i]
962 }
963
964
965 genControls[i] = genResult0(rr, arch, control, false, false, newpos, nil)
966 }
967 switch outdata.controls {
968 case 0:
969 rr.add(stmtf("b.Reset(%s)", blockName))
970 case 1:
971 rr.add(stmtf("b.resetWithControl(%s, %s)", blockName, genControls[0]))
972 case 2:
973 rr.add(stmtf("b.resetWithControl2(%s, %s, %s)", blockName, genControls[0], genControls[1]))
974 default:
975 log.Fatalf("too many controls: %d", outdata.controls)
976 }
977
978 if auxint != "" {
979
980 rr.add(stmtf("b.AuxInt = %sToAuxInt(%s)", unTitle(outdata.auxIntType()), auxint))
981 }
982 if aux != "" {
983
984 rr.add(stmtf("b.Aux = %sToAux(%s)", unTitle(outdata.auxType()), aux))
985 }
986
987 succChanged := false
988 for i := 0; i < len(succs); i++ {
989 if succs[i] != newsuccs[i] {
990 succChanged = true
991 }
992 }
993 if succChanged {
994 if len(succs) != 2 {
995 log.Fatalf("changed successors, len!=2 in %s", rule)
996 }
997 if succs[0] != newsuccs[1] || succs[1] != newsuccs[0] {
998 log.Fatalf("can only handle swapped successors in %s", rule)
999 }
1000 rr.add(stmtf("b.swapSuccessors()"))
1001 }
1002
1003 if *genLog {
1004 rr.add(stmtf("logRule(%q)", rule.Loc))
1005 }
1006 return rr
1007 }
1008
1009
1010
1011 func genMatch(rr *RuleRewrite, arch arch, match string, pregenTop bool) (pos, checkOp string) {
1012 cnt := varCount(rr)
1013 return genMatch0(rr, arch, match, "v", cnt, pregenTop)
1014 }
1015
1016 func genMatch0(rr *RuleRewrite, arch arch, match, v string, cnt map[string]int, pregenTop bool) (pos, checkOp string) {
1017 if match[0] != '(' || match[len(match)-1] != ')' {
1018 log.Fatalf("%s: non-compound expr in genMatch0: %q", rr.Loc, match)
1019 }
1020 op, oparch, typ, auxint, aux, args := parseValue(match, arch, rr.Loc)
1021
1022 checkOp = fmt.Sprintf("Op%s%s", oparch, op.name)
1023
1024 if op.faultOnNilArg0 || op.faultOnNilArg1 {
1025
1026 pos = v + ".Pos"
1027 }
1028
1029
1030
1031
1032
1033 if op.argLength == -1 {
1034 l := len(args)
1035 if l == 0 || args[l-1] != "___" {
1036 rr.add(breakf("len(%s.Args) != %d", v, l))
1037 } else if l > 1 && args[l-1] == "___" {
1038 rr.add(breakf("len(%s.Args) < %d", v, l-1))
1039 }
1040 }
1041
1042 for _, e := range []struct {
1043 name, field, dclType string
1044 }{
1045 {typ, "Type", "*types.Type"},
1046 {auxint, "AuxInt", op.auxIntType()},
1047 {aux, "Aux", op.auxType()},
1048 } {
1049 if e.name == "" {
1050 continue
1051 }
1052
1053 if e.dclType == "" {
1054 log.Fatalf("op %s has no declared type for %s", op.name, e.field)
1055 }
1056 if !token.IsIdentifier(e.name) || rr.declared(e.name) {
1057 switch e.field {
1058 case "Aux":
1059 rr.add(breakf("auxTo%s(%s.%s) != %s", title(e.dclType), v, e.field, e.name))
1060 case "AuxInt":
1061 rr.add(breakf("auxIntTo%s(%s.%s) != %s", title(e.dclType), v, e.field, e.name))
1062 case "Type":
1063 rr.add(breakf("%s.%s != %s", v, e.field, e.name))
1064 }
1065 } else {
1066 switch e.field {
1067 case "Aux":
1068 rr.add(declf(rr.Loc, e.name, "auxTo%s(%s.%s)", title(e.dclType), v, e.field))
1069 case "AuxInt":
1070 rr.add(declf(rr.Loc, e.name, "auxIntTo%s(%s.%s)", title(e.dclType), v, e.field))
1071 case "Type":
1072 rr.add(declf(rr.Loc, e.name, "%s.%s", v, e.field))
1073 }
1074 }
1075 }
1076
1077 commutative := op.commutative
1078 if commutative {
1079 if args[0] == args[1] {
1080
1081
1082
1083
1084 commutative = false
1085 }
1086 if cnt[args[0]] == 1 && cnt[args[1]] == 1 {
1087
1088
1089
1090 commutative = false
1091 }
1092 }
1093
1094 if !pregenTop {
1095
1096 for n := len(args) - 1; n > 0; n-- {
1097 a := args[n]
1098 if a == "_" {
1099 continue
1100 }
1101 if !rr.declared(a) && token.IsIdentifier(a) && !(commutative && len(args) == 2) {
1102 rr.add(declf(rr.Loc, a, "%s.Args[%d]", v, n))
1103
1104 args = args[:n]
1105 } else {
1106 rr.add(stmtf("_ = %s.Args[%d]", v, n))
1107 }
1108 break
1109 }
1110 }
1111 if commutative && !pregenTop {
1112 for i := 0; i <= 1; i++ {
1113 vname := fmt.Sprintf("%s_%d", v, i)
1114 rr.add(declf(rr.Loc, vname, "%s.Args[%d]", v, i))
1115 }
1116 }
1117 if commutative {
1118 rr.add(StartCommuteLoop{rr.CommuteDepth, v})
1119 rr.CommuteDepth++
1120 }
1121 for i, arg := range args {
1122 if arg == "_" {
1123 continue
1124 }
1125 var rhs string
1126 if (commutative && i < 2) || pregenTop {
1127 rhs = fmt.Sprintf("%s_%d", v, i)
1128 } else {
1129 rhs = fmt.Sprintf("%s.Args[%d]", v, i)
1130 }
1131 if !strings.Contains(arg, "(") {
1132
1133 if rr.declared(arg) {
1134
1135
1136
1137
1138 rr.add(breakf("%s != %s", arg, rhs))
1139 } else {
1140 if arg != rhs {
1141 rr.add(declf(rr.Loc, arg, "%s", rhs))
1142 }
1143 }
1144 continue
1145 }
1146
1147 argname, expr := splitNameExpr(arg)
1148 if argname == "" {
1149 argname = fmt.Sprintf("%s_%d", v, i)
1150 }
1151 if argname == "b" {
1152 log.Fatalf("don't name args 'b', it is ambiguous with blocks")
1153 }
1154
1155 if argname != rhs {
1156 rr.add(declf(rr.Loc, argname, "%s", rhs))
1157 }
1158 bexpr := exprf("%s.Op != addLater", argname)
1159 rr.add(&CondBreak{Cond: bexpr})
1160 argPos, argCheckOp := genMatch0(rr, arch, expr, argname, cnt, false)
1161 bexpr.(*ast.BinaryExpr).Y.(*ast.Ident).Name = argCheckOp
1162
1163 if argPos != "" {
1164
1165
1166
1167
1168
1169 pos = argPos
1170 }
1171 }
1172
1173 return pos, checkOp
1174 }
1175
1176 func genResult(rr *RuleRewrite, arch arch, result, pos string) {
1177 move := result[0] == '@'
1178 if move {
1179
1180 s := strings.SplitN(result[1:], " ", 2)
1181 rr.add(stmtf("b = %s", s[0]))
1182 result = s[1]
1183 }
1184 cse := make(map[string]string)
1185 genResult0(rr, arch, result, true, move, pos, cse)
1186 }
1187
1188 func genResult0(rr *RuleRewrite, arch arch, result string, top, move bool, pos string, cse map[string]string) string {
1189 resname, expr := splitNameExpr(result)
1190 result = expr
1191
1192
1193 if result[0] != '(' {
1194
1195 if top {
1196
1197
1198
1199 rr.add(stmtf("v.copyOf(%s)", result))
1200 }
1201 return result
1202 }
1203
1204 w := normalizeWhitespace(result)
1205 if prev := cse[w]; prev != "" {
1206 return prev
1207 }
1208
1209 op, oparch, typ, auxint, aux, args := parseValue(result, arch, rr.Loc)
1210
1211
1212 typeOverride := typ != ""
1213 if typ == "" && op.typ != "" {
1214 typ = typeName(op.typ)
1215 }
1216
1217 v := "v"
1218 if top && !move {
1219 rr.add(stmtf("v.reset(Op%s%s)", oparch, op.name))
1220 if typeOverride {
1221 rr.add(stmtf("v.Type = %s", typ))
1222 }
1223 } else {
1224 if typ == "" {
1225 log.Fatalf("sub-expression %s (op=Op%s%s) at %s must have a type", result, oparch, op.name, rr.Loc)
1226 }
1227 if resname == "" {
1228 v = fmt.Sprintf("v%d", rr.Alloc)
1229 } else {
1230 v = resname
1231 }
1232 rr.Alloc++
1233 rr.add(declf(rr.Loc, v, "b.NewValue0(%s, Op%s%s, %s)", pos, oparch, op.name, typ))
1234 if move && top {
1235
1236 rr.add(stmtf("v.copyOf(%s)", v))
1237 }
1238 }
1239
1240 if auxint != "" {
1241
1242 rr.add(stmtf("%s.AuxInt = %sToAuxInt(%s)", v, unTitle(op.auxIntType()), auxint))
1243 }
1244 if aux != "" {
1245
1246 rr.add(stmtf("%s.Aux = %sToAux(%s)", v, unTitle(op.auxType()), aux))
1247 }
1248 all := new(strings.Builder)
1249 for i, arg := range args {
1250 x := genResult0(rr, arch, arg, false, move, pos, cse)
1251 if i > 0 {
1252 all.WriteString(", ")
1253 }
1254 all.WriteString(x)
1255 }
1256 switch len(args) {
1257 case 0:
1258 case 1:
1259 rr.add(stmtf("%s.AddArg(%s)", v, all.String()))
1260 default:
1261 rr.add(stmtf("%s.AddArg%d(%s)", v, len(args), all.String()))
1262 }
1263
1264 if cse != nil {
1265 cse[w] = v
1266 }
1267 return v
1268 }
1269
1270 func split(s string) []string {
1271 var r []string
1272
1273 outer:
1274 for s != "" {
1275 d := 0
1276 var open, close byte
1277 nonsp := false
1278 for i := 0; i < len(s); i++ {
1279 switch {
1280 case d == 0 && s[i] == '(':
1281 open, close = '(', ')'
1282 d++
1283 case d == 0 && s[i] == '<':
1284 open, close = '<', '>'
1285 d++
1286 case d == 0 && s[i] == '[':
1287 open, close = '[', ']'
1288 d++
1289 case d == 0 && s[i] == '{':
1290 open, close = '{', '}'
1291 d++
1292 case d == 0 && (s[i] == ' ' || s[i] == '\t'):
1293 if nonsp {
1294 r = append(r, strings.TrimSpace(s[:i]))
1295 s = s[i:]
1296 continue outer
1297 }
1298 case d > 0 && s[i] == open:
1299 d++
1300 case d > 0 && s[i] == close:
1301 d--
1302 default:
1303 nonsp = true
1304 }
1305 }
1306 if d != 0 {
1307 log.Fatalf("imbalanced expression: %q", s)
1308 }
1309 if nonsp {
1310 r = append(r, strings.TrimSpace(s))
1311 }
1312 break
1313 }
1314 return r
1315 }
1316
1317
1318 func isBlock(name string, arch arch) bool {
1319 for _, b := range genericBlocks {
1320 if b.name == name {
1321 return true
1322 }
1323 }
1324 for _, b := range arch.blocks {
1325 if b.name == name {
1326 return true
1327 }
1328 }
1329 return false
1330 }
1331
1332 func extract(val string) (op, typ, auxint, aux string, args []string) {
1333 val = val[1 : len(val)-1]
1334
1335
1336
1337 s := split(val)
1338
1339
1340 op = s[0]
1341 for _, a := range s[1:] {
1342 switch a[0] {
1343 case '<':
1344 typ = a[1 : len(a)-1]
1345 case '[':
1346 auxint = a[1 : len(a)-1]
1347 case '{':
1348 aux = a[1 : len(a)-1]
1349 default:
1350 args = append(args, a)
1351 }
1352 }
1353 return
1354 }
1355
1356
1357
1358
1359
1360 func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxint, aux string, args []string) {
1361
1362 var s string
1363 s, typ, auxint, aux, args = extract(val)
1364
1365
1366
1367
1368
1369
1370
1371 match := func(x opData, strict bool, archname string) bool {
1372 if x.name != s {
1373 return false
1374 }
1375 if x.argLength != -1 && int(x.argLength) != len(args) && (len(args) != 1 || args[0] != "...") {
1376 if strict {
1377 return false
1378 }
1379 log.Printf("%s: op %s (%s) should have %d args, has %d", loc, s, archname, x.argLength, len(args))
1380 }
1381 return true
1382 }
1383
1384 for _, x := range genericOps {
1385 if match(x, true, "generic") {
1386 op = x
1387 break
1388 }
1389 }
1390 for _, x := range arch.ops {
1391 if arch.name != "generic" && match(x, true, arch.name) {
1392 if op.name != "" {
1393 log.Fatalf("%s: matches for op %s found in both generic and %s", loc, op.name, arch.name)
1394 }
1395 op = x
1396 oparch = arch.name
1397 break
1398 }
1399 }
1400
1401 if op.name == "" {
1402
1403
1404
1405 for _, x := range genericOps {
1406 match(x, false, "generic")
1407 }
1408 for _, x := range arch.ops {
1409 match(x, false, arch.name)
1410 }
1411 log.Fatalf("%s: unknown op %s", loc, s)
1412 }
1413
1414
1415 if auxint != "" && !opHasAuxInt(op) {
1416 log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
1417 }
1418 if aux != "" && !opHasAux(op) {
1419 log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
1420 }
1421 return
1422 }
1423
1424 func opHasAuxInt(op opData) bool {
1425 switch op.aux {
1426 case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "UInt8", "Float32", "Float64",
1427 "SymOff", "CallOff", "SymValAndOff", "TypSize", "ARM64BitField", "FlagConstant", "CCop":
1428 return true
1429 }
1430 return false
1431 }
1432
1433 func opHasAux(op opData) bool {
1434 switch op.aux {
1435 case "String", "Sym", "SymOff", "Call", "CallOff", "SymValAndOff", "Typ", "TypSize",
1436 "S390XCCMask", "S390XRotateParams":
1437 return true
1438 }
1439 return false
1440 }
1441
1442
1443
1444
1445
1446 func splitNameExpr(arg string) (name, expr string) {
1447 colon := strings.Index(arg, ":")
1448 if colon < 0 {
1449 return "", arg
1450 }
1451 openparen := strings.Index(arg, "(")
1452 if openparen < 0 {
1453 log.Fatalf("splitNameExpr(%q): colon but no open parens", arg)
1454 }
1455 if colon > openparen {
1456
1457 return "", arg
1458 }
1459 return arg[:colon], arg[colon+1:]
1460 }
1461
1462 func getBlockInfo(op string, arch arch) (name string, data blockData) {
1463 for _, b := range genericBlocks {
1464 if b.name == op {
1465 return "Block" + op, b
1466 }
1467 }
1468 for _, b := range arch.blocks {
1469 if b.name == op {
1470 return "Block" + arch.name + op, b
1471 }
1472 }
1473 log.Fatalf("could not find block data for %s", op)
1474 panic("unreachable")
1475 }
1476
1477
1478 func typeName(typ string) string {
1479 if typ[0] == '(' {
1480 ts := strings.Split(typ[1:len(typ)-1], ",")
1481 if len(ts) != 2 {
1482 log.Fatalf("Tuple expect 2 arguments")
1483 }
1484 return "types.NewTuple(" + typeName(ts[0]) + ", " + typeName(ts[1]) + ")"
1485 }
1486 switch typ {
1487 case "Flags", "Mem", "Void", "Int128":
1488 return "types.Type" + typ
1489 default:
1490 return "typ." + typ
1491 }
1492 }
1493
1494
1495
1496 func balance(s string) int {
1497 balance := 0
1498 for _, c := range s {
1499 switch c {
1500 case '(':
1501 balance++
1502 case ')':
1503 balance--
1504 if balance < 0 {
1505
1506 return -1
1507 }
1508 }
1509 }
1510 return balance
1511 }
1512
1513
1514 var findAllOpcode = regexp.MustCompile(`[(](\w+[|])+\w+[)]`).FindAllStringIndex
1515
1516
1517
1518
1519
1520 func excludeFromExpansion(s string, idx []int) bool {
1521 left := s[:idx[0]]
1522 if strings.LastIndexByte(left, '[') > strings.LastIndexByte(left, ']') {
1523
1524 return true
1525 }
1526 right := s[idx[1]:]
1527 if strings.Contains(left, "&&") && strings.Contains(right, "=>") {
1528
1529 return true
1530 }
1531 return false
1532 }
1533
1534
1535 func expandOr(r string) []string {
1536
1537
1538
1539
1540
1541 n := 1
1542 for _, idx := range findAllOpcode(r, -1) {
1543 if excludeFromExpansion(r, idx) {
1544 continue
1545 }
1546 s := r[idx[0]:idx[1]]
1547 c := strings.Count(s, "|") + 1
1548 if c == 1 {
1549 continue
1550 }
1551 if n > 1 && n != c {
1552 log.Fatalf("'|' count doesn't match in %s: both %d and %d\n", r, n, c)
1553 }
1554 n = c
1555 }
1556 if n == 1 {
1557
1558 return []string{r}
1559 }
1560
1561 res := make([]string, n)
1562 for i := 0; i < n; i++ {
1563 buf := new(strings.Builder)
1564 x := 0
1565 for _, idx := range findAllOpcode(r, -1) {
1566 if excludeFromExpansion(r, idx) {
1567 continue
1568 }
1569 buf.WriteString(r[x:idx[0]])
1570 s := r[idx[0]+1 : idx[1]-1]
1571 buf.WriteString(strings.Split(s, "|")[i])
1572 x = idx[1]
1573 }
1574 buf.WriteString(r[x:])
1575 res[i] = buf.String()
1576 }
1577 return res
1578 }
1579
1580
1581
1582 func varCount(rr *RuleRewrite) map[string]int {
1583 cnt := map[string]int{}
1584 varCount1(rr.Loc, rr.Match, cnt)
1585 if rr.Cond != "" {
1586 expr, err := parser.ParseExpr(rr.Cond)
1587 if err != nil {
1588 log.Fatalf("%s: failed to parse cond %q: %v", rr.Loc, rr.Cond, err)
1589 }
1590 ast.Inspect(expr, func(n ast.Node) bool {
1591 if id, ok := n.(*ast.Ident); ok {
1592 cnt[id.Name]++
1593 }
1594 return true
1595 })
1596 }
1597 return cnt
1598 }
1599
1600 func varCount1(loc, m string, cnt map[string]int) {
1601 if m[0] == '<' || m[0] == '[' || m[0] == '{' {
1602 return
1603 }
1604 if token.IsIdentifier(m) {
1605 cnt[m]++
1606 return
1607 }
1608
1609 name, expr := splitNameExpr(m)
1610 if name != "" {
1611 cnt[name]++
1612 }
1613 if expr[0] != '(' || expr[len(expr)-1] != ')' {
1614 log.Fatalf("%s: non-compound expr in varCount1: %q", loc, expr)
1615 }
1616 s := split(expr[1 : len(expr)-1])
1617 for _, arg := range s[1:] {
1618 varCount1(loc, arg, cnt)
1619 }
1620 }
1621
1622
1623 func normalizeWhitespace(x string) string {
1624 x = strings.Join(strings.Fields(x), " ")
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 x = strings.Replace(x, ")=>", ") =>", -1)
1630 return x
1631 }
1632
1633
1634 func opIsCommutative(op string, arch arch) bool {
1635 for _, x := range genericOps {
1636 if op == x.name {
1637 if x.commutative {
1638 return true
1639 }
1640 break
1641 }
1642 }
1643 if arch.name != "generic" {
1644 for _, x := range arch.ops {
1645 if op == x.name {
1646 if x.commutative {
1647 return true
1648 }
1649 break
1650 }
1651 }
1652 }
1653 return false
1654 }
1655
1656 func normalizeMatch(m string, arch arch) string {
1657 if token.IsIdentifier(m) {
1658 return m
1659 }
1660 op, typ, auxint, aux, args := extract(m)
1661 if opIsCommutative(op, arch) {
1662 if args[1] < args[0] {
1663 args[0], args[1] = args[1], args[0]
1664 }
1665 }
1666 s := new(strings.Builder)
1667 fmt.Fprintf(s, "%s <%s> [%s] {%s}", op, typ, auxint, aux)
1668 for _, arg := range args {
1669 prefix, expr := splitNameExpr(arg)
1670 fmt.Fprint(s, " ", prefix, normalizeMatch(expr, arch))
1671 }
1672 return s.String()
1673 }
1674
1675 func parseEllipsisRules(rules []Rule, arch arch) (newop string, ok bool) {
1676 if len(rules) != 1 {
1677 for _, r := range rules {
1678 if strings.Contains(r.Rule, "...") {
1679 log.Fatalf("%s: found ellipsis in rule, but there are other rules with the same op", r.Loc)
1680 }
1681 }
1682 return "", false
1683 }
1684 rule := rules[0]
1685 match, cond, result := rule.parse()
1686 if cond != "" || !isEllipsisValue(match) || !isEllipsisValue(result) {
1687 if strings.Contains(rule.Rule, "...") {
1688 log.Fatalf("%s: found ellipsis in non-ellipsis rule", rule.Loc)
1689 }
1690 checkEllipsisRuleCandidate(rule, arch)
1691 return "", false
1692 }
1693 op, oparch, _, _, _, _ := parseValue(result, arch, rule.Loc)
1694 return fmt.Sprintf("Op%s%s", oparch, op.name), true
1695 }
1696
1697
1698 func isEllipsisValue(s string) bool {
1699 if len(s) < 2 || s[0] != '(' || s[len(s)-1] != ')' {
1700 return false
1701 }
1702 c := split(s[1 : len(s)-1])
1703 if len(c) != 2 || c[1] != "..." {
1704 return false
1705 }
1706 return true
1707 }
1708
1709 func checkEllipsisRuleCandidate(rule Rule, arch arch) {
1710 match, cond, result := rule.parse()
1711 if cond != "" {
1712 return
1713 }
1714 op, _, _, auxint, aux, args := parseValue(match, arch, rule.Loc)
1715 var auxint2, aux2 string
1716 var args2 []string
1717 var usingCopy string
1718 var eop opData
1719 if result[0] != '(' {
1720
1721 args2 = []string{result}
1722 usingCopy = " using Copy"
1723 } else {
1724 eop, _, _, auxint2, aux2, args2 = parseValue(result, arch, rule.Loc)
1725 }
1726
1727 if aux != aux2 || auxint != auxint2 || len(args) != len(args2) {
1728 return
1729 }
1730 if strings.Contains(rule.Rule, "=>") && op.aux != eop.aux {
1731 return
1732 }
1733 for i := range args {
1734 if args[i] != args2[i] {
1735 return
1736 }
1737 }
1738 switch {
1739 case opHasAux(op) && aux == "" && aux2 == "":
1740 fmt.Printf("%s: rule silently zeros aux, either copy aux or explicitly zero\n", rule.Loc)
1741 case opHasAuxInt(op) && auxint == "" && auxint2 == "":
1742 fmt.Printf("%s: rule silently zeros auxint, either copy auxint or explicitly zero\n", rule.Loc)
1743 default:
1744 fmt.Printf("%s: possible ellipsis rule candidate%s: %q\n", rule.Loc, usingCopy, rule.Rule)
1745 }
1746 }
1747
1748 func opByName(arch arch, name string) opData {
1749 name = name[2:]
1750 for _, x := range genericOps {
1751 if name == x.name {
1752 return x
1753 }
1754 }
1755 if arch.name != "generic" {
1756 name = name[len(arch.name):]
1757 for _, x := range arch.ops {
1758 if name == x.name {
1759 return x
1760 }
1761 }
1762 }
1763 log.Fatalf("failed to find op named %s in arch %s", name, arch.name)
1764 panic("unreachable")
1765 }
1766
1767
1768 func (op opData) auxType() string {
1769 switch op.aux {
1770 case "String":
1771 return "string"
1772 case "Sym":
1773
1774 return "Sym"
1775 case "SymOff":
1776 return "Sym"
1777 case "Call":
1778 return "Call"
1779 case "CallOff":
1780 return "Call"
1781 case "SymValAndOff":
1782 return "Sym"
1783 case "Typ":
1784 return "*types.Type"
1785 case "TypSize":
1786 return "*types.Type"
1787 case "S390XCCMask":
1788 return "s390x.CCMask"
1789 case "S390XRotateParams":
1790 return "s390x.RotateParams"
1791 default:
1792 return "invalid"
1793 }
1794 }
1795
1796
1797 func (op opData) auxIntType() string {
1798 switch op.aux {
1799 case "Bool":
1800 return "bool"
1801 case "Int8":
1802 return "int8"
1803 case "Int16":
1804 return "int16"
1805 case "Int32":
1806 return "int32"
1807 case "Int64":
1808 return "int64"
1809 case "Int128":
1810 return "int128"
1811 case "UInt8":
1812 return "uint8"
1813 case "Float32":
1814 return "float32"
1815 case "Float64":
1816 return "float64"
1817 case "CallOff":
1818 return "int32"
1819 case "SymOff":
1820 return "int32"
1821 case "SymValAndOff":
1822 return "ValAndOff"
1823 case "TypSize":
1824 return "int64"
1825 case "CCop":
1826 return "Op"
1827 case "FlagConstant":
1828 return "flagConstant"
1829 case "ARM64BitField":
1830 return "arm64BitField"
1831 default:
1832 return "invalid"
1833 }
1834 }
1835
1836
1837 func (b blockData) auxType() string {
1838 switch b.aux {
1839 case "Sym":
1840 return "Sym"
1841 case "S390XCCMask", "S390XCCMaskInt8", "S390XCCMaskUint8":
1842 return "s390x.CCMask"
1843 case "S390XRotateParams":
1844 return "s390x.RotateParams"
1845 default:
1846 return "invalid"
1847 }
1848 }
1849
1850
1851 func (b blockData) auxIntType() string {
1852 switch b.aux {
1853 case "S390XCCMaskInt8":
1854 return "int8"
1855 case "S390XCCMaskUint8":
1856 return "uint8"
1857 case "Int64":
1858 return "int64"
1859 default:
1860 return "invalid"
1861 }
1862 }
1863
1864 func title(s string) string {
1865 if i := strings.Index(s, "."); i >= 0 {
1866 switch strings.ToLower(s[:i]) {
1867 case "s390x":
1868 s = s[:i] + s[i+1:]
1869 default:
1870 s = s[i+1:]
1871 }
1872 }
1873 return strings.Title(s)
1874 }
1875
1876 func unTitle(s string) string {
1877 if i := strings.Index(s, "."); i >= 0 {
1878 switch strings.ToLower(s[:i]) {
1879 case "s390x":
1880 s = s[:i] + s[i+1:]
1881 default:
1882 s = s[i+1:]
1883 }
1884 }
1885 return strings.ToLower(s[:1]) + s[1:]
1886 }
1887
View as plain text