Commit 0fbf6818 authored by Daniel Martí's avatar Daniel Martí

cmd/compile: reduce rulegen's for loop verbosity

A lot of the naked for loops begin like:

	for {
		v := b.Control
		if v.Op != OpConstBool {
			break
		}
		...
		return true
	}

Instead, write them out in a more compact and readable way:

	for v.Op == OpConstBool {
		...
		return true
	}

This requires the addition of two bytes.Buffer writers, as this helps us
make a decision based on future pieces of generated code. This probably
makes rulegen slightly slower, but that's not noticeable; the code
generation still takes ~3.5s on my laptop, excluding build time.

The "v := b.Control" declaration can be moved to the top of each
function. Even though the rules can modify b.Control when firing, they
also make the function return, so v can't be used again.

While at it, remove three unnecessary lines from the top of each
rewriteBlock func.

In total, this results in ~4k lines removed from the generated code, and
a slight improvement in readability.

Change-Id: I317e4c6a4842c64df506f4513375475fad2aeec5
Reviewed-on: https://go-review.googlesource.com/c/go/+/167399
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent b06d2122
...@@ -217,7 +217,7 @@ func genRulesSuffix(arch arch, suff string) { ...@@ -217,7 +217,7 @@ func genRulesSuffix(arch arch, suff string) {
canFail = false canFail = false
fmt.Fprintf(buf, "for {\n") fmt.Fprintf(buf, "for {\n")
pos, matchCanFail := genMatch(buf, arch, match, rule.loc) pos, _, matchCanFail := genMatch(buf, arch, match, rule.loc)
if pos == "" { if pos == "" {
pos = "v.Pos" pos = "v.Pos"
} }
...@@ -273,11 +273,10 @@ func genRulesSuffix(arch arch, suff string) { ...@@ -273,11 +273,10 @@ func genRulesSuffix(arch arch, suff string) {
// so we can make this one function with a switch. // so we can make this one function with a switch.
fmt.Fprintf(w, "func rewriteBlock%s%s(b *Block) bool {\n", arch.name, suff) fmt.Fprintf(w, "func rewriteBlock%s%s(b *Block) bool {\n", arch.name, suff)
fmt.Fprintln(w, "config := b.Func.Config") fmt.Fprintln(w, "config := b.Func.Config")
fmt.Fprintln(w, "_ = config")
fmt.Fprintln(w, "fe := b.Func.fe")
fmt.Fprintln(w, "_ = fe")
fmt.Fprintln(w, "typ := &config.Types") fmt.Fprintln(w, "typ := &config.Types")
fmt.Fprintln(w, "_ = typ") fmt.Fprintln(w, "_ = typ")
fmt.Fprintln(w, "v := b.Control")
fmt.Fprintln(w, "_ = v")
fmt.Fprintf(w, "switch b.Kind {\n") fmt.Fprintf(w, "switch b.Kind {\n")
ops = nil ops = nil
for op := range blockrules { for op := range blockrules {
...@@ -292,27 +291,26 @@ func genRulesSuffix(arch arch, suff string) { ...@@ -292,27 +291,26 @@ func genRulesSuffix(arch arch, suff string) {
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)
fmt.Fprintf(w, "for {\n")
_, _, _, aux, s := extract(match) // remove parens, then split _, _, _, aux, s := extract(match) // remove parens, then split
loopw := new(bytes.Buffer)
// check match of control value // check match of control value
pos := "" pos := ""
checkOp := ""
if s[0] != "nil" { if s[0] != "nil" {
fmt.Fprintf(w, "v := b.Control\n")
if strings.Contains(s[0], "(") { if strings.Contains(s[0], "(") {
pos, _ = genMatch0(w, arch, s[0], "v", map[string]struct{}{}, false, rule.loc) pos, checkOp, _ = genMatch0(loopw, arch, s[0], "v", map[string]struct{}{}, rule.loc)
} else { } else {
fmt.Fprintf(w, "_ = v\n") // in case we don't use v fmt.Fprintf(loopw, "%s := b.Control\n", s[0])
fmt.Fprintf(w, "%s := b.Control\n", s[0])
} }
} }
if aux != "" { if aux != "" {
fmt.Fprintf(w, "%s := b.Aux\n", aux) fmt.Fprintf(loopw, "%s := b.Aux\n", aux)
} }
if cond != "" { if cond != "" {
fmt.Fprintf(w, "if !(%s) {\nbreak\n}\n", cond) fmt.Fprintf(loopw, "if !(%s) {\nbreak\n}\n", cond)
} }
// Rule matches. Generate result. // Rule matches. Generate result.
...@@ -338,19 +336,19 @@ func genRulesSuffix(arch arch, suff string) { ...@@ -338,19 +336,19 @@ func genRulesSuffix(arch arch, suff string) {
log.Fatalf("unmatched successors %v in %s", m, rule) log.Fatalf("unmatched successors %v in %s", m, rule)
} }
fmt.Fprintf(w, "b.Kind = %s\n", blockName(outop, arch)) fmt.Fprintf(loopw, "b.Kind = %s\n", blockName(outop, arch))
if t[0] == "nil" { if t[0] == "nil" {
fmt.Fprintf(w, "b.SetControl(nil)\n") fmt.Fprintf(loopw, "b.SetControl(nil)\n")
} else { } else {
if pos == "" { if pos == "" {
pos = "v.Pos" pos = "v.Pos"
} }
fmt.Fprintf(w, "b.SetControl(%s)\n", genResult0(w, arch, t[0], new(int), false, false, rule.loc, pos)) fmt.Fprintf(loopw, "b.SetControl(%s)\n", genResult0(loopw, arch, t[0], new(int), false, false, rule.loc, pos))
} }
if aux != "" { if aux != "" {
fmt.Fprintf(w, "b.Aux = %s\n", aux) fmt.Fprintf(loopw, "b.Aux = %s\n", aux)
} else { } else {
fmt.Fprintln(w, "b.Aux = nil") fmt.Fprintln(loopw, "b.Aux = nil")
} }
succChanged := false succChanged := false
...@@ -366,13 +364,20 @@ func genRulesSuffix(arch arch, suff string) { ...@@ -366,13 +364,20 @@ func genRulesSuffix(arch arch, suff string) {
if succs[0] != newsuccs[1] || succs[1] != newsuccs[0] { if succs[0] != newsuccs[1] || succs[1] != newsuccs[0] {
log.Fatalf("can only handle swapped successors in %s", rule) log.Fatalf("can only handle swapped successors in %s", rule)
} }
fmt.Fprintln(w, "b.swapSuccessors()") fmt.Fprintln(loopw, "b.swapSuccessors()")
} }
if *genLog { if *genLog {
fmt.Fprintf(w, "logRule(\"%s\")\n", rule.loc) fmt.Fprintf(loopw, "logRule(\"%s\")\n", rule.loc)
} }
fmt.Fprintf(w, "return true\n") fmt.Fprintf(loopw, "return true\n")
if checkOp != "" {
fmt.Fprintf(w, "for v.Op == %s {\n", checkOp)
} else {
fmt.Fprintf(w, "for {\n")
}
io.Copy(w, loopw)
fmt.Fprintf(w, "}\n") fmt.Fprintf(w, "}\n")
} }
...@@ -398,24 +403,18 @@ func genRulesSuffix(arch arch, suff string) { ...@@ -398,24 +403,18 @@ func genRulesSuffix(arch arch, suff string) {
// genMatch returns the variable whose source position should be used for the // genMatch returns the variable whose source position should be used for the
// result (or "" if no opinion), and a boolean that reports whether the match can fail. // result (or "" if no opinion), and a boolean that reports whether the match can fail.
func genMatch(w io.Writer, arch arch, match string, loc string) (string, bool) { func genMatch(w io.Writer, arch arch, match string, loc string) (pos, checkOp string, canFail bool) {
return genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc) return genMatch0(w, arch, match, "v", map[string]struct{}{}, loc)
} }
func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, top bool, loc string) (string, bool) { func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, loc string) (pos, checkOp string, canFail bool) {
if match[0] != '(' || match[len(match)-1] != ')' { if match[0] != '(' || match[len(match)-1] != ')' {
panic("non-compound expr in genMatch0: " + match) panic("non-compound expr in genMatch0: " + match)
} }
pos := ""
canFail := false
op, oparch, typ, auxint, aux, args := parseValue(match, arch, loc) op, oparch, typ, auxint, aux, args := parseValue(match, arch, loc)
// check op checkOp = fmt.Sprintf("Op%s%s", oparch, op.name)
if !top {
fmt.Fprintf(w, "if %s.Op != Op%s%s {\nbreak\n}\n", v, oparch, op.name)
canFail = true
}
if op.faultOnNilArg0 || op.faultOnNilArg1 { if op.faultOnNilArg0 || op.faultOnNilArg1 {
// Prefer the position of an instruction which could fault. // Prefer the position of an instruction which could fault.
pos = v + ".Pos" pos = v + ".Pos"
...@@ -521,8 +520,13 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t ...@@ -521,8 +520,13 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t
if argname == "b" { if argname == "b" {
log.Fatalf("don't name args 'b', it is ambiguous with blocks") log.Fatalf("don't name args 'b', it is ambiguous with blocks")
} }
fmt.Fprintf(w, "%s := %s.Args[%d]\n", argname, v, i) fmt.Fprintf(w, "%s := %s.Args[%d]\n", argname, v, i)
argPos, argCanFail := genMatch0(w, arch, arg, argname, m, false, loc) w2 := new(bytes.Buffer)
argPos, argCheckOp, _ := genMatch0(w2, arch, arg, argname, m, loc)
fmt.Fprintf(w, "if %s.Op != %s {\nbreak\n}\n", argname, argCheckOp)
io.Copy(w, w2)
if argPos != "" { if argPos != "" {
// Keep the argument in preference to the parent, as the // Keep the argument in preference to the parent, as the
// argument is normally earlier in program flow. // argument is normally earlier in program flow.
...@@ -531,16 +535,14 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t ...@@ -531,16 +535,14 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t
// in the program flow. // in the program flow.
pos = argPos pos = argPos
} }
if argCanFail { canFail = true
canFail = true
}
} }
if op.argLength == -1 { if op.argLength == -1 {
fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, len(args)) fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, len(args))
canFail = true canFail = true
} }
return pos, canFail return pos, checkOp, canFail
} }
func genResult(w io.Writer, arch arch, result string, loc string, pos string) { func genResult(w io.Writer, arch arch, result string, loc string, pos string) {
......
This diff is collapsed.
...@@ -169,11 +169,10 @@ func rewriteValue386splitload_Op386CMPWload_0(v *Value) bool { ...@@ -169,11 +169,10 @@ func rewriteValue386splitload_Op386CMPWload_0(v *Value) bool {
} }
func rewriteBlock386splitload(b *Block) bool { func rewriteBlock386splitload(b *Block) bool {
config := b.Func.Config config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types typ := &config.Types
_ = typ _ = typ
v := b.Control
_ = v
switch b.Kind { switch b.Kind {
} }
return false return false
......
...@@ -218,11 +218,10 @@ func rewriteValueAMD64splitload_OpAMD64CMPWload_0(v *Value) bool { ...@@ -218,11 +218,10 @@ func rewriteValueAMD64splitload_OpAMD64CMPWload_0(v *Value) bool {
} }
func rewriteBlockAMD64splitload(b *Block) bool { func rewriteBlockAMD64splitload(b *Block) bool {
config := b.Func.Config config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types typ := &config.Types
_ = typ _ = typ
v := b.Control
_ = v
switch b.Kind { switch b.Kind {
} }
return false return false
......
This diff is collapsed.
This diff is collapsed.
...@@ -6382,11 +6382,10 @@ func rewriteValueWasm_OpZeroExt8to64_0(v *Value) bool { ...@@ -6382,11 +6382,10 @@ func rewriteValueWasm_OpZeroExt8to64_0(v *Value) bool {
} }
func rewriteBlockWasm(b *Block) bool { func rewriteBlockWasm(b *Block) bool {
config := b.Func.Config config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types typ := &config.Types
_ = typ _ = typ
v := b.Control
_ = v
switch b.Kind { switch b.Kind {
} }
return false return false
......
...@@ -493,11 +493,10 @@ func rewriteValuedec_OpStringPtr_0(v *Value) bool { ...@@ -493,11 +493,10 @@ func rewriteValuedec_OpStringPtr_0(v *Value) bool {
} }
func rewriteBlockdec(b *Block) bool { func rewriteBlockdec(b *Block) bool {
config := b.Func.Config config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types typ := &config.Types
_ = typ _ = typ
v := b.Control
_ = v
switch b.Kind { switch b.Kind {
} }
return false return false
......
...@@ -2727,11 +2727,10 @@ func rewriteValuedec64_OpZeroExt8to64_0(v *Value) bool { ...@@ -2727,11 +2727,10 @@ func rewriteValuedec64_OpZeroExt8to64_0(v *Value) bool {
} }
func rewriteBlockdec64(b *Block) bool { func rewriteBlockdec64(b *Block) bool {
config := b.Func.Config config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types typ := &config.Types
_ = typ _ = typ
v := b.Control
_ = v
switch b.Kind { switch b.Kind {
} }
return false return false
......
...@@ -271,11 +271,10 @@ func rewriteValuedecArgs_OpArg_10(v *Value) bool { ...@@ -271,11 +271,10 @@ func rewriteValuedecArgs_OpArg_10(v *Value) bool {
} }
func rewriteBlockdecArgs(b *Block) bool { func rewriteBlockdecArgs(b *Block) bool {
config := b.Func.Config config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types typ := &config.Types
_ = typ _ = typ
v := b.Control
_ = v
switch b.Kind { switch b.Kind {
} }
return false return false
......
...@@ -32620,21 +32620,16 @@ func rewriteValuegeneric_OpZeroExt8to64_0(v *Value) bool { ...@@ -32620,21 +32620,16 @@ func rewriteValuegeneric_OpZeroExt8to64_0(v *Value) bool {
} }
func rewriteBlockgeneric(b *Block) bool { func rewriteBlockgeneric(b *Block) bool {
config := b.Func.Config config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types typ := &config.Types
_ = typ _ = typ
v := b.Control
_ = v
switch b.Kind { switch b.Kind {
case BlockIf: case BlockIf:
// match: (If (Not cond) yes no) // match: (If (Not cond) yes no)
// cond: // cond:
// result: (If cond no yes) // result: (If cond no yes)
for { for v.Op == OpNot {
v := b.Control
if v.Op != OpNot {
break
}
cond := v.Args[0] cond := v.Args[0]
b.Kind = BlockIf b.Kind = BlockIf
b.SetControl(cond) b.SetControl(cond)
...@@ -32645,11 +32640,7 @@ func rewriteBlockgeneric(b *Block) bool { ...@@ -32645,11 +32640,7 @@ func rewriteBlockgeneric(b *Block) bool {
// match: (If (ConstBool [c]) yes no) // match: (If (ConstBool [c]) yes no)
// cond: c == 1 // cond: c == 1
// result: (First nil yes no) // result: (First nil yes no)
for { for v.Op == OpConstBool {
v := b.Control
if v.Op != OpConstBool {
break
}
c := v.AuxInt c := v.AuxInt
if !(c == 1) { if !(c == 1) {
break break
...@@ -32662,11 +32653,7 @@ func rewriteBlockgeneric(b *Block) bool { ...@@ -32662,11 +32653,7 @@ func rewriteBlockgeneric(b *Block) bool {
// match: (If (ConstBool [c]) yes no) // match: (If (ConstBool [c]) yes no)
// cond: c == 0 // cond: c == 0
// result: (First nil no yes) // result: (First nil no yes)
for { for v.Op == OpConstBool {
v := b.Control
if v.Op != OpConstBool {
break
}
c := v.AuxInt c := v.AuxInt
if !(c == 0) { if !(c == 0) {
break break
......
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