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