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