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 case 2, 3, 4, 5, 6:
1275 rr.add(stmtf("%s.AddArg%d(%s)", v, len(args), all.String()))
1276 default:
1277 rr.add(stmtf("%s.AddArgs(%s)", v, all.String()))
1278 }
1279
1280 if cse != nil {
1281 cse[w] = v
1282 }
1283 return v
1284 }
1285
1286 func split(s string) []string {
1287 var r []string
1288
1289 outer:
1290 for s != "" {
1291 d := 0
1292 var open, close byte
1293 nonsp := false
1294 for i := 0; i < len(s); i++ {
1295 switch {
1296 case d == 0 && s[i] == '(':
1297 open, close = '(', ')'
1298 d++
1299 case d == 0 && s[i] == '<':
1300 open, close = '<', '>'
1301 d++
1302 case d == 0 && s[i] == '[':
1303 open, close = '[', ']'
1304 d++
1305 case d == 0 && s[i] == '{':
1306 open, close = '{', '}'
1307 d++
1308 case d == 0 && (s[i] == ' ' || s[i] == '\t'):
1309 if nonsp {
1310 r = append(r, strings.TrimSpace(s[:i]))
1311 s = s[i:]
1312 continue outer
1313 }
1314 case d > 0 && s[i] == open:
1315 d++
1316 case d > 0 && s[i] == close:
1317 d--
1318 case s[i] == ':':
1319
1320 nonsp = true
1321 for i+1 < len(s) && (s[i+1] == ' ' || s[i+1] == '\t') {
1322 i++
1323 }
1324 default:
1325 nonsp = true
1326 }
1327 }
1328 if d != 0 {
1329 log.Fatalf("imbalanced expression: %q", s)
1330 }
1331 if nonsp {
1332 r = append(r, strings.TrimSpace(s))
1333 }
1334 break
1335 }
1336 return r
1337 }
1338
1339
1340 func isBlock(name string, arch arch) bool {
1341 for _, b := range genericBlocks {
1342 if b.name == name {
1343 return true
1344 }
1345 }
1346 for _, b := range arch.blocks {
1347 if b.name == name {
1348 return true
1349 }
1350 }
1351 return false
1352 }
1353
1354 func extract(val string) (op, typ, auxint, aux string, args []string) {
1355 val = val[1 : len(val)-1]
1356
1357
1358
1359 s := split(val)
1360
1361
1362 op = s[0]
1363 for _, a := range s[1:] {
1364 switch a[0] {
1365 case '<':
1366 typ = a[1 : len(a)-1]
1367 case '[':
1368 auxint = a[1 : len(a)-1]
1369 case '{':
1370 aux = a[1 : len(a)-1]
1371 default:
1372 args = append(args, a)
1373 }
1374 }
1375 return
1376 }
1377
1378
1379
1380
1381
1382 func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxint, aux string, args []string) {
1383
1384 var s string
1385 s, typ, auxint, aux, args = extract(val)
1386
1387
1388
1389
1390
1391
1392
1393 match := func(x opData, strict bool, archname string) bool {
1394 if x.name != s {
1395 return false
1396 }
1397 if x.argLength != -1 && int(x.argLength) != len(args) && (len(args) != 1 || args[0] != "...") {
1398 if strict {
1399 return false
1400 }
1401 log.Printf("%s: op %s (%s) should have %d args, has %d", loc, s, archname, x.argLength, len(args))
1402 }
1403 return true
1404 }
1405
1406 for _, x := range genericOps {
1407 if match(x, true, "generic") {
1408 op = x
1409 break
1410 }
1411 }
1412 for _, x := range arch.ops {
1413 if arch.name != "generic" && match(x, true, arch.name) {
1414 if op.name != "" {
1415 log.Fatalf("%s: matches for op %s found in both generic and %s", loc, op.name, arch.name)
1416 }
1417 op = x
1418 oparch = arch.name
1419 break
1420 }
1421 }
1422
1423 if op.name == "" {
1424
1425
1426
1427 for _, x := range genericOps {
1428 match(x, false, "generic")
1429 }
1430 for _, x := range arch.ops {
1431 match(x, false, arch.name)
1432 }
1433 log.Fatalf("%s: unknown op %s", loc, s)
1434 }
1435
1436
1437 if auxint != "" && !opHasAuxInt(op) {
1438 log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
1439 }
1440 if aux != "" && !opHasAux(op) {
1441 log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
1442 }
1443 return
1444 }
1445
1446 func opHasAuxInt(op opData) bool {
1447 switch op.aux {
1448 case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "UInt8", "Float32", "Float64",
1449 "SymOff", "CallOff", "SymValAndOff", "TypSize", "ARM64BitField", "FlagConstant", "CCop",
1450 "PanicBoundsC", "PanicBoundsCC", "ARM64ConditionalParams":
1451 return true
1452 }
1453 return false
1454 }
1455
1456 func opHasAux(op opData) bool {
1457 switch op.aux {
1458 case "String", "Sym", "SymOff", "Call", "CallOff", "SymValAndOff", "Typ", "TypSize",
1459 "S390XCCMask", "S390XRotateParams", "PanicBoundsC", "PanicBoundsCC":
1460 return true
1461 }
1462 return false
1463 }
1464
1465
1466
1467
1468
1469 func splitNameExpr(arg string) (name, expr string) {
1470 colon := strings.Index(arg, ":")
1471 if colon < 0 {
1472 return "", arg
1473 }
1474 openparen := strings.Index(arg, "(")
1475 if openparen < 0 {
1476 log.Fatalf("splitNameExpr(%q): colon but no open parens", arg)
1477 }
1478 if colon > openparen {
1479
1480 return "", arg
1481 }
1482 return arg[:colon], strings.TrimSpace(arg[colon+1:])
1483 }
1484
1485 func getBlockInfo(op string, arch arch) (name string, data blockData) {
1486 for _, b := range genericBlocks {
1487 if b.name == op {
1488 return "Block" + op, b
1489 }
1490 }
1491 for _, b := range arch.blocks {
1492 if b.name == op {
1493 return "Block" + arch.name + op, b
1494 }
1495 }
1496 log.Fatalf("could not find block data for %s", op)
1497 panic("unreachable")
1498 }
1499
1500
1501 func typeName(typ string) string {
1502 if typ[0] == '(' {
1503 ts := strings.Split(typ[1:len(typ)-1], ",")
1504 if len(ts) != 2 {
1505 log.Fatalf("Tuple expect 2 arguments")
1506 }
1507 return "types.NewTuple(" + typeName(ts[0]) + ", " + typeName(ts[1]) + ")"
1508 }
1509 switch typ {
1510 case "Flags", "Mem", "Void", "Int128":
1511 return "types.Type" + typ
1512 default:
1513 return "typ." + typ
1514 }
1515 }
1516
1517
1518
1519 func balance(s string) int {
1520 balance := 0
1521 for _, c := range s {
1522 switch c {
1523 case '(':
1524 balance++
1525 case ')':
1526 balance--
1527 if balance < 0 {
1528
1529 return -1
1530 }
1531 }
1532 }
1533 return balance
1534 }
1535
1536
1537 var findAllOpcode = regexp.MustCompile(`[(](\w+[|])+\w+[)]`).FindAllStringIndex
1538
1539
1540
1541
1542
1543 func excludeFromExpansion(s string, idx []int) bool {
1544 left := s[:idx[0]]
1545 if strings.LastIndexByte(left, '[') > strings.LastIndexByte(left, ']') {
1546
1547 return true
1548 }
1549 right := s[idx[1]:]
1550 if strings.Contains(left, "&&") && strings.Contains(right, "=>") {
1551
1552 return true
1553 }
1554 return false
1555 }
1556
1557
1558 func expandOr(r string) []string {
1559
1560
1561
1562
1563
1564 n := 1
1565 for _, idx := range findAllOpcode(r, -1) {
1566 if excludeFromExpansion(r, idx) {
1567 continue
1568 }
1569 s := r[idx[0]:idx[1]]
1570 c := strings.Count(s, "|") + 1
1571 if c == 1 {
1572 continue
1573 }
1574 if n > 1 && n != c {
1575 log.Fatalf("'|' count doesn't match in %s: both %d and %d\n", r, n, c)
1576 }
1577 n = c
1578 }
1579 if n == 1 {
1580
1581 return []string{r}
1582 }
1583
1584 res := make([]string, n)
1585 for i := 0; i < n; i++ {
1586 buf := new(strings.Builder)
1587 x := 0
1588 for _, idx := range findAllOpcode(r, -1) {
1589 if excludeFromExpansion(r, idx) {
1590 continue
1591 }
1592 buf.WriteString(r[x:idx[0]])
1593 s := r[idx[0]+1 : idx[1]-1]
1594 buf.WriteString(strings.Split(s, "|")[i])
1595 x = idx[1]
1596 }
1597 buf.WriteString(r[x:])
1598 res[i] = buf.String()
1599 }
1600 return res
1601 }
1602
1603
1604
1605 func varCount(rr *RuleRewrite) map[string]int {
1606 cnt := map[string]int{}
1607 varCount1(rr.Loc, rr.Match, cnt)
1608 if rr.Cond != "" {
1609 expr, err := parser.ParseExpr(rr.Cond)
1610 if err != nil {
1611 log.Fatalf("%s: failed to parse cond %q: %v", rr.Loc, rr.Cond, err)
1612 }
1613 ast.Inspect(expr, func(n ast.Node) bool {
1614 if id, ok := n.(*ast.Ident); ok {
1615 cnt[id.Name]++
1616 }
1617 return true
1618 })
1619 }
1620 return cnt
1621 }
1622
1623 func varCount1(loc, m string, cnt map[string]int) {
1624 if m[0] == '<' || m[0] == '[' || m[0] == '{' {
1625 return
1626 }
1627 if token.IsIdentifier(m) {
1628 cnt[m]++
1629 return
1630 }
1631
1632 name, expr := splitNameExpr(m)
1633 if name != "" {
1634 cnt[name]++
1635 }
1636 if expr[0] != '(' || expr[len(expr)-1] != ')' {
1637 log.Fatalf("%s: non-compound expr in varCount1: %q", loc, expr)
1638 }
1639 s := split(expr[1 : len(expr)-1])
1640 for _, arg := range s[1:] {
1641 varCount1(loc, arg, cnt)
1642 }
1643 }
1644
1645
1646 func normalizeWhitespace(x string) string {
1647 x = strings.Join(strings.Fields(x), " ")
1648 x = strings.ReplaceAll(x, "( ", "(")
1649 x = strings.ReplaceAll(x, " )", ")")
1650 x = strings.ReplaceAll(x, "[ ", "[")
1651 x = strings.ReplaceAll(x, " ]", "]")
1652 x = strings.ReplaceAll(x, ")=>", ") =>")
1653 return x
1654 }
1655
1656
1657 func opIsCommutative(op string, arch arch) bool {
1658 for _, x := range genericOps {
1659 if op == x.name {
1660 if x.commutative {
1661 return true
1662 }
1663 break
1664 }
1665 }
1666 if arch.name != "generic" {
1667 for _, x := range arch.ops {
1668 if op == x.name {
1669 if x.commutative {
1670 return true
1671 }
1672 break
1673 }
1674 }
1675 }
1676 return false
1677 }
1678
1679 func normalizeMatch(m string, arch arch) string {
1680 if token.IsIdentifier(m) {
1681 return m
1682 }
1683 op, typ, auxint, aux, args := extract(m)
1684 if opIsCommutative(op, arch) {
1685 if args[1] < args[0] {
1686 args[0], args[1] = args[1], args[0]
1687 }
1688 }
1689 s := new(strings.Builder)
1690 fmt.Fprintf(s, "%s <%s> [%s] {%s}", op, typ, auxint, aux)
1691 for _, arg := range args {
1692 prefix, expr := splitNameExpr(arg)
1693 fmt.Fprint(s, " ", prefix, normalizeMatch(expr, arch))
1694 }
1695 return s.String()
1696 }
1697
1698 func parseEllipsisRules(rules []Rule, arch arch) (newop string, ok bool) {
1699 if len(rules) != 1 {
1700 for _, r := range rules {
1701 if strings.Contains(r.Rule, "...") {
1702 log.Fatalf("%s: found ellipsis in rule, but there are other rules with the same op", r.Loc)
1703 }
1704 }
1705 return "", false
1706 }
1707 rule := rules[0]
1708 match, cond, result := rule.parse()
1709 if cond != "" || !isEllipsisValue(match) || !isEllipsisValue(result) {
1710 if strings.Contains(rule.Rule, "...") {
1711 log.Fatalf("%s: found ellipsis in non-ellipsis rule", rule.Loc)
1712 }
1713 checkEllipsisRuleCandidate(rule, arch)
1714 return "", false
1715 }
1716 op, oparch, _, _, _, _ := parseValue(result, arch, rule.Loc)
1717 return fmt.Sprintf("Op%s%s", oparch, op.name), true
1718 }
1719
1720
1721 func isEllipsisValue(s string) bool {
1722 if len(s) < 2 || s[0] != '(' || s[len(s)-1] != ')' {
1723 return false
1724 }
1725 c := split(s[1 : len(s)-1])
1726 if len(c) != 2 || c[1] != "..." {
1727 return false
1728 }
1729 return true
1730 }
1731
1732 func checkEllipsisRuleCandidate(rule Rule, arch arch) {
1733 match, cond, result := rule.parse()
1734 if cond != "" {
1735 return
1736 }
1737 op, _, _, auxint, aux, args := parseValue(match, arch, rule.Loc)
1738 var auxint2, aux2 string
1739 var args2 []string
1740 var usingCopy string
1741 var eop opData
1742 if result[0] != '(' {
1743
1744 args2 = []string{result}
1745 usingCopy = " using Copy"
1746 } else {
1747 eop, _, _, auxint2, aux2, args2 = parseValue(result, arch, rule.Loc)
1748 }
1749
1750 if aux != aux2 || auxint != auxint2 || len(args) != len(args2) {
1751 return
1752 }
1753 if strings.Contains(rule.Rule, "=>") && op.aux != eop.aux {
1754 return
1755 }
1756 for i := range args {
1757 if args[i] != args2[i] {
1758 return
1759 }
1760 }
1761 switch {
1762 case opHasAux(op) && aux == "" && aux2 == "":
1763 fmt.Printf("%s: rule silently zeros aux, either copy aux or explicitly zero\n", rule.Loc)
1764 case opHasAuxInt(op) && auxint == "" && auxint2 == "":
1765 fmt.Printf("%s: rule silently zeros auxint, either copy auxint or explicitly zero\n", rule.Loc)
1766 default:
1767 fmt.Printf("%s: possible ellipsis rule candidate%s: %q\n", rule.Loc, usingCopy, rule.Rule)
1768 }
1769 }
1770
1771 func opByName(arch arch, name string) opData {
1772 name = name[2:]
1773 for _, x := range genericOps {
1774 if name == x.name {
1775 return x
1776 }
1777 }
1778 if arch.name != "generic" {
1779 name = name[len(arch.name):]
1780 for _, x := range arch.ops {
1781 if name == x.name {
1782 return x
1783 }
1784 }
1785 }
1786 log.Fatalf("failed to find op named %s in arch %s", name, arch.name)
1787 panic("unreachable")
1788 }
1789
1790
1791 func (op opData) auxType() string {
1792 switch op.aux {
1793 case "String":
1794 return "string"
1795 case "Sym":
1796
1797 return "Sym"
1798 case "SymOff":
1799 return "Sym"
1800 case "Call":
1801 return "Call"
1802 case "CallOff":
1803 return "Call"
1804 case "SymValAndOff":
1805 return "Sym"
1806 case "Typ":
1807 return "*types.Type"
1808 case "TypSize":
1809 return "*types.Type"
1810 case "S390XCCMask":
1811 return "s390x.CCMask"
1812 case "S390XRotateParams":
1813 return "s390x.RotateParams"
1814 case "PanicBoundsC":
1815 return "PanicBoundsC"
1816 case "PanicBoundsCC":
1817 return "PanicBoundsCC"
1818 default:
1819 return "invalid"
1820 }
1821 }
1822
1823
1824 func (op opData) auxIntType() string {
1825 switch op.aux {
1826 case "Bool":
1827 return "bool"
1828 case "Int8":
1829 return "int8"
1830 case "Int16":
1831 return "int16"
1832 case "Int32":
1833 return "int32"
1834 case "Int64":
1835 return "int64"
1836 case "Int128":
1837 return "int128"
1838 case "UInt8":
1839 return "uint8"
1840 case "Float32":
1841 return "float32"
1842 case "Float64":
1843 return "float64"
1844 case "CallOff":
1845 return "int32"
1846 case "SymOff":
1847 return "int32"
1848 case "SymValAndOff":
1849 return "ValAndOff"
1850 case "TypSize":
1851 return "int64"
1852 case "CCop":
1853 return "Op"
1854 case "FlagConstant":
1855 return "flagConstant"
1856 case "ARM64BitField":
1857 return "arm64BitField"
1858 case "ARM64ConditionalParams":
1859 return "arm64ConditionalParams"
1860 case "PanicBoundsC", "PanicBoundsCC":
1861 return "int64"
1862 default:
1863 return "invalid"
1864 }
1865 }
1866
1867
1868 func (b blockData) auxType() string {
1869 switch b.aux {
1870 case "Sym":
1871 return "Sym"
1872 case "S390XCCMask", "S390XCCMaskInt8", "S390XCCMaskUint8":
1873 return "s390x.CCMask"
1874 case "S390XRotateParams":
1875 return "s390x.RotateParams"
1876 default:
1877 return "invalid"
1878 }
1879 }
1880
1881
1882 func (b blockData) auxIntType() string {
1883 switch b.aux {
1884 case "S390XCCMaskInt8":
1885 return "int8"
1886 case "S390XCCMaskUint8":
1887 return "uint8"
1888 case "Int64":
1889 return "int64"
1890 default:
1891 return "invalid"
1892 }
1893 }
1894
1895 func title(s string) string {
1896 if i := strings.Index(s, "."); i >= 0 {
1897 switch strings.ToLower(s[:i]) {
1898 case "s390x":
1899 s = s[:i] + s[i+1:]
1900 default:
1901 s = s[i+1:]
1902 }
1903 }
1904 return strings.Title(s)
1905 }
1906
1907 func unTitle(s string) string {
1908 if i := strings.Index(s, "."); i >= 0 {
1909 switch strings.ToLower(s[:i]) {
1910 case "s390x":
1911 s = s[:i] + s[i+1:]
1912 default:
1913 s = s[i+1:]
1914 }
1915 }
1916 return strings.ToLower(s[:1]) + s[1:]
1917 }
1918
View as plain text