Commit 18d98bc9 authored by Russ Cox's avatar Russ Cox

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/9721Reviewed-by: default avatarDavid Chase <drchase@google.com>
parent 3f209abb
......@@ -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
......
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