mirror of https://github.com/golang/go.git
cmd/internal/gc: avoid turning 'x = f()' into 'tmp = f(); x = tmp' for simple x
This slows down more things than I expected, but it also speeds things up, and it reduces stack frame sizes and the load on the optimizer, so it's still likely a net win. name old mean new mean delta BenchmarkBinaryTree17 13.2s × (0.98,1.03) 13.2s × (0.98,1.02) ~ (p=0.795) BenchmarkFannkuch11 4.41s × (1.00,1.00) 4.45s × (0.99,1.01) +0.88% (p=0.000) BenchmarkFmtFprintfEmpty 86.4ns × (0.99,1.01) 90.1ns × (0.95,1.05) +4.31% (p=0.000) BenchmarkFmtFprintfString 318ns × (0.96,1.07) 337ns × (0.98,1.03) +6.05% (p=0.000) BenchmarkFmtFprintfInt 332ns × (0.97,1.04) 320ns × (0.97,1.02) -3.42% (p=0.000) BenchmarkFmtFprintfIntInt 562ns × (0.96,1.04) 574ns × (0.96,1.06) +2.00% (p=0.013) BenchmarkFmtFprintfPrefixedInt 442ns × (0.96,1.06) 450ns × (0.97,1.05) +1.73% (p=0.039) BenchmarkFmtFprintfFloat 640ns × (0.99,1.02) 659ns × (0.99,1.03) +3.01% (p=0.000) BenchmarkFmtManyArgs 2.19µs × (0.97,1.06) 2.21µs × (0.98,1.02) ~ (p=0.104) BenchmarkGobDecode 20.0ms × (0.98,1.03) 19.7ms × (0.97,1.04) -1.35% (p=0.035) BenchmarkGobEncode 17.8ms × (0.96,1.04) 18.0ms × (0.96,1.06) ~ (p=0.131) BenchmarkGzip 653ms × (0.99,1.02) 652ms × (0.99,1.01) ~ (p=0.572) BenchmarkGunzip 143ms × (0.99,1.02) 142ms × (1.00,1.01) -0.52% (p=0.005) BenchmarkHTTPClientServer 110µs × (0.98,1.03) 108µs × (0.99,1.02) -1.90% (p=0.000) BenchmarkJSONEncode 40.0ms × (0.98,1.05) 41.5ms × (0.97,1.06) +3.89% (p=0.000) BenchmarkJSONDecode 118ms × (0.99,1.01) 118ms × (0.98,1.01) +0.69% (p=0.010) BenchmarkMandelbrot200 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.924) BenchmarkGoParse 8.43ms × (0.92,1.11) 8.56ms × (0.93,1.05) ~ (p=0.242) BenchmarkRegexpMatchEasy0_32 180ns × (0.91,1.07) 163ns × (1.00,1.00) -9.33% (p=0.000) BenchmarkRegexpMatchEasy0_1K 550ns × (0.98,1.02) 558ns × (0.99,1.01) +1.44% (p=0.000) BenchmarkRegexpMatchEasy1_32 152ns × (0.94,1.05) 139ns × (0.98,1.02) -8.51% (p=0.000) BenchmarkRegexpMatchEasy1_1K 909ns × (0.98,1.06) 868ns × (0.99,1.02) -4.52% (p=0.000) BenchmarkRegexpMatchMedium_32 262ns × (0.97,1.03) 253ns × (0.99,1.02) -3.31% (p=0.000) BenchmarkRegexpMatchMedium_1K 73.8µs × (0.98,1.04) 72.7µs × (1.00,1.01) -1.61% (p=0.001) BenchmarkRegexpMatchHard_32 3.87µs × (0.99,1.02) 3.87µs × (1.00,1.01) ~ (p=0.791) BenchmarkRegexpMatchHard_1K 118µs × (0.98,1.04) 117µs × (0.99,1.02) ~ (p=0.110) BenchmarkRevcomp 1.00s × (0.94,1.10) 0.99s × (0.94,1.09) ~ (p=0.433) BenchmarkTemplate 140ms × (0.97,1.04) 140ms × (0.99,1.01) ~ (p=0.303) BenchmarkTimeParse 622ns × (0.99,1.02) 625ns × (0.99,1.01) +0.51% (p=0.001) BenchmarkTimeFormat 731ns × (0.98,1.04) 719ns × (0.99,1.01) -1.66% (p=0.000) Change-Id: Ibc3edb59a178adafda50156f46a341f69a17d83f Reviewed-on: https://go-review.googlesource.com/9721 Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
3f209abb29
commit
18d98bc9cb
|
|
@ -264,7 +264,7 @@ func orderblock(l **NodeList) {
|
|||
func orderexprinplace(np **Node, outer *Order) {
|
||||
n := *np
|
||||
var order Order
|
||||
orderexpr(&n, &order)
|
||||
orderexpr(&n, &order, nil)
|
||||
addinit(&n, order.out)
|
||||
|
||||
// insert new temporaries from order
|
||||
|
|
@ -358,8 +358,8 @@ func ordercallargs(l **NodeList, order *Order) {
|
|||
// Ordercall orders the call expression n.
|
||||
// n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
|
||||
func ordercall(n *Node, order *Order) {
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Right, order) // ODDDARG temp
|
||||
orderexpr(&n.Left, order, nil)
|
||||
orderexpr(&n.Right, order, nil) // ODDDARG temp
|
||||
ordercallargs(&n.List, order)
|
||||
}
|
||||
|
||||
|
|
@ -447,8 +447,14 @@ func orderstmt(n *Node, order *Order) {
|
|||
case OVARKILL:
|
||||
order.out = list(order.out, n)
|
||||
|
||||
case OAS,
|
||||
OAS2,
|
||||
case OAS:
|
||||
t := marktemp(order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
orderexpr(&n.Right, order, n.Left)
|
||||
ordermapassign(n, order)
|
||||
cleantemp(t, order)
|
||||
|
||||
case OAS2,
|
||||
OCLOSE,
|
||||
OCOPY,
|
||||
OPRINT,
|
||||
|
|
@ -456,29 +462,27 @@ func orderstmt(n *Node, order *Order) {
|
|||
ORECOVER,
|
||||
ORECV:
|
||||
t := marktemp(order)
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Right, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
orderexpr(&n.Right, order, nil)
|
||||
orderexprlist(n.List, order)
|
||||
orderexprlist(n.Rlist, order)
|
||||
switch n.Op {
|
||||
case OAS, OAS2, OAS2DOTTYPE:
|
||||
case OAS2, OAS2DOTTYPE:
|
||||
ordermapassign(n, order)
|
||||
|
||||
default:
|
||||
order.out = list(order.out, n)
|
||||
}
|
||||
|
||||
cleantemp(t, order)
|
||||
|
||||
// Special: rewrite l op= r into l = l op r.
|
||||
// This simplies quite a few operations;
|
||||
// most important is that it lets us separate
|
||||
// out map read from map write when l is
|
||||
// a map index expression.
|
||||
case OASOP:
|
||||
// Special: rewrite l op= r into l = l op r.
|
||||
// This simplies quite a few operations;
|
||||
// most important is that it lets us separate
|
||||
// out map read from map write when l is
|
||||
// a map index expression.
|
||||
t := marktemp(order)
|
||||
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
n.Left = ordersafeexpr(n.Left, order)
|
||||
tmp1 := treecopy(n.Left)
|
||||
if tmp1.Op == OINDEXMAP {
|
||||
|
|
@ -487,7 +491,7 @@ func orderstmt(n *Node, order *Order) {
|
|||
tmp1 = ordercopyexpr(tmp1, n.Left.Type, order, 0)
|
||||
n.Right = Nod(int(n.Etype), tmp1, n.Right)
|
||||
typecheck(&n.Right, Erv)
|
||||
orderexpr(&n.Right, order)
|
||||
orderexpr(&n.Right, order, nil)
|
||||
n.Etype = 0
|
||||
n.Op = OAS
|
||||
ordermapassign(n, order)
|
||||
|
|
@ -500,8 +504,8 @@ func orderstmt(n *Node, order *Order) {
|
|||
|
||||
orderexprlist(n.List, order)
|
||||
r := n.Rlist.N
|
||||
orderexpr(&r.Left, order)
|
||||
orderexpr(&r.Right, order)
|
||||
orderexpr(&r.Left, order, nil)
|
||||
orderexpr(&r.Right, order, nil)
|
||||
|
||||
// See case OINDEXMAP below.
|
||||
if r.Right.Op == OARRAYBYTESTR {
|
||||
|
|
@ -527,7 +531,7 @@ func orderstmt(n *Node, order *Order) {
|
|||
t := marktemp(order)
|
||||
|
||||
orderexprlist(n.List, order)
|
||||
orderexpr(&n.Rlist.N.Left, order) // i in i.(T)
|
||||
orderexpr(&n.Rlist.N.Left, order, nil) // i in i.(T)
|
||||
if isblank(n.List.N) {
|
||||
order.out = list(order.out, n)
|
||||
} else {
|
||||
|
|
@ -548,7 +552,7 @@ func orderstmt(n *Node, order *Order) {
|
|||
t := marktemp(order)
|
||||
|
||||
orderexprlist(n.List, order)
|
||||
orderexpr(&n.Rlist.N.Left, order) // arg to recv
|
||||
orderexpr(&n.Rlist.N.Left, order, nil) // arg to recv
|
||||
ch := n.Rlist.N.Left.Type
|
||||
tmp1 := ordertemp(ch.Type, order, haspointers(ch.Type))
|
||||
var tmp2 *Node
|
||||
|
|
@ -617,8 +621,8 @@ func orderstmt(n *Node, order *Order) {
|
|||
|
||||
case ODELETE:
|
||||
t := marktemp(order)
|
||||
orderexpr(&n.List.N, order)
|
||||
orderexpr(&n.List.Next.N, order)
|
||||
orderexpr(&n.List.N, order, nil)
|
||||
orderexpr(&n.List.Next.N, order, nil)
|
||||
orderaddrtemp(&n.List.Next.N, order) // map key
|
||||
order.out = list(order.out, n)
|
||||
cleantemp(t, order)
|
||||
|
|
@ -659,7 +663,7 @@ func orderstmt(n *Node, order *Order) {
|
|||
case OPANIC:
|
||||
t := marktemp(order)
|
||||
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
if !Isinter(n.Left.Type) {
|
||||
orderaddrtemp(&n.Left, order)
|
||||
}
|
||||
|
|
@ -677,7 +681,7 @@ func orderstmt(n *Node, order *Order) {
|
|||
case ORANGE:
|
||||
t := marktemp(order)
|
||||
|
||||
orderexpr(&n.Right, order)
|
||||
orderexpr(&n.Right, order, nil)
|
||||
switch n.Type.Etype {
|
||||
default:
|
||||
Fatal("orderstmt range %v", n.Type)
|
||||
|
|
@ -793,7 +797,7 @@ func orderstmt(n *Node, order *Order) {
|
|||
// r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
|
||||
// r->left == N means 'case <-c'.
|
||||
// c is always evaluated; x and ok are only evaluated when assigned.
|
||||
orderexpr(&r.Right.Left, order)
|
||||
orderexpr(&r.Right.Left, order, nil)
|
||||
|
||||
if r.Right.Left.Op != ONAME {
|
||||
r.Right.Left = ordercopyexpr(r.Right.Left, r.Right.Left.Type, order, 0)
|
||||
|
|
@ -853,12 +857,12 @@ func orderstmt(n *Node, order *Order) {
|
|||
|
||||
// case c <- x
|
||||
// r->left is c, r->right is x, both are always evaluated.
|
||||
orderexpr(&r.Left, order)
|
||||
orderexpr(&r.Left, order, nil)
|
||||
|
||||
if !istemp(r.Left) {
|
||||
r.Left = ordercopyexpr(r.Left, r.Left.Type, order, 0)
|
||||
}
|
||||
orderexpr(&r.Right, order)
|
||||
orderexpr(&r.Right, order, nil)
|
||||
if !istemp(r.Right) {
|
||||
r.Right = ordercopyexpr(r.Right, r.Right.Type, order, 0)
|
||||
}
|
||||
|
|
@ -884,8 +888,8 @@ func orderstmt(n *Node, order *Order) {
|
|||
case OSEND:
|
||||
t := marktemp(order)
|
||||
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Right, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
orderexpr(&n.Right, order, nil)
|
||||
orderaddrtemp(&n.Right, order)
|
||||
order.out = list(order.out, n)
|
||||
cleantemp(t, order)
|
||||
|
|
@ -900,7 +904,7 @@ func orderstmt(n *Node, order *Order) {
|
|||
case OSWITCH:
|
||||
t := marktemp(order)
|
||||
|
||||
orderexpr(&n.Ntest, order)
|
||||
orderexpr(&n.Ntest, order, nil)
|
||||
for l := n.List; l != nil; l = l.Next {
|
||||
if l.N.Op != OXCASE {
|
||||
Fatal("order switch case %v", Oconv(int(l.N.Op), 0))
|
||||
|
|
@ -919,7 +923,7 @@ func orderstmt(n *Node, order *Order) {
|
|||
// Orderexprlist orders the expression list l into order.
|
||||
func orderexprlist(l *NodeList, order *Order) {
|
||||
for ; l != nil; l = l.Next {
|
||||
orderexpr(&l.N, order)
|
||||
orderexpr(&l.N, order, nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -933,7 +937,10 @@ func orderexprlistinplace(l *NodeList, order *Order) {
|
|||
|
||||
// Orderexpr orders a single expression, appending side
|
||||
// effects to order->out as needed.
|
||||
func orderexpr(np **Node, order *Order) {
|
||||
// If this is part of an assignment lhs = *np, lhs is given.
|
||||
// Otherwise lhs == nil. (When lhs != nil it may be possible
|
||||
// to avoid copying the result of the expression to a temporary.)
|
||||
func orderexpr(np **Node, order *Order, lhs *Node) {
|
||||
n := *np
|
||||
if n == nil {
|
||||
return
|
||||
|
|
@ -944,8 +951,8 @@ func orderexpr(np **Node, order *Order) {
|
|||
|
||||
switch n.Op {
|
||||
default:
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Right, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
orderexpr(&n.Right, order, nil)
|
||||
orderexprlist(n.List, order)
|
||||
orderexprlist(n.Rlist, order)
|
||||
|
||||
|
|
@ -986,8 +993,8 @@ func orderexpr(np **Node, order *Order) {
|
|||
}
|
||||
|
||||
case OCMPSTR:
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Right, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
orderexpr(&n.Right, order, nil)
|
||||
|
||||
// Mark string(byteSlice) arguments to reuse byteSlice backing
|
||||
// buffer during conversion. String comparison does not
|
||||
|
|
@ -1001,9 +1008,9 @@ func orderexpr(np **Node, order *Order) {
|
|||
|
||||
// key must be addressable
|
||||
case OINDEXMAP:
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
|
||||
orderexpr(&n.Right, order)
|
||||
orderexpr(&n.Right, order, nil)
|
||||
|
||||
// For x = m[string(k)] where k is []byte, the allocation of
|
||||
// backing bytes for the string can be avoided by reusing
|
||||
|
|
@ -1029,7 +1036,7 @@ func orderexpr(np **Node, order *Order) {
|
|||
// concrete type (not interface) argument must be addressable
|
||||
// temporary to pass to runtime.
|
||||
case OCONVIFACE:
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
|
||||
if !Isinter(n.Left.Type) {
|
||||
orderaddrtemp(&n.Left, order)
|
||||
|
|
@ -1037,7 +1044,7 @@ func orderexpr(np **Node, order *Order) {
|
|||
|
||||
case OANDAND, OOROR:
|
||||
mark := marktemp(order)
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
|
||||
// Clean temporaries from first branch at beginning of second.
|
||||
// Leave them on the stack so that they can be killed in the outer
|
||||
|
|
@ -1064,7 +1071,9 @@ func orderexpr(np **Node, order *Order) {
|
|||
OREAL,
|
||||
ORECOVER:
|
||||
ordercall(n, order)
|
||||
n = ordercopyexpr(n, n.Type, order, 0)
|
||||
if lhs == nil || lhs.Op != ONAME || flag_race != 0 {
|
||||
n = ordercopyexpr(n, n.Type, order, 0)
|
||||
}
|
||||
|
||||
case OCLOSURE:
|
||||
if n.Noescape && n.Func.Cvars != nil {
|
||||
|
|
@ -1072,8 +1081,8 @@ func orderexpr(np **Node, order *Order) {
|
|||
}
|
||||
|
||||
case OARRAYLIT, OCALLPART:
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Right, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
orderexpr(&n.Right, order, nil)
|
||||
orderexprlist(n.List, order)
|
||||
orderexprlist(n.Rlist, order)
|
||||
if n.Noescape {
|
||||
|
|
@ -1090,7 +1099,7 @@ func orderexpr(np **Node, order *Order) {
|
|||
}
|
||||
|
||||
case ODOTTYPE, ODOTTYPE2:
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
// TODO(rsc): The Isfat is for consistency with componentgen and walkexpr.
|
||||
// It needs to be removed in all three places.
|
||||
// That would allow inlining x.(struct{*int}) the same as x.(*int).
|
||||
|
|
@ -1099,12 +1108,12 @@ func orderexpr(np **Node, order *Order) {
|
|||
}
|
||||
|
||||
case ORECV:
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
n = ordercopyexpr(n, n.Type, order, 1)
|
||||
|
||||
case OEQ, ONE:
|
||||
orderexpr(&n.Left, order)
|
||||
orderexpr(&n.Right, order)
|
||||
orderexpr(&n.Left, order, nil)
|
||||
orderexpr(&n.Right, order, nil)
|
||||
t := n.Left.Type
|
||||
if t.Etype == TSTRUCT || Isfixedarray(t) {
|
||||
// for complex comparisons, we need both args to be
|
||||
|
|
|
|||
Loading…
Reference in New Issue