]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: stop adding implicit OKEY nodes
authorMatthew Dempsky <mdempsky@google.com>
Thu, 27 Oct 2016 09:02:30 +0000 (02:02 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 27 Oct 2016 22:55:30 +0000 (22:55 +0000)
Keys are uncommon in array and slice literals, and normalizing
OARRAYLIT and OSLICELIT nodes to always use OKEY ends up not reducing
complexity much. Instead, only create OKEY nodes to represent explicit
keys, and recalculate implicit keys when/where necessary.

Fixes #15350.

name       old time/op     new time/op     delta
Template       299ms ± 9%      299ms ±12%    ~           (p=0.694 n=28+30)
Unicode        165ms ± 7%      162ms ± 9%    ~           (p=0.084 n=27+27)
GoTypes        950ms ± 9%      963ms ± 5%    ~           (p=0.301 n=30+29)
Compiler       4.23s ± 7%      4.17s ± 7%    ~           (p=0.057 n=29+27)

name       old user-ns/op  new user-ns/op  delta
Template        389M ±15%       400M ±12%    ~           (p=0.202 n=30+29)
Unicode         246M ±21%       232M ±22%  -5.76%        (p=0.006 n=28+29)
GoTypes        1.34G ± 8%      1.34G ± 7%    ~           (p=0.775 n=28+30)
Compiler       5.91G ± 6%      5.87G ± 7%    ~           (p=0.298 n=28+29)

name       old alloc/op    new alloc/op    delta
Template      41.2MB ± 0%     41.2MB ± 0%    ~           (p=0.085 n=30+30)
Unicode       34.0MB ± 0%     31.5MB ± 0%  -7.28%        (p=0.000 n=30+29)
GoTypes        121MB ± 0%      121MB ± 0%    ~           (p=0.657 n=30+30)
Compiler       511MB ± 0%      511MB ± 0%  -0.01%        (p=0.001 n=29+29)

name       old allocs/op   new allocs/op   delta
Template        390k ± 0%       390k ± 0%    ~           (p=0.225 n=30+29)
Unicode         318k ± 0%       293k ± 0%  -8.03%        (p=0.000 n=30+29)
GoTypes        1.16M ± 0%      1.16M ± 0%    ~           (p=0.745 n=30+30)
Compiler       4.35M ± 0%      4.35M ± 0%    ~           (p=0.105 n=30+30)

Change-Id: I6310739a0bfdb54f1ab8a460b2c03615ad1ff5bc
Reviewed-on: https://go-review.googlesource.com/32221
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/esc.go
src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/syntax.go
src/cmd/compile/internal/gc/typecheck.go

index 5e1c06cbe7245d3fb2164eb735300bf1de812993..4f37ff0e34f49348a2af83b872db146143065186 100644 (file)
@@ -899,16 +899,22 @@ func (e *EscState) esc(n *Node, parent *Node) {
 
        case OARRAYLIT:
                // Link values to array
-               for _, n5 := range n.List.Slice() {
-                       e.escassign(n, n5.Right, e.stepAssignWhere(n, n5.Right, "array literal element", n))
+               for _, n2 := range n.List.Slice() {
+                       if n2.Op == OKEY {
+                               n2 = n2.Right
+                       }
+                       e.escassign(n, n2, e.stepAssignWhere(n, n2, "array literal element", n))
                }
 
        case OSLICELIT:
                // Slice is not leaked until proven otherwise
                e.track(n)
                // Link values to slice
-               for _, n5 := range n.List.Slice() {
-                       e.escassign(n, n5.Right, e.stepAssignWhere(n, n5.Right, "slice literal element", n))
+               for _, n2 := range n.List.Slice() {
+                       if n2.Op == OKEY {
+                               n2 = n2.Right
+                       }
+                       e.escassign(n, n2, e.stepAssignWhere(n, n2, "slice literal element", n))
                }
 
                // Link values to struct.
@@ -1928,7 +1934,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
 
        case OSLICELIT:
                for _, n1 := range src.List.Slice() {
-                       e.escwalk(level.dec(), dst, n1.Right, e.stepWalk(dst, n1.Right, "slice-literal-element", step))
+                       if n1.Op == OKEY {
+                               n1 = n1.Right
+                       }
+                       e.escwalk(level.dec(), dst, n1, e.stepWalk(dst, n1, "slice-literal-element", step))
                }
 
                fallthrough
index d758f35e57902acc4ec120dc7dbc1a52f685ead2..620d7c4b8966321c41bcded02303295ce8238aab 100644 (file)
@@ -621,11 +621,13 @@ func getdyn(n *Node, top bool) initGenType {
 
        var mode initGenType
        for _, n1 := range n.List.Slice() {
-               value := n1.Right
-               if n.Op == OSTRUCTLIT {
-                       value = n1.Left
+               switch n1.Op {
+               case OKEY:
+                       n1 = n1.Right
+               case OSTRUCTKEY:
+                       n1 = n1.Left
                }
-               mode |= getdyn(value, false)
+               mode |= getdyn(n1, false)
                if mode == initDynamic|initConst {
                        break
                }
@@ -640,10 +642,10 @@ func isStaticCompositeLiteral(n *Node) bool {
                return false
        case OARRAYLIT:
                for _, r := range n.List.Slice() {
-                       if r.Op != OKEY {
-                               Fatalf("isStaticCompositeLiteral: rhs not OKEY: %v", r)
+                       if r.Op == OKEY {
+                               r = r.Right
                        }
-                       if r.Left.Op != OLITERAL || !isStaticCompositeLiteral(r.Right) {
+                       if !isStaticCompositeLiteral(r) {
                                return false
                        }
                }
@@ -700,11 +702,15 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
        var splitnode func(*Node) (a *Node, value *Node)
        switch n.Op {
        case OARRAYLIT, OSLICELIT:
+               var k int64
                splitnode = func(r *Node) (*Node, *Node) {
-                       if r.Op != OKEY {
-                               Fatalf("fixedlit: rhs not OKEY: %v", r)
+                       if r.Op == OKEY {
+                               k = nonnegintconst(r.Left)
+                               r = r.Right
                        }
-                       return nod(OINDEX, var_, r.Left), r.Right
+                       a := nod(OINDEX, var_, nodintconst(k))
+                       k++
+                       return a, r
                }
        case OSTRUCTLIT:
                splitnode = func(r *Node) (*Node, *Node) {
@@ -733,9 +739,6 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
                }
 
                islit := isliteral(value)
-               if n.Op == OARRAYLIT {
-                       islit = islit && isliteral(r.Left)
-               }
                if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
                        continue
                }
@@ -863,14 +866,16 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
        }
 
        // put dynamics into array (5)
+       var index int64
        for _, r := range n.List.Slice() {
-               if r.Op != OKEY {
-                       Fatalf("slicelit: rhs not OKEY: %v", r)
+               value := r
+               if r.Op == OKEY {
+                       index = nonnegintconst(r.Left)
+                       value = r.Right
                }
-               index := r.Left
-               value := r.Right
-               a := nod(OINDEX, vauto, index)
+               a := nod(OINDEX, vauto, nodintconst(index))
                a.Bounded = true
+               index++
 
                // TODO need to check bounds?
 
@@ -883,7 +888,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
                        continue
                }
 
-               if isliteral(index) && isliteral(value) {
+               if isliteral(value) {
                        continue
                }
 
@@ -1237,12 +1242,14 @@ func initplan(n *Node) {
                Fatalf("initplan")
 
        case OARRAYLIT, OSLICELIT:
+               var k int64
                for _, a := range n.List.Slice() {
-                       index := nonnegintconst(a.Left)
-                       if a.Op != OKEY || index < 0 {
-                               Fatalf("initplan fixedlit")
+                       if a.Op == OKEY {
+                               k = nonnegintconst(a.Left)
+                               a = a.Right
                        }
-                       addvalue(p, index*n.Type.Elem().Width, a.Right)
+                       addvalue(p, k*n.Type.Elem().Width, a)
+                       k++
                }
 
        case OSTRUCTLIT:
@@ -1308,7 +1315,10 @@ func iszero(n *Node) bool {
 
        case OARRAYLIT:
                for _, n1 := range n.List.Slice() {
-                       if !iszero(n1.Right) {
+                       if n1.Op == OKEY {
+                               n1 = n1.Right
+                       }
+                       if !iszero(n1) {
                                return false
                        }
                }
index ea8e0543545689db3c4dd5a51425587ac4b02a2f..0be10c689bd339001ade15483b53576e26a7190c 100644 (file)
@@ -383,7 +383,7 @@ const (
        OIND       // *Left
        OINDEX     // Left[Right] (index of array or slice)
        OINDEXMAP  // Left[Right] (index of map)
-       OKEY       // Left:Right (key:value in struct/array/map literal, or slice index pair)
+       OKEY       // Left:Right (key:value in struct/array/map literal)
        OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
        OLEN       // len(Left)
        OMAKE      // make(List) (before type checking converts to one of the following)
index eb95c20992953911af330d7953526fb9cb8db172..866c387f418354f60237250aae97d2bbe493cd7c 100644 (file)
@@ -2902,7 +2902,6 @@ func typecheckcomplit(n *Node) *Node {
                t = t.Elem()
        }
 
-       var r *Node
        switch t.Etype {
        default:
                yyerror("invalid type for composite literal: %v", t)
@@ -2921,24 +2920,20 @@ func typecheckcomplit(n *Node) *Node {
 
                var length, i int64
                checkBounds := t.IsArray() && !t.isDDDArray()
-               for i2, n2 := range n.List.Slice() {
-                       l := n2
+               nl := n.List.Slice()
+               for i2, l := range nl {
                        setlineno(l)
-                       if l.Op != OKEY {
-                               l = nod(OKEY, nodintconst(int64(i)), l)
-                               l.Left.Type = Types[TINT]
-                               l.Left.Typecheck = 1
-                               n.List.SetIndex(i2, l)
-                       }
-
-                       l.Left = typecheck(l.Left, Erv)
-                       evconst(l.Left)
-
-                       i = nonnegintconst(l.Left)
-                       if i < 0 && l.Left.Diag == 0 {
-                               yyerror("index must be non-negative integer constant")
-                               l.Left.Diag = 1
-                               i = -(1 << 30) // stay negative for a while
+                       vp := &nl[i2]
+                       if l.Op == OKEY {
+                               l.Left = typecheck(l.Left, Erv)
+                               evconst(l.Left)
+                               i = nonnegintconst(l.Left)
+                               if i < 0 && l.Left.Diag == 0 {
+                                       yyerror("index must be non-negative integer constant")
+                                       l.Left.Diag = 1
+                                       i = -(1 << 30) // stay negative for a while
+                               }
+                               vp = &l.Right
                        }
 
                        if i >= 0 && indices != nil {
@@ -2949,6 +2944,12 @@ func typecheckcomplit(n *Node) *Node {
                                }
                        }
 
+                       r := *vp
+                       pushtype(r, t.Elem())
+                       r = typecheck(r, Erv)
+                       r = defaultlit(r, t.Elem())
+                       *vp = assignconv(r, t.Elem(), "array or slice literal")
+
                        i++
                        if i > length {
                                length = i
@@ -2958,12 +2959,6 @@ func typecheckcomplit(n *Node) *Node {
                                        checkBounds = false
                                }
                        }
-
-                       r = l.Right
-                       pushtype(r, t.Elem())
-                       r = typecheck(r, Erv)
-                       r = defaultlit(r, t.Elem())
-                       l.Right = assignconv(r, t.Elem(), "array or slice literal")
                }
 
                if t.isDDDArray() {
@@ -2978,9 +2973,7 @@ func typecheckcomplit(n *Node) *Node {
 
        case TMAP:
                hash := make(map[uint32][]*Node)
-               var l *Node
-               for i3, n3 := range n.List.Slice() {
-                       l = n3
+               for i3, l := range n.List.Slice() {
                        setlineno(l)
                        if l.Op != OKEY {
                                n.List.SetIndex(i3, typecheck(n.List.Index(i3), Erv))
@@ -2988,7 +2981,7 @@ func typecheckcomplit(n *Node) *Node {
                                continue
                        }
 
-                       r = l.Left
+                       r := l.Left
                        pushtype(r, t.Key())
                        r = typecheck(r, Erv)
                        r = defaultlit(r, t.Key())
@@ -3015,7 +3008,6 @@ func typecheckcomplit(n *Node) *Node {
                        // simple list of variables
                        f, it := iterFields(t)
 
-                       var s *Sym
                        ls := n.List.Slice()
                        for i1, n1 := range ls {
                                setlineno(n1)
@@ -3029,7 +3021,7 @@ func typecheckcomplit(n *Node) *Node {
                                        continue
                                }
 
-                               s = f.Sym
+                               s := f.Sym
                                if s != nil && !exportname(s.Name) && s.Pkg != localpkg {
                                        yyerror("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
                                }