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