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