]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: cache const nil, iface, slice, and ""
authorJosh Bleecher Snyder <josharian@gmail.com>
Mon, 7 Mar 2016 02:06:09 +0000 (18:06 -0800)
committerJosh Bleecher Snyder <josharian@gmail.com>
Tue, 8 Mar 2016 16:21:51 +0000 (16:21 +0000)
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 <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/ssa/TODO
src/cmd/compile/internal/ssa/func.go

index b13bc86e8564aa8dafdce8ffdfa31f8bd29623c7..317e02ebf7bd1a1f3bdb7c85ac9212797953c5f1 100644 (file)
@@ -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)
index 1eb30d6b891bf906ddc270bc86debdfa6a08c498..c5d6884e278bbeb32ce241697bb7abb8502625f6 100644 (file)
@@ -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
index b648832d6431a85e9528985be49891025780da1f..e3e4b08af11d31fe712b459e4b7165c13d2f7b11 100644 (file)
@@ -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...) }