From 48d3c32ba9c2cbe4cfded44a150540f15fdf517c Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Sun, 10 Mar 2019 11:55:49 -0700 Subject: [PATCH] cmd/compile: teach rulegen to |-expand multiple |s in a single op I want to be able to write MOV(Q|Q|L|L|L|W|W|B)loadidx(1|8|1|4|8|1|2|1) instead of MOV(Qloadidx1|Qloadidx8|Lloadidx1|Lloadidx4|Lloadidx8|Wloadidx1|Wloadidx2|Bloadidx1) in rewrite rules. Both are fairly cryptic and hard to review, but the former is at least compact, which helps to not obscure the structure of the rest of the rule. Support that by adjusting rulegen's expansion. Instead of looking for an op that begins with "(", ends with " ", and has exactly one set of parens in it, look for everything of the form "(...|...)". That has false positives: Go code in the && conditions and AuxInt expressions. Those are easily checked for syntactically: && conditions are between && and ->, and AuxInt expressions are inside square brackets. After ruling out those false positives, we can keep everything else, regardless of where it is. No change to the generated code for existing rules. Change-Id: I5b70a190e268989504f53cb2cce2f9a50170d8a2 Reviewed-on: https://go-review.googlesource.com/c/go/+/166737 Run-TryBot: Josh Bleecher Snyder TryBot-Result: Gobot Gobot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/gen/rulegen.go | 53 +++++++++++++++------ 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go index f3a54b6299..d280688a0a 100644 --- a/src/cmd/compile/internal/ssa/gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/gen/rulegen.go @@ -815,20 +815,39 @@ func isVariable(s string) bool { } // opRegexp is a regular expression to find the opcode portion of s-expressions. -var opRegexp = regexp.MustCompile(`[(]\w*[(](\w+[|])+\w+[)]\w* `) +var opRegexp = regexp.MustCompile(`[(](\w+[|])+\w+[)]`) + +// excludeFromExpansion reports whether the substring s[idx[0]:idx[1]] in a rule +// should be disregarded as a candidate for | expansion. +// It uses simple syntactic checks to see whether the substring +// is inside an AuxInt expression or inside the && conditions. +func excludeFromExpansion(s string, idx []int) bool { + left := s[:idx[0]] + if strings.LastIndexByte(left, '[') > strings.LastIndexByte(left, ']') { + // Inside an AuxInt expression. + return true + } + right := s[idx[1]:] + if strings.Contains(left, "&&") && strings.Contains(right, "->") { + // Inside && conditions. + return true + } + return false +} // expandOr converts a rule into multiple rules by expanding | ops. func expandOr(r string) []string { - // Find every occurrence of |-separated things at the opcode position. - // They look like (MOV(B|W|L|Q|SS|SD)load - // Note: there might be false positives in parts of rules that are Go code - // (e.g. && conditions, AuxInt expressions, etc.). There are currently no - // such false positives, so I'm not too worried about it. + // Find every occurrence of |-separated things. + // They look like MOV(B|W|L|Q|SS|SD)load or MOV(Q|L)loadidx(1|8). // Generate rules selecting one case from each |-form. // Count width of |-forms. They must match. n := 1 - for _, s := range opRegexp.FindAllString(r, -1) { + for _, idx := range opRegexp.FindAllStringIndex(r, -1) { + if excludeFromExpansion(r, idx) { + continue + } + s := r[idx[0]:idx[1]] c := strings.Count(s, "|") + 1 if c == 1 { continue @@ -842,16 +861,22 @@ func expandOr(r string) []string { // No |-form in this rule. return []string{r} } + // Build each new rule. res := make([]string, n) for i := 0; i < n; i++ { - res[i] = opRegexp.ReplaceAllStringFunc(r, func(s string) string { - if strings.Count(s, "|") == 0 { - return s + buf := new(strings.Builder) + x := 0 + for _, idx := range opRegexp.FindAllStringIndex(r, -1) { + if excludeFromExpansion(r, idx) { + continue } - s = s[1 : len(s)-1] // remove leading "(" and trailing " " - x, y := strings.Index(s, "("), strings.Index(s, ")") - return "(" + s[:x] + strings.Split(s[x+1:y], "|")[i] + s[y+1:] + " " - }) + buf.WriteString(r[x:idx[0]]) // write bytes we've skipped over so far + s := r[idx[0]+1 : idx[1]-1] // remove leading "(" and trailing ")" + buf.WriteString(strings.Split(s, "|")[i]) // write the op component for this rule + x = idx[1] // note that we've written more bytes + } + buf.WriteString(r[x:]) + res[i] = buf.String() } return res } -- 2.50.0