aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssa/gen/rulegen.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/ssa/gen/rulegen.go')
-rw-r--r--src/cmd/compile/internal/ssa/gen/rulegen.go109
1 files changed, 40 insertions, 69 deletions
diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go
index be51a7c5f8..120ccbbdb3 100644
--- a/src/cmd/compile/internal/ssa/gen/rulegen.go
+++ b/src/cmd/compile/internal/ssa/gen/rulegen.go
@@ -35,8 +35,7 @@ import (
)
// rule syntax:
-// sexpr [&& extra conditions] -> [@block] sexpr (untyped)
-// sexpr [&& extra conditions] => [@block] sexpr (typed)
+// sexpr [&& extra conditions] => [@block] sexpr
//
// sexpr are s-expressions (lisp-like parenthesized groupings)
// sexpr ::= [variable:](opcode sexpr*)
@@ -50,8 +49,12 @@ import (
// variable ::= some token
// opcode ::= one of the opcodes from the *Ops.go files
+// special rules: trailing ellipsis "..." (in the outermost sexpr?) must match on both sides of a rule.
+// trailing three underscore "___" in the outermost match sexpr indicate the presence of
+// extra ignored args that need not appear in the replacement
+
// extra conditions is just a chunk of Go that evaluates to a boolean. It may use
-// variables declared in the matching sexpr. The variable "v" is predefined to be
+// variables declared in the matching tsexpr. The variable "v" is predefined to be
// the value matched by the entire rule.
// If multiple rules match, the first one in file order is selected.
@@ -75,14 +78,8 @@ func normalizeSpaces(s string) string {
}
// parse returns the matching part of the rule, additional conditions, and the result.
-// parse also reports whether the generated code should use strongly typed aux and auxint fields.
-func (r Rule) parse() (match, cond, result string, typed bool) {
- arrow := "->"
- if strings.Contains(r.Rule, "=>") {
- arrow = "=>"
- typed = true
- }
- s := strings.Split(r.Rule, arrow)
+func (r Rule) parse() (match, cond, result string) {
+ s := strings.Split(r.Rule, "=>")
match = normalizeSpaces(s[0])
result = normalizeSpaces(s[1])
cond = ""
@@ -90,7 +87,7 @@ func (r Rule) parse() (match, cond, result string, typed bool) {
cond = normalizeSpaces(match[i+2:])
match = normalizeSpaces(match[:i])
}
- return match, cond, result, typed
+ return match, cond, result
}
func genRules(arch arch) { genRulesSuffix(arch, "") }
@@ -116,7 +113,7 @@ func genRulesSuffix(arch arch, suff string) {
scanner := bufio.NewScanner(text)
rule := ""
var lineno int
- var ruleLineno int // line number of "->" or "=>"
+ var ruleLineno int // line number of "=>"
for scanner.Scan() {
lineno++
line := scanner.Text()
@@ -130,13 +127,13 @@ func genRulesSuffix(arch arch, suff string) {
if rule == "" {
continue
}
- if !strings.Contains(rule, "->") && !strings.Contains(rule, "=>") {
+ if !strings.Contains(rule, "=>") {
continue
}
if ruleLineno == 0 {
ruleLineno = lineno
}
- if strings.HasSuffix(rule, "->") || strings.HasSuffix(rule, "=>") {
+ if strings.HasSuffix(rule, "=>") {
continue // continue on the next line
}
if n := balance(rule); n > 0 {
@@ -153,7 +150,7 @@ func genRulesSuffix(arch arch, suff string) {
continue
}
// Do fancier value op matching.
- match, _, _, _ := r.parse()
+ match, _, _ := r.parse()
op, oparch, _, _, _, _ := parseValue(match, arch, loc)
opname := fmt.Sprintf("Op%s%s", oparch, op.name)
oprules[opname] = append(oprules[opname], r)
@@ -227,7 +224,7 @@ func genRulesSuffix(arch arch, suff string) {
log.Fatalf("unconditional rule %s is followed by other rules", rr.Match)
}
rr = &RuleRewrite{Loc: rule.Loc}
- rr.Match, rr.Cond, rr.Result, rr.Typed = rule.parse()
+ rr.Match, rr.Cond, rr.Result = rule.parse()
pos, _ := genMatch(rr, arch, rr.Match, fn.ArgLen >= 0)
if pos == "" {
pos = "v.Pos"
@@ -786,7 +783,6 @@ type (
Alloc int // for unique var names
Loc string // file name & line number of the original rule
CommuteDepth int // used to track depth of commute loops
- Typed bool // aux and auxint fields should be strongly typed
}
Declare struct {
Name string
@@ -840,7 +836,7 @@ func breakf(format string, a ...interface{}) *CondBreak {
func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
rr := &RuleRewrite{Loc: rule.Loc}
- rr.Match, rr.Cond, rr.Result, rr.Typed = rule.parse()
+ rr.Match, rr.Cond, rr.Result = rule.parse()
_, _, auxint, aux, s := extract(rr.Match) // remove parens, then split
// check match of control values
@@ -884,15 +880,6 @@ func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
if e.name == "" {
continue
}
- if !rr.Typed {
- if !token.IsIdentifier(e.name) || rr.declared(e.name) {
- // code or variable
- rr.add(breakf("b.%s != %s", e.field, e.name))
- } else {
- rr.add(declf(e.name, "b.%s", e.field))
- }
- continue
- }
if e.dclType == "" {
log.Fatalf("op %s has no declared type for %s", data.name, e.field)
@@ -961,20 +948,12 @@ func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
}
if auxint != "" {
- if rr.Typed {
- // Make sure auxint value has the right type.
- rr.add(stmtf("b.AuxInt = %sToAuxInt(%s)", unTitle(outdata.auxIntType()), auxint))
- } else {
- rr.add(stmtf("b.AuxInt = %s", auxint))
- }
+ // Make sure auxint value has the right type.
+ rr.add(stmtf("b.AuxInt = %sToAuxInt(%s)", unTitle(outdata.auxIntType()), auxint))
}
if aux != "" {
- if rr.Typed {
- // Make sure aux value has the right type.
- rr.add(stmtf("b.Aux = %sToAux(%s)", unTitle(outdata.auxType()), aux))
- } else {
- rr.add(stmtf("b.Aux = %s", aux))
- }
+ // Make sure aux value has the right type.
+ rr.add(stmtf("b.Aux = %sToAux(%s)", unTitle(outdata.auxType()), aux))
}
succChanged := false
@@ -1019,6 +998,19 @@ func genMatch0(rr *RuleRewrite, arch arch, match, v string, cnt map[string]int,
pos = v + ".Pos"
}
+ // If the last argument is ___, it means "don't care about trailing arguments, really"
+ // The likely/intended use is for rewrites that are too tricky to express in the existing pattern language
+ // Do a length check early because long patterns fed short (ultimately not-matching) inputs will
+ // do an indexing error in pattern-matching.
+ if op.argLength == -1 {
+ l := len(args)
+ if l == 0 || args[l-1] != "___" {
+ rr.add(breakf("len(%s.Args) != %d", v, l))
+ } else if l > 1 && args[l-1] == "___" {
+ rr.add(breakf("len(%s.Args) < %d", v, l-1))
+ }
+ }
+
for _, e := range []struct {
name, field, dclType string
}{
@@ -1029,15 +1021,6 @@ func genMatch0(rr *RuleRewrite, arch arch, match, v string, cnt map[string]int,
if e.name == "" {
continue
}
- if !rr.Typed {
- if !token.IsIdentifier(e.name) || rr.declared(e.name) {
- // code or variable
- rr.add(breakf("%s.%s != %s", v, e.field, e.name))
- } else {
- rr.add(declf(e.name, "%s.%s", v, e.field))
- }
- continue
- }
if e.dclType == "" {
log.Fatalf("op %s has no declared type for %s", op.name, e.field)
@@ -1159,9 +1142,6 @@ func genMatch0(rr *RuleRewrite, arch arch, match, v string, cnt map[string]int,
}
}
- if op.argLength == -1 {
- rr.add(breakf("len(%s.Args) != %d", v, len(args)))
- }
return pos, checkOp
}
@@ -1230,20 +1210,12 @@ func genResult0(rr *RuleRewrite, arch arch, result string, top, move bool, pos s
}
if auxint != "" {
- if rr.Typed {
- // Make sure auxint value has the right type.
- rr.add(stmtf("%s.AuxInt = %sToAuxInt(%s)", v, unTitle(op.auxIntType()), auxint))
- } else {
- rr.add(stmtf("%s.AuxInt = %s", v, auxint))
- }
+ // Make sure auxint value has the right type.
+ rr.add(stmtf("%s.AuxInt = %sToAuxInt(%s)", v, unTitle(op.auxIntType()), auxint))
}
if aux != "" {
- if rr.Typed {
- // Make sure aux value has the right type.
- rr.add(stmtf("%s.Aux = %sToAux(%s)", v, unTitle(op.auxType()), aux))
- } else {
- rr.add(stmtf("%s.Aux = %s", v, aux))
- }
+ // Make sure aux value has the right type.
+ rr.add(stmtf("%s.Aux = %sToAux(%s)", v, unTitle(op.auxType()), aux))
}
all := new(strings.Builder)
for i, arg := range args {
@@ -1524,7 +1496,7 @@ func excludeFromExpansion(s string, idx []int) bool {
return true
}
right := s[idx[1]:]
- if strings.Contains(left, "&&") && (strings.Contains(right, "->") || strings.Contains(right, "=>")) {
+ if strings.Contains(left, "&&") && strings.Contains(right, "=>") {
// Inside && conditions.
return true
}
@@ -1626,7 +1598,6 @@ func normalizeWhitespace(x string) string {
x = strings.Replace(x, " )", ")", -1)
x = strings.Replace(x, "[ ", "[", -1)
x = strings.Replace(x, " ]", "]", -1)
- x = strings.Replace(x, ")->", ") ->", -1)
x = strings.Replace(x, ")=>", ") =>", -1)
return x
}
@@ -1683,7 +1654,7 @@ func parseEllipsisRules(rules []Rule, arch arch) (newop string, ok bool) {
return "", false
}
rule := rules[0]
- match, cond, result, _ := rule.parse()
+ match, cond, result := rule.parse()
if cond != "" || !isEllipsisValue(match) || !isEllipsisValue(result) {
if strings.Contains(rule.Rule, "...") {
log.Fatalf("%s: found ellipsis in non-ellipsis rule", rule.Loc)
@@ -1708,7 +1679,7 @@ func isEllipsisValue(s string) bool {
}
func checkEllipsisRuleCandidate(rule Rule, arch arch) {
- match, cond, result, _ := rule.parse()
+ match, cond, result := rule.parse()
if cond != "" {
return
}
@@ -1718,7 +1689,7 @@ func checkEllipsisRuleCandidate(rule Rule, arch arch) {
var usingCopy string
var eop opData
if result[0] != '(' {
- // Check for (Foo x) -> x, which can be converted to (Foo ...) -> (Copy ...).
+ // Check for (Foo x) => x, which can be converted to (Foo ...) => (Copy ...).
args2 = []string{result}
usingCopy = " using Copy"
} else {