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 ( ...@@ -45,6 +45,35 @@ import (
// If multiple rules match, the first one in file order is selected. // 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) { func genRules(arch arch) {
// Open input file. // Open input file.
text, err := os.Open(arch.name + ".rules") text, err := os.Open(arch.name + ".rules")
...@@ -53,13 +82,15 @@ func genRules(arch arch) { ...@@ -53,13 +82,15 @@ func genRules(arch arch) {
} }
// oprules contains a list of rules for each block and opcode // oprules contains a list of rules for each block and opcode
blockrules := map[string][]string{} blockrules := map[string][]Rule{}
oprules := map[string][]string{} oprules := map[string][]Rule{}
// read rule file // read rule file
scanner := bufio.NewScanner(text) scanner := bufio.NewScanner(text)
rule := "" rule := ""
var lineno int
for scanner.Scan() { for scanner.Scan() {
lineno++
line := scanner.Text() line := scanner.Text()
if i := strings.Index(line, "//"); i >= 0 { if i := strings.Index(line, "//"); i >= 0 {
// Remove comments. Note that this isn't string safe, so // Remove comments. Note that this isn't string safe, so
...@@ -85,24 +116,25 @@ func genRules(arch arch) { ...@@ -85,24 +116,25 @@ func genRules(arch arch) {
op = op[:len(op)-1] // rule has only opcode, e.g. (ConstNil) -> ... op = op[:len(op)-1] // rule has only opcode, e.g. (ConstNil) -> ...
} }
if isBlock(op, arch) { if isBlock(op, arch) {
blockrules[op] = append(blockrules[op], rule) blockrules[op] = append(blockrules[op], Rule{rule: rule, lineno: lineno})
} else { } else {
oprules[op] = append(oprules[op], rule) oprules[op] = append(oprules[op], Rule{rule: rule, lineno: lineno})
} }
rule = "" rule = ""
} }
if unbalanced(rule) {
log.Fatalf("unbalanced rule: %v\n", rule)
}
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
log.Fatalf("scanner failed: %v\n", err) 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. // Start output buffer, write header.
w := new(bytes.Buffer) w := new(bytes.Buffer)
fmt.Fprintf(w, "// autogenerated from gen/%s.rules: do not edit!\n", arch.name) 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, "// generated with: cd gen; go run *.go")
fmt.Fprintln(w, "package ssa") 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.Fprintf(w, "func rewriteValue%s(v *Value, config *Config) bool {\n", arch.name)
fmt.Fprintln(w, "b := v.Block") fmt.Fprintln(w, "b := v.Block")
...@@ -120,24 +152,9 @@ func genRules(arch arch) { ...@@ -120,24 +152,9 @@ func genRules(arch arch) {
// identity is invariant to adding/removing rules elsewhere // identity is invariant to adding/removing rules elsewhere
// in the rules file. This is useful to squash spurious // in the rules file. This is useful to squash spurious
// diffs that would occur if we used rule index. // diffs that would occur if we used rule index.
rulehash := fmt.Sprintf("%02x", md5.Sum([]byte(rule))) rulehash := rule.hash()
// 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])
}
match, cond, result := rule.parse()
fmt.Fprintf(w, "// match: %s\n", match) fmt.Fprintf(w, "// match: %s\n", match)
fmt.Fprintf(w, "// cond: %s\n", cond) fmt.Fprintf(w, "// cond: %s\n", cond)
fmt.Fprintf(w, "// result: %s\n", result) fmt.Fprintf(w, "// result: %s\n", result)
...@@ -152,6 +169,9 @@ func genRules(arch arch) { ...@@ -152,6 +169,9 @@ func genRules(arch arch) {
} }
genResult(w, arch, result) 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, "return true\n")
fmt.Fprintf(w, "}\n") fmt.Fprintf(w, "}\n")
...@@ -174,23 +194,9 @@ func genRules(arch arch) { ...@@ -174,23 +194,9 @@ func genRules(arch arch) {
for _, op := range ops { for _, op := range ops {
fmt.Fprintf(w, "case %s:\n", blockName(op, arch)) fmt.Fprintf(w, "case %s:\n", blockName(op, arch))
for _, rule := range blockrules[op] { for _, rule := range blockrules[op] {
rulehash := fmt.Sprintf("%02x", md5.Sum([]byte(rule))) rulehash := rule.hash()
// 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])
}
match, cond, result := rule.parse()
fmt.Fprintf(w, "// match: %s\n", match) fmt.Fprintf(w, "// match: %s\n", match)
fmt.Fprintf(w, "// cond: %s\n", cond) fmt.Fprintf(w, "// cond: %s\n", cond)
fmt.Fprintf(w, "// result: %s\n", result) fmt.Fprintf(w, "// result: %s\n", result)
...@@ -198,7 +204,8 @@ func genRules(arch arch) { ...@@ -198,7 +204,8 @@ func genRules(arch arch) {
fail := fmt.Sprintf("{\ngoto end%s\n}\n", rulehash) fail := fmt.Sprintf("{\ngoto end%s\n}\n", rulehash)
fmt.Fprintf(w, "{\n") 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 // check match of control value
if s[1] != "nil" { if s[1] != "nil" {
...@@ -268,6 +275,9 @@ func genRules(arch arch) { ...@@ -268,6 +275,9 @@ func genRules(arch arch) {
fmt.Fprintln(w, "b.Likely = BranchUnknown") 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, "return true\n")
fmt.Fprintf(w, "}\n") fmt.Fprintf(w, "}\n")
......
...@@ -6,6 +6,11 @@ package ssa ...@@ -6,6 +6,11 @@ package ssa
import "fmt" 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) { func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) {
// repeat rewrites until we find no more rewrites // repeat rewrites until we find no more rewrites
var curb *Block 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