Commit fc7b83d1 authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/compile: break up large value rewrite functions

This makes the cmd/compile/internal/ssa package
compile much faster, and has no impact
on the speed of the compiler.

The chunk size was selected empirically,
in that at chunk size 10, the object
file was smaller than at chunk size 5 or 20.

name  old time/op       new time/op       delta
SSA         7.33s ± 5%        5.64s ± 1%  -23.10%  (p=0.000 n=10+10)

name  old user-time/op  new user-time/op  delta
SSA         9.70s ± 1%        8.04s ± 2%  -17.17%  (p=0.000 n=9+10)

name  old obj-bytes     new obj-bytes     delta
SSA         9.82M ± 0%        8.28M ± 0%  -15.67%  (p=0.000 n=10+10)

Change-Id: Iab472905da3f0e82f3db2c93d06e2759abc9dd44
Reviewed-on: https://go-review.googlesource.com/41296Reviewed-by: 's avatarKeith Randall <khr@golang.org>
parent eaa198f3
......@@ -162,12 +162,20 @@ func genRules(arch arch) {
fmt.Fprintln(w, "var _ = objabi.GOROOT // in case not otherwise used")
fmt.Fprintln(w)
const chunkSize = 10
// Main rewrite routine is a switch on v.Op.
fmt.Fprintf(w, "func rewriteValue%s(v *Value) bool {\n", arch.name)
fmt.Fprintf(w, "switch v.Op {\n")
for _, op := range ops {
fmt.Fprintf(w, "case %s:\n", op)
fmt.Fprintf(w, "return rewriteValue%s_%s(v)\n", arch.name, op)
fmt.Fprint(w, "return ")
for chunk := 0; chunk < len(oprules[op]); chunk += chunkSize {
if chunk > 0 {
fmt.Fprint(w, " || ")
}
fmt.Fprintf(w, "rewriteValue%s_%s_%d(v)", arch.name, op, chunk)
}
fmt.Fprintln(w)
}
fmt.Fprintf(w, "}\n")
fmt.Fprintf(w, "return false\n")
......@@ -176,67 +184,73 @@ func genRules(arch arch) {
// Generate a routine per op. Note that we don't make one giant routine
// because it is too big for some compilers.
for _, op := range ops {
buf := new(bytes.Buffer)
var canFail bool
for i, rule := range oprules[op] {
match, cond, result := rule.parse()
fmt.Fprintf(buf, "// match: %s\n", match)
fmt.Fprintf(buf, "// cond: %s\n", cond)
fmt.Fprintf(buf, "// result: %s\n", result)
canFail = false
fmt.Fprintf(buf, "for {\n")
if genMatch(buf, arch, match, rule.loc) {
canFail = true
for chunk := 0; chunk < len(oprules[op]); chunk += chunkSize {
buf := new(bytes.Buffer)
var canFail bool
endchunk := chunk + chunkSize
if endchunk > len(oprules[op]) {
endchunk = len(oprules[op])
}
for i, rule := range oprules[op][chunk:endchunk] {
match, cond, result := rule.parse()
fmt.Fprintf(buf, "// match: %s\n", match)
fmt.Fprintf(buf, "// cond: %s\n", cond)
fmt.Fprintf(buf, "// result: %s\n", result)
canFail = false
fmt.Fprintf(buf, "for {\n")
if genMatch(buf, arch, match, rule.loc) {
canFail = true
}
if cond != "" {
fmt.Fprintf(buf, "if !(%s) {\nbreak\n}\n", cond)
canFail = true
if cond != "" {
fmt.Fprintf(buf, "if !(%s) {\nbreak\n}\n", cond)
canFail = true
}
if !canFail && i+chunk != len(oprules[op])-1 {
log.Fatalf("unconditional rule %s is followed by other rules", match)
}
genResult(buf, arch, result, rule.loc)
if *genLog {
fmt.Fprintf(buf, "logRule(\"%s\")\n", rule.loc)
}
fmt.Fprintf(buf, "return true\n")
fmt.Fprintf(buf, "}\n")
}
if !canFail && i != len(oprules[op])-1 {
log.Fatalf("unconditional rule %s is followed by other rules", match)
if canFail {
fmt.Fprintf(buf, "return false\n")
}
genResult(buf, arch, result, rule.loc)
if *genLog {
fmt.Fprintf(buf, "logRule(\"%s\")\n", rule.loc)
body := buf.String()
// Do a rough match to predict whether we need b, config, fe, and/or types.
// It's not precise--thus the blank assignments--but it's good enough
// to avoid generating needless code and doing pointless nil checks.
hasb := strings.Contains(body, "b.")
hasconfig := strings.Contains(body, "config.") || strings.Contains(body, "config)")
hasfe := strings.Contains(body, "fe.")
hasts := strings.Contains(body, "types.")
fmt.Fprintf(w, "func rewriteValue%s_%s_%d(v *Value) bool {\n", arch.name, op, chunk)
if hasb || hasconfig || hasfe {
fmt.Fprintln(w, "b := v.Block")
fmt.Fprintln(w, "_ = b")
}
fmt.Fprintf(buf, "return true\n")
fmt.Fprintf(buf, "}\n")
}
if canFail {
fmt.Fprintf(buf, "return false\n")
}
body := buf.String()
// Do a rough match to predict whether we need b, config, fe, and/or types.
// It's not precise--thus the blank assignments--but it's good enough
// to avoid generating needless code and doing pointless nil checks.
hasb := strings.Contains(body, "b.")
hasconfig := strings.Contains(body, "config.") || strings.Contains(body, "config)")
hasfe := strings.Contains(body, "fe.")
hasts := strings.Contains(body, "types.")
fmt.Fprintf(w, "func rewriteValue%s_%s(v *Value) bool {\n", arch.name, op)
if hasb || hasconfig || hasfe {
fmt.Fprintln(w, "b := v.Block")
fmt.Fprintln(w, "_ = b")
}
if hasconfig {
fmt.Fprintln(w, "config := b.Func.Config")
fmt.Fprintln(w, "_ = config")
}
if hasfe {
fmt.Fprintln(w, "fe := b.Func.fe")
fmt.Fprintln(w, "_ = fe")
}
if hasts {
fmt.Fprintln(w, "types := &b.Func.Config.Types")
fmt.Fprintln(w, "_ = types")
if hasconfig {
fmt.Fprintln(w, "config := b.Func.Config")
fmt.Fprintln(w, "_ = config")
}
if hasfe {
fmt.Fprintln(w, "fe := b.Func.fe")
fmt.Fprintln(w, "_ = fe")
}
if hasts {
fmt.Fprintln(w, "types := &b.Func.Config.Types")
fmt.Fprintln(w, "_ = types")
}
fmt.Fprint(w, body)
fmt.Fprintf(w, "}\n")
}
fmt.Fprint(w, body)
fmt.Fprintf(w, "}\n")
}
// Generate block rewrite function. There are only a few block types
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
......@@ -14,31 +14,31 @@ var _ = objabi.GOROOT // in case not otherwise used
func rewriteValuedec(v *Value) bool {
switch v.Op {
case OpComplexImag:
return rewriteValuedec_OpComplexImag(v)
return rewriteValuedec_OpComplexImag_0(v)
case OpComplexReal:
return rewriteValuedec_OpComplexReal(v)
return rewriteValuedec_OpComplexReal_0(v)
case OpIData:
return rewriteValuedec_OpIData(v)
return rewriteValuedec_OpIData_0(v)
case OpITab:
return rewriteValuedec_OpITab(v)
return rewriteValuedec_OpITab_0(v)
case OpLoad:
return rewriteValuedec_OpLoad(v)
return rewriteValuedec_OpLoad_0(v)
case OpSliceCap:
return rewriteValuedec_OpSliceCap(v)
return rewriteValuedec_OpSliceCap_0(v)
case OpSliceLen:
return rewriteValuedec_OpSliceLen(v)
return rewriteValuedec_OpSliceLen_0(v)
case OpSlicePtr:
return rewriteValuedec_OpSlicePtr(v)
return rewriteValuedec_OpSlicePtr_0(v)
case OpStore:
return rewriteValuedec_OpStore(v)
return rewriteValuedec_OpStore_0(v)
case OpStringLen:
return rewriteValuedec_OpStringLen(v)
return rewriteValuedec_OpStringLen_0(v)
case OpStringPtr:
return rewriteValuedec_OpStringPtr(v)
return rewriteValuedec_OpStringPtr_0(v)
}
return false
}
func rewriteValuedec_OpComplexImag(v *Value) bool {
func rewriteValuedec_OpComplexImag_0(v *Value) bool {
// match: (ComplexImag (ComplexMake _ imag))
// cond:
// result: imag
......@@ -55,7 +55,7 @@ func rewriteValuedec_OpComplexImag(v *Value) bool {
}
return false
}
func rewriteValuedec_OpComplexReal(v *Value) bool {
func rewriteValuedec_OpComplexReal_0(v *Value) bool {
// match: (ComplexReal (ComplexMake real _))
// cond:
// result: real
......@@ -72,7 +72,7 @@ func rewriteValuedec_OpComplexReal(v *Value) bool {
}
return false
}
func rewriteValuedec_OpIData(v *Value) bool {
func rewriteValuedec_OpIData_0(v *Value) bool {
// match: (IData (IMake _ data))
// cond:
// result: data
......@@ -89,7 +89,7 @@ func rewriteValuedec_OpIData(v *Value) bool {
}
return false
}
func rewriteValuedec_OpITab(v *Value) bool {
func rewriteValuedec_OpITab_0(v *Value) bool {
b := v.Block
_ = b
// match: (ITab (IMake itab _))
......@@ -108,7 +108,7 @@ func rewriteValuedec_OpITab(v *Value) bool {
}
return false
}
func rewriteValuedec_OpLoad(v *Value) bool {
func rewriteValuedec_OpLoad_0(v *Value) bool {
b := v.Block
_ = b
config := b.Func.Config
......@@ -244,7 +244,7 @@ func rewriteValuedec_OpLoad(v *Value) bool {
}
return false
}
func rewriteValuedec_OpSliceCap(v *Value) bool {
func rewriteValuedec_OpSliceCap_0(v *Value) bool {
// match: (SliceCap (SliceMake _ _ cap))
// cond:
// result: cap
......@@ -261,7 +261,7 @@ func rewriteValuedec_OpSliceCap(v *Value) bool {
}
return false
}
func rewriteValuedec_OpSliceLen(v *Value) bool {
func rewriteValuedec_OpSliceLen_0(v *Value) bool {
// match: (SliceLen (SliceMake _ len _))
// cond:
// result: len
......@@ -278,7 +278,7 @@ func rewriteValuedec_OpSliceLen(v *Value) bool {
}
return false
}
func rewriteValuedec_OpSlicePtr(v *Value) bool {
func rewriteValuedec_OpSlicePtr_0(v *Value) bool {
// match: (SlicePtr (SliceMake ptr _ _))
// cond:
// result: ptr
......@@ -295,7 +295,7 @@ func rewriteValuedec_OpSlicePtr(v *Value) bool {
}
return false
}
func rewriteValuedec_OpStore(v *Value) bool {
func rewriteValuedec_OpStore_0(v *Value) bool {
b := v.Block
_ = b
config := b.Func.Config
......@@ -456,7 +456,7 @@ func rewriteValuedec_OpStore(v *Value) bool {
}
return false
}
func rewriteValuedec_OpStringLen(v *Value) bool {
func rewriteValuedec_OpStringLen_0(v *Value) bool {
// match: (StringLen (StringMake _ len))
// cond:
// result: len
......@@ -473,7 +473,7 @@ func rewriteValuedec_OpStringLen(v *Value) bool {
}
return false
}
func rewriteValuedec_OpStringPtr(v *Value) bool {
func rewriteValuedec_OpStringPtr_0(v *Value) bool {
// match: (StringPtr (StringMake ptr _))
// cond:
// result: ptr
......
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