Commit bba1ac4f authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: stop adding implicit OKEY nodes

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