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) {
canFail = false
fmt.Fprintf(buf, "for {\n")
pos, matchCanFail := genMatch(buf, arch, match, rule.loc)
pos, _, matchCanFail := genMatch(buf, arch, match, rule.loc)
if pos == "" {
pos = "v.Pos"
}
......@@ -273,11 +273,10 @@ func genRulesSuffix(arch arch, suff string) {
// 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.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")
fmt.Fprintln(w, "v := b.Control")
fmt.Fprintln(w, "_ = v")
fmt.Fprintf(w, "switch b.Kind {\n")
ops = nil
for op := range blockrules {
......@@ -292,27 +291,26 @@ func genRulesSuffix(arch arch, suff string) {
fmt.Fprintf(w, "// cond: %s\n", cond)
fmt.Fprintf(w, "// result: %s\n", result)
fmt.Fprintf(w, "for {\n")
_, _, _, aux, s := extract(match) // remove parens, then split
loopw := new(bytes.Buffer)
// check match of control value
pos := ""
checkOp := ""
if s[0] != "nil" {
fmt.Fprintf(w, "v := b.Control\n")
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 {
fmt.Fprintf(w, "_ = v\n") // in case we don't use v
fmt.Fprintf(w, "%s := b.Control\n", s[0])
fmt.Fprintf(loopw, "%s := b.Control\n", s[0])
}
}
if aux != "" {
fmt.Fprintf(w, "%s := b.Aux\n", aux)
fmt.Fprintf(loopw, "%s := b.Aux\n", aux)
}
if cond != "" {
fmt.Fprintf(w, "if !(%s) {\nbreak\n}\n", cond)
fmt.Fprintf(loopw, "if !(%s) {\nbreak\n}\n", cond)
}
// Rule matches. Generate result.
......@@ -338,19 +336,19 @@ func genRulesSuffix(arch arch, suff string) {
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" {
fmt.Fprintf(w, "b.SetControl(nil)\n")
fmt.Fprintf(loopw, "b.SetControl(nil)\n")
} else {
if 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 != "" {
fmt.Fprintf(w, "b.Aux = %s\n", aux)
fmt.Fprintf(loopw, "b.Aux = %s\n", aux)
} else {
fmt.Fprintln(w, "b.Aux = nil")
fmt.Fprintln(loopw, "b.Aux = nil")
}
succChanged := false
......@@ -366,13 +364,20 @@ func genRulesSuffix(arch arch, suff string) {
if succs[0] != newsuccs[1] || succs[1] != newsuccs[0] {
log.Fatalf("can only handle swapped successors in %s", rule)
}
fmt.Fprintln(w, "b.swapSuccessors()")
fmt.Fprintln(loopw, "b.swapSuccessors()")
}
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")
}
......@@ -398,24 +403,18 @@ func genRulesSuffix(arch arch, suff string) {
// 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.
func genMatch(w io.Writer, arch arch, match string, loc string) (string, bool) {
return genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc)
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{}{}, 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] != ')' {
panic("non-compound expr in genMatch0: " + match)
}
pos := ""
canFail := false
op, oparch, typ, auxint, aux, args := parseValue(match, arch, loc)
// check op
if !top {
fmt.Fprintf(w, "if %s.Op != Op%s%s {\nbreak\n}\n", v, oparch, op.name)
canFail = true
}
checkOp = fmt.Sprintf("Op%s%s", oparch, op.name)
if op.faultOnNilArg0 || op.faultOnNilArg1 {
// Prefer the position of an instruction which could fault.
pos = v + ".Pos"
......@@ -521,8 +520,13 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t
if argname == "b" {
log.Fatalf("don't name args 'b', it is ambiguous with blocks")
}
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 != "" {
// Keep the argument in preference to the parent, as the
// 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
// in the program flow.
pos = argPos
}
if argCanFail {
canFail = true
}
canFail = true
}
if op.argLength == -1 {
fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, len(args))
canFail = true
}
return pos, canFail
return pos, checkOp, canFail
}
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 {
}
func rewriteBlock386splitload(b *Block) bool {
config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types
_ = typ
v := b.Control
_ = v
switch b.Kind {
}
return false
......
......@@ -218,11 +218,10 @@ func rewriteValueAMD64splitload_OpAMD64CMPWload_0(v *Value) bool {
}
func rewriteBlockAMD64splitload(b *Block) bool {
config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types
_ = typ
v := b.Control
_ = v
switch b.Kind {
}
return false
......
This diff is collapsed.
This diff is collapsed.
......@@ -6382,11 +6382,10 @@ func rewriteValueWasm_OpZeroExt8to64_0(v *Value) bool {
}
func rewriteBlockWasm(b *Block) bool {
config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types
_ = typ
v := b.Control
_ = v
switch b.Kind {
}
return false
......
......@@ -493,11 +493,10 @@ func rewriteValuedec_OpStringPtr_0(v *Value) bool {
}
func rewriteBlockdec(b *Block) bool {
config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types
_ = typ
v := b.Control
_ = v
switch b.Kind {
}
return false
......
......@@ -2727,11 +2727,10 @@ func rewriteValuedec64_OpZeroExt8to64_0(v *Value) bool {
}
func rewriteBlockdec64(b *Block) bool {
config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types
_ = typ
v := b.Control
_ = v
switch b.Kind {
}
return false
......
......@@ -271,11 +271,10 @@ func rewriteValuedecArgs_OpArg_10(v *Value) bool {
}
func rewriteBlockdecArgs(b *Block) bool {
config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types
_ = typ
v := b.Control
_ = v
switch b.Kind {
}
return false
......
......@@ -32620,21 +32620,16 @@ func rewriteValuegeneric_OpZeroExt8to64_0(v *Value) bool {
}
func rewriteBlockgeneric(b *Block) bool {
config := b.Func.Config
_ = config
fe := b.Func.fe
_ = fe
typ := &config.Types
_ = typ
v := b.Control
_ = v
switch b.Kind {
case BlockIf:
// match: (If (Not cond) yes no)
// cond:
// result: (If cond no yes)
for {
v := b.Control
if v.Op != OpNot {
break
}
for v.Op == OpNot {
cond := v.Args[0]
b.Kind = BlockIf
b.SetControl(cond)
......@@ -32645,11 +32640,7 @@ func rewriteBlockgeneric(b *Block) bool {
// match: (If (ConstBool [c]) yes no)
// cond: c == 1
// result: (First nil yes no)
for {
v := b.Control
if v.Op != OpConstBool {
break
}
for v.Op == OpConstBool {
c := v.AuxInt
if !(c == 1) {
break
......@@ -32662,11 +32653,7 @@ func rewriteBlockgeneric(b *Block) bool {
// match: (If (ConstBool [c]) yes no)
// cond: c == 0
// result: (First nil no yes)
for {
v := b.Control
if v.Op != OpConstBool {
break
}
for v.Op == OpConstBool {
c := v.AuxInt
if !(c == 0) {
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