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