Commit 514ab7c3 authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

[dev.ssa] cmd/compile: log line numbers in generated rewrite rules

This makes it easier to investigate and
understand rewrite behavior.

Change-Id: I790e8964922caf98362ce8a6d6972f52d83eefa8
Reviewed-on: https://go-review.googlesource.com/13588Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent 3d23afb9
......@@ -45,6 +45,35 @@ import (
// If multiple rules match, the first one in file order is selected.
type Rule struct {
rule string
lineno int
}
func (r Rule) String() string {
return fmt.Sprintf("rule %q at line %d", r.rule, r.lineno)
}
func (r Rule) hash() string {
return fmt.Sprintf("%02x", md5.Sum([]byte(r.rule)))
}
// parse returns the matching part of the rule, additional conditions, and the result.
func (r Rule) parse() (match, cond, result string) {
s := strings.Split(r.rule, "->")
if len(s) != 2 {
log.Fatalf("no arrow in %s", r)
}
match = strings.TrimSpace(s[0])
result = strings.TrimSpace(s[1])
cond = ""
if i := strings.Index(match, "&&"); i >= 0 {
cond = strings.TrimSpace(match[i+2:])
match = strings.TrimSpace(match[:i])
}
return match, cond, result
}
func genRules(arch arch) {
// Open input file.
text, err := os.Open(arch.name + ".rules")
......@@ -53,13 +82,15 @@ func genRules(arch arch) {
}
// oprules contains a list of rules for each block and opcode
blockrules := map[string][]string{}
oprules := map[string][]string{}
blockrules := map[string][]Rule{}
oprules := map[string][]Rule{}
// read rule file
scanner := bufio.NewScanner(text)
rule := ""
var lineno int
for scanner.Scan() {
lineno++
line := scanner.Text()
if i := strings.Index(line, "//"); i >= 0 {
// Remove comments. Note that this isn't string safe, so
......@@ -85,24 +116,25 @@ func genRules(arch arch) {
op = op[:len(op)-1] // rule has only opcode, e.g. (ConstNil) -> ...
}
if isBlock(op, arch) {
blockrules[op] = append(blockrules[op], rule)
blockrules[op] = append(blockrules[op], Rule{rule: rule, lineno: lineno})
} else {
oprules[op] = append(oprules[op], rule)
oprules[op] = append(oprules[op], Rule{rule: rule, lineno: lineno})
}
rule = ""
}
if unbalanced(rule) {
log.Fatalf("unbalanced rule: %v\n", rule)
}
if err := scanner.Err(); err != nil {
log.Fatalf("scanner failed: %v\n", err)
}
if unbalanced(rule) {
log.Fatalf("unbalanced rule at line %d: %v\n", lineno, rule)
}
// Start output buffer, write header.
w := new(bytes.Buffer)
fmt.Fprintf(w, "// autogenerated from gen/%s.rules: do not edit!\n", arch.name)
fmt.Fprintln(w, "// generated with: cd gen; go run *.go")
fmt.Fprintln(w, "package ssa")
fmt.Fprintln(w, "import \"fmt\"")
fmt.Fprintf(w, "func rewriteValue%s(v *Value, config *Config) bool {\n", arch.name)
fmt.Fprintln(w, "b := v.Block")
......@@ -120,24 +152,9 @@ func genRules(arch arch) {
// identity is invariant to adding/removing rules elsewhere
// in the rules file. This is useful to squash spurious
// diffs that would occur if we used rule index.
rulehash := fmt.Sprintf("%02x", md5.Sum([]byte(rule)))
// split at ->
s := strings.Split(rule, "->")
if len(s) != 2 {
log.Fatalf("rule must contain exactly one arrow: %s", rule)
}
lhs := strings.TrimSpace(s[0])
result := strings.TrimSpace(s[1])
// split match into matching part and additional condition
match := lhs
cond := ""
if i := strings.Index(match, "&&"); i >= 0 {
cond = strings.TrimSpace(match[i+2:])
match = strings.TrimSpace(match[:i])
}
rulehash := rule.hash()
match, cond, result := rule.parse()
fmt.Fprintf(w, "// match: %s\n", match)
fmt.Fprintf(w, "// cond: %s\n", cond)
fmt.Fprintf(w, "// result: %s\n", result)
......@@ -152,6 +169,9 @@ func genRules(arch arch) {
}
genResult(w, arch, result)
fmt.Fprintf(w, "if logRewriteRules {\n")
fmt.Fprintf(w, " fmt.Println(\"rewrite %s.rules:%d\")", arch.name, rule.lineno)
fmt.Fprintf(w, "}\n")
fmt.Fprintf(w, "return true\n")
fmt.Fprintf(w, "}\n")
......@@ -174,23 +194,9 @@ func genRules(arch arch) {
for _, op := range ops {
fmt.Fprintf(w, "case %s:\n", blockName(op, arch))
for _, rule := range blockrules[op] {
rulehash := fmt.Sprintf("%02x", md5.Sum([]byte(rule)))
// split at ->
s := strings.Split(rule, "->")
if len(s) != 2 {
log.Fatalf("no arrow in rule %s", rule)
}
lhs := strings.TrimSpace(s[0])
result := strings.TrimSpace(s[1])
// split match into matching part and additional condition
match := lhs
cond := ""
if i := strings.Index(match, "&&"); i >= 0 {
cond = strings.TrimSpace(match[i+2:])
match = strings.TrimSpace(match[:i])
}
rulehash := rule.hash()
match, cond, result := rule.parse()
fmt.Fprintf(w, "// match: %s\n", match)
fmt.Fprintf(w, "// cond: %s\n", cond)
fmt.Fprintf(w, "// result: %s\n", result)
......@@ -198,7 +204,8 @@ func genRules(arch arch) {
fail := fmt.Sprintf("{\ngoto end%s\n}\n", rulehash)
fmt.Fprintf(w, "{\n")
s = split(match[1 : len(match)-1]) // remove parens, then split
s := split(match[1 : len(match)-1]) // remove parens, then split
// check match of control value
if s[1] != "nil" {
......@@ -268,6 +275,9 @@ func genRules(arch arch) {
fmt.Fprintln(w, "b.Likely = BranchUnknown")
}
fmt.Fprintf(w, "if logRewriteRules {\n")
fmt.Fprintf(w, " fmt.Println(\"rewrite %s.rules:%d\")", arch.name, rule.lineno)
fmt.Fprintf(w, "}\n")
fmt.Fprintf(w, "return true\n")
fmt.Fprintf(w, "}\n")
......
......@@ -6,6 +6,11 @@ package ssa
import "fmt"
// Set to true to log all rewrite rules as they occur.
// This is useful for figuring out whether a rule is triggering
// and which rules are most heavily used.
const logRewriteRules = false
func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) {
// repeat rewrites until we find no more rewrites
var curb *Block
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment