From 194c79c16390187624f648e4af279a11c67b99ce Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Sun, 28 Feb 2016 15:51:11 -0800 Subject: [PATCH] [dev.ssa] cmd/compile: add constant cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cache gets a 62% hit rate while compiling the standard library. name old time/op new time/op delta Template 449ms ± 2% 443ms ± 4% -1.40% (p=0.006 n=23+25) GoTypes 1.54s ± 1% 1.50s ± 2% -2.53% (p=0.000 n=22+22) Compiler 5.51s ± 1% 5.39s ± 1% -2.29% (p=0.000 n=23+25) name old alloc/op new alloc/op delta Template 90.4MB ± 0% 90.0MB ± 0% -0.45% (p=0.000 n=25+25) GoTypes 334MB ± 0% 331MB ± 0% -1.05% (p=0.000 n=25+25) Compiler 1.12GB ± 0% 1.10GB ± 0% -1.57% (p=0.000 n=25+24) name old allocs/op new allocs/op delta Template 681k ± 0% 682k ± 0% +0.26% (p=0.000 n=25+25) GoTypes 2.23M ± 0% 2.23M ± 0% +0.05% (p=0.000 n=23+24) Compiler 6.46M ± 0% 6.46M ± 0% +0.02% (p=0.000 n=24+25) Change-Id: I2629c291892827493d7b55ec4d83f6973a2ab133 Reviewed-on: https://go-review.googlesource.com/20026 Reviewed-by: Keith Randall Run-TryBot: Josh Bleecher Snyder Reviewed-by: Alexandru Moșoi TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/ssa/TODO | 2 +- src/cmd/compile/internal/ssa/func.go | 39 +++++++++++++-------- src/cmd/compile/internal/ssa/gen/rulegen.go | 2 ++ 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/ssa/TODO b/src/cmd/compile/internal/ssa/TODO index 57bed9a9a30..4e39d1e9c35 100644 --- a/src/cmd/compile/internal/ssa/TODO +++ b/src/cmd/compile/internal/ssa/TODO @@ -47,7 +47,7 @@ Optimizations (better compiler) ------------------------------- - Smaller Value.Type (int32 or ptr)? Get rid of types altogether? - OpStore uses 3 args. Increase the size of Value.argstorage to 3? -- Constant cache +- Use a constant cache for OpConstNil, OpConstInterface, OpConstSlice, maybe OpConstString - Handle signed division overflow and sign extension earlier - Implement 64 bit const division with high multiply, maybe in the frontend? - Add bit widths to complex ops diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 9441110769f..7cc5f6c8d99 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -35,6 +35,8 @@ type Func struct { freeValues *Value // free Values linked by argstorage[0]. All other fields except ID are 0/nil. freeBlocks *Block // free Blocks linked by succstorage[0]. All other fields except ID are 0/nil. + + constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type } // NumBlocks returns an integer larger than the id of any Block in the Func. @@ -270,38 +272,47 @@ func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1, return v } +// constVal returns a constant value for c. +func (f *Func) constVal(line int32, op Op, t Type, c int64) *Value { + if f.constants == nil { + f.constants = make(map[int64][]*Value) + } + vv := f.constants[c] + for _, v := range vv { + if v.Op == op && v.Type.Equal(t) { + return v + } + } + v := f.Entry.NewValue0I(line, op, t, c) + f.constants[c] = append(vv, v) + return v +} + // ConstInt returns an int constant representing its argument. func (f *Func) ConstBool(line int32, t Type, c bool) *Value { - // TODO: cache? i := int64(0) if c { i = 1 } - return f.Entry.NewValue0I(line, OpConstBool, t, i) + return f.constVal(line, OpConstBool, t, i) } func (f *Func) ConstInt8(line int32, t Type, c int8) *Value { - // TODO: cache? - return f.Entry.NewValue0I(line, OpConst8, t, int64(c)) + return f.constVal(line, OpConst8, t, int64(c)) } func (f *Func) ConstInt16(line int32, t Type, c int16) *Value { - // TODO: cache? - return f.Entry.NewValue0I(line, OpConst16, t, int64(c)) + return f.constVal(line, OpConst16, t, int64(c)) } func (f *Func) ConstInt32(line int32, t Type, c int32) *Value { - // TODO: cache? - return f.Entry.NewValue0I(line, OpConst32, t, int64(c)) + return f.constVal(line, OpConst32, t, int64(c)) } func (f *Func) ConstInt64(line int32, t Type, c int64) *Value { - // TODO: cache? - return f.Entry.NewValue0I(line, OpConst64, t, c) + return f.constVal(line, OpConst64, t, c) } func (f *Func) ConstFloat32(line int32, t Type, c float64) *Value { - // TODO: cache? - return f.Entry.NewValue0I(line, OpConst32F, t, int64(math.Float64bits(c))) + return f.constVal(line, OpConst32F, t, int64(math.Float64bits(c))) } func (f *Func) ConstFloat64(line int32, t Type, c float64) *Value { - // TODO: cache? - return f.Entry.NewValue0I(line, OpConst64F, t, int64(math.Float64bits(c))) + return f.constVal(line, OpConst64F, t, int64(math.Float64bits(c))) } func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go index 55287c187d8..c2da3e64892 100644 --- a/src/cmd/compile/internal/ssa/gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/gen/rulegen.go @@ -426,6 +426,8 @@ func genResult(w io.Writer, arch arch, result string) { genResult0(w, arch, result, new(int), true, move) } func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move bool) string { + // TODO: when generating a constant result, use f.constVal to avoid + // introducing copies just to clean them up again. if result[0] != '(' { // variable if top {