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: default 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) {
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
......
......@@ -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
}
}
......
......@@ -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)
......
......@@ -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)
}
......
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