mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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/32221 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
4951c79363
commit
bba1ac4fd9
4 changed files with 71 additions and 60 deletions
|
|
@ -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,
|
||||||
|
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if isliteral(index) && isliteral(value) {
|
if isliteral(value) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
||||||
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 (
|
||||||
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 {
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
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 {
|
||||||
// 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 {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue