]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: eliminate copy for static literals
authorKeith Randall <khr@golang.org>
Mon, 18 Apr 2016 18:17:55 +0000 (11:17 -0700)
committerKeith Randall <khr@golang.org>
Mon, 18 Apr 2016 18:51:10 +0000 (18:51 +0000)
*p = [5]byte{1,2,3,4,5}

First we allocate a global containing the RHS.  Then we copy
that global to a local stack variable, and then copy that local
stack variable to *p.  The intermediate copy is unnecessary.

Note that this only works if the RHS is completely constant.
If the code was:
*p = [5]byte{1,2,x,4,5}
this optimization doesn't apply as we have to construct the
RHS on the stack before copying it to *p.

Fixes #12841

Change-Id: I7cd0404ecc7a2d1750cbd8fe1222dba0fa44611f
Reviewed-on: https://go-review.googlesource.com/22192
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/walk.go

index 85ef78b97321ba3be50a25691888cc9d7056e859..1021609d3a1f6e460f56a4e7033b70134b8eca37 100644 (file)
@@ -563,6 +563,32 @@ func getdyn(n *Node, top int) initGenType {
        return mode
 }
 
+// isStaticCompositeLiteral reports whether n is a compile-time constant.
+// n must be a struct or array literal.
+func isStaticCompositeLiteral(n *Node) bool {
+       for _, r := range n.List.Slice() {
+               if r.Op != OKEY {
+                       Fatalf("isStaticCompositeLiteral: rhs not OKEY: %v", r)
+               }
+               index := r.Left
+               if n.Op == OARRAYLIT && index.Op != OLITERAL {
+                       return false
+               }
+               value := r.Right
+               switch value.Op {
+               case OSTRUCTLIT, OARRAYLIT:
+                       if !isStaticCompositeLiteral(value) {
+                               return false
+                       }
+               default:
+                       if value.Op != OLITERAL {
+                               return false
+                       }
+               }
+       }
+       return true
+}
+
 func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
        for _, r := range n.List.Slice() {
                if r.Op != OKEY {
index 78bad8d348786f80ba99e8e63a68eae18e536295..1a15bd93d0c2b30b21e309e88c273f19930fd151 100644 (file)
@@ -1531,6 +1531,19 @@ opswitch:
                n = r
 
        case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
+               if (n.Op == OSTRUCTLIT || (n.Op == OARRAYLIT && !n.Type.IsSlice())) && isStaticCompositeLiteral(n) {
+                       // n can be directly represented in the read-only data section.
+                       // Make direct reference to the static data. See issue 12841.
+                       vstat := staticname(n.Type, 0)
+                       if n.Op == OSTRUCTLIT {
+                               structlit(0, 1, n, vstat, init)
+                       } else {
+                               arraylit(0, 1, n, vstat, init)
+                       }
+                       n = vstat
+                       n = typecheck(n, Erv)
+                       break
+               }
                var_ := temp(n.Type)
                anylit(0, n, var_, init)
                n = var_