From 39214275d6dd89f91ee2b5162698777a97cd6e72 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Sun, 6 Mar 2016 18:06:09 -0800 Subject: [PATCH] cmd/compile: cache const nil, iface, slice, and "" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit name old time/op new time/op delta Template 441ms ± 4% 446ms ± 4% +1.23% (p=0.048 n=22+25) GoTypes 1.51s ± 2% 1.51s ± 2% ~ (p=0.224 n=25+25) Compiler 5.59s ± 1% 5.57s ± 2% -0.38% (p=0.019 n=24+24) name old alloc/op new alloc/op delta Template 85.6MB ± 0% 85.6MB ± 0% -0.11% (p=0.000 n=25+24) GoTypes 307MB ± 0% 305MB ± 0% -0.45% (p=0.000 n=25+25) Compiler 1.06GB ± 0% 1.06GB ± 0% -0.34% (p=0.000 n=25+25) name old allocs/op new allocs/op delta Template 1.10M ± 0% 1.10M ± 0% -0.03% (p=0.001 n=25+24) GoTypes 3.36M ± 0% 3.35M ± 0% -0.13% (p=0.000 n=25+25) Compiler 13.0M ± 0% 13.0M ± 0% -0.12% (p=0.000 n=25+24) Change-Id: I7fc18acbc3b1588aececef9692e24a0bd3dba974 Reviewed-on: https://go-review.googlesource.com/20295 Run-TryBot: Josh Bleecher Snyder TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/ssa.go | 27 +++++++++------ src/cmd/compile/internal/ssa/TODO | 1 - src/cmd/compile/internal/ssa/func.go | 49 +++++++++++++++++++++++----- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index b13bc86e856..317e02ebf7b 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -466,6 +466,10 @@ func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ss } // const* routines add a new const value to the entry block. +func (s *state) constSlice(t ssa.Type) *ssa.Value { return s.f.ConstSlice(s.peekLine(), t) } +func (s *state) constInterface(t ssa.Type) *ssa.Value { return s.f.ConstInterface(s.peekLine(), t) } +func (s *state) constNil(t ssa.Type) *ssa.Value { return s.f.ConstNil(s.peekLine(), t) } +func (s *state) constEmptyString(t ssa.Type) *ssa.Value { return s.f.ConstEmptyString(s.peekLine(), t) } func (s *state) constBool(c bool) *ssa.Value { return s.f.ConstBool(s.peekLine(), Types[TBOOL], c) } @@ -1383,6 +1387,9 @@ func (s *state) expr(n *Node) *ssa.Value { return nil } case CTSTR: + if n.Val().U == "" { + return s.constEmptyString(n.Type) + } return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U) case CTBOOL: v := s.constBool(n.Val().U.(bool)) @@ -1397,11 +1404,11 @@ func (s *state) expr(n *Node) *ssa.Value { t := n.Type switch { case t.IsSlice(): - return s.entryNewValue0(ssa.OpConstSlice, t) + return s.constSlice(t) case t.IsInterface(): - return s.entryNewValue0(ssa.OpConstInterface, t) + return s.constInterface(t) default: - return s.entryNewValue0(ssa.OpConstNil, t) + return s.constNil(t) } case CTFLT: f := n.Val().U.(*Mpflt) @@ -2266,15 +2273,15 @@ func (s *state) zeroVal(t *Type) *ssa.Value { } case t.IsString(): - return s.entryNewValue0A(ssa.OpConstString, t, "") + return s.constEmptyString(t) case t.IsPtr(): - return s.entryNewValue0(ssa.OpConstNil, t) + return s.constNil(t) case t.IsBoolean(): return s.constBool(false) case t.IsInterface(): - return s.entryNewValue0(ssa.OpConstInterface, t) + return s.constInterface(t) case t.IsSlice(): - return s.entryNewValue0(ssa.OpConstSlice, t) + return s.constSlice(t) case t.IsStruct(): n := t.NumFields() v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t) @@ -3191,7 +3198,7 @@ func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value { // return *(((*int)n)+1) // } lenType := n.Type - nilValue := s.newValue0(ssa.OpConstNil, Types[TUINTPTR]) + nilValue := s.constNil(Types[TUINTPTR]) cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue) b := s.endBlock() b.Kind = ssa.BlockIf @@ -3312,7 +3319,7 @@ func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value { tab := s.newValue1(ssa.OpITab, byteptr, v) s.vars[&typVar] = tab - isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.entryNewValue0(ssa.OpConstNil, byteptr)) + isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.constNil(byteptr)) b := s.endBlock() b.Kind = ssa.BlockIf b.Control = isnonnil @@ -3391,7 +3398,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) { // type assertion failed s.startBlock(bFail) - s.vars[&idataVar] = s.entryNewValue0(ssa.OpConstNil, byteptr) + s.vars[&idataVar] = s.constNil(byteptr) s.vars[&okVar] = s.constBool(false) s.endBlock() bFail.AddEdgeTo(bEnd) diff --git a/src/cmd/compile/internal/ssa/TODO b/src/cmd/compile/internal/ssa/TODO index 1eb30d6b891..c5d6884e278 100644 --- a/src/cmd/compile/internal/ssa/TODO +++ b/src/cmd/compile/internal/ssa/TODO @@ -30,7 +30,6 @@ Optimizations (better compiled code) Optimizations (better compiler) ------------------------------- - OpStore uses 3 args. Increase the size of Value.argstorage to 3? -- Use a constant cache for OpConstNil, OpConstInterface, OpConstSlice, maybe OpConstString - Handle signed division overflow and sign extension earlier Regalloc diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index b648832d643..e3e4b08af11 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -273,7 +273,7 @@ func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1, } // constVal returns a constant value for c. -func (f *Func) constVal(line int32, op Op, t Type, c int64) *Value { +func (f *Func) constVal(line int32, op Op, t Type, c int64, setAux bool) *Value { if f.constants == nil { f.constants = make(map[int64][]*Value) } @@ -283,36 +283,67 @@ func (f *Func) constVal(line int32, op Op, t Type, c int64) *Value { return v } } - v := f.Entry.NewValue0I(line, op, t, c) + var v *Value + if setAux { + v = f.Entry.NewValue0I(line, op, t, c) + } else { + v = f.Entry.NewValue0(line, op, t) + } f.constants[c] = append(vv, v) return v } +// These magic auxint values let us easily cache non-numeric constants +// using the same constants map while making collisions unlikely. +// These values are unlikely to occur in regular code and +// are easy to grep for in case of bugs. +const ( + constSliceMagic = 1122334455 + constInterfaceMagic = 2233445566 + constNilMagic = 3344556677 + constEmptyStringMagic = 4455667788 +) + // ConstInt returns an int constant representing its argument. func (f *Func) ConstBool(line int32, t Type, c bool) *Value { i := int64(0) if c { i = 1 } - return f.constVal(line, OpConstBool, t, i) + return f.constVal(line, OpConstBool, t, i, true) } func (f *Func) ConstInt8(line int32, t Type, c int8) *Value { - return f.constVal(line, OpConst8, t, int64(c)) + return f.constVal(line, OpConst8, t, int64(c), true) } func (f *Func) ConstInt16(line int32, t Type, c int16) *Value { - return f.constVal(line, OpConst16, t, int64(c)) + return f.constVal(line, OpConst16, t, int64(c), true) } func (f *Func) ConstInt32(line int32, t Type, c int32) *Value { - return f.constVal(line, OpConst32, t, int64(c)) + return f.constVal(line, OpConst32, t, int64(c), true) } func (f *Func) ConstInt64(line int32, t Type, c int64) *Value { - return f.constVal(line, OpConst64, t, c) + return f.constVal(line, OpConst64, t, c, true) } func (f *Func) ConstFloat32(line int32, t Type, c float64) *Value { - return f.constVal(line, OpConst32F, t, int64(math.Float64bits(c))) + return f.constVal(line, OpConst32F, t, int64(math.Float64bits(c)), true) } func (f *Func) ConstFloat64(line int32, t Type, c float64) *Value { - return f.constVal(line, OpConst64F, t, int64(math.Float64bits(c))) + return f.constVal(line, OpConst64F, t, int64(math.Float64bits(c)), true) +} + +func (f *Func) ConstSlice(line int32, t Type) *Value { + return f.constVal(line, OpConstSlice, t, constSliceMagic, false) +} +func (f *Func) ConstInterface(line int32, t Type) *Value { + return f.constVal(line, OpConstInterface, t, constInterfaceMagic, false) +} +func (f *Func) ConstNil(line int32, t Type) *Value { + return f.constVal(line, OpConstNil, t, constNilMagic, false) +} +func (f *Func) ConstEmptyString(line int32, t Type) *Value { + v := f.constVal(line, OpConstString, t, constEmptyStringMagic, false) + v.Aux = "" + return v } func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args...) }