From bba1ac4fd9d208892aa45e49eda215954008d2ee Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 27 Oct 2016 02:02:30 -0700 Subject: [PATCH] cmd/compile: stop adding implicit OKEY nodes MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/esc.go | 19 ++++++-- src/cmd/compile/internal/gc/sinit.go | 58 ++++++++++++++---------- src/cmd/compile/internal/gc/syntax.go | 2 +- src/cmd/compile/internal/gc/typecheck.go | 52 +++++++++------------ 4 files changed, 71 insertions(+), 60 deletions(-) diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index 5e1c06cbe7..4f37ff0e34 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -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 diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go index d758f35e57..620d7c4b89 100644 --- a/src/cmd/compile/internal/gc/sinit.go +++ b/src/cmd/compile/internal/gc/sinit.go @@ -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 } } diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index ea8e054354..0be10c689b 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -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) diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index eb95c20992..866c387f41 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -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) } -- 2.48.1