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