]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/gc: avoid turning 'x = f()' into 'tmp = f(); x = tmp' for simple x
authorRuss Cox <rsc@golang.org>
Fri, 1 May 2015 00:35:47 +0000 (20:35 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 12 May 2015 16:26:47 +0000 (16:26 +0000)
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>
src/cmd/internal/gc/order.go

index f08f5f20fe710f781334f984923b916db947ed85..82876f81bc2a003de1057ca3964d4a6eaf1388e5 100644 (file)
@@ -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