]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: eliminate stores to unread auto variables
authorMichael Munday <mike.munday@ibm.com>
Wed, 29 Mar 2017 18:01:41 +0000 (14:01 -0400)
committerMichael Munday <mike.munday@ibm.com>
Thu, 24 Aug 2017 16:53:56 +0000 (16:53 +0000)
This is a crude compiler pass to eliminate stores to auto variables
that are only ever written to.

Eliminates an unnecessary store to x from the following code:

func f() int {
var x := 1
return *(&x)
}

Fixes #19765.

Change-Id: If2c63a8ae67b8c590b6e0cc98a9610939a3eeffa
Reviewed-on: https://go-review.googlesource.com/38746
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/gc/asm_test.go
src/cmd/compile/internal/gc/plive.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/ssa/compile.go
src/cmd/compile/internal/ssa/deadstore.go
src/runtime/runtime-gdb_test.go
test/live.go
test/live2.go

index 375fd790fee81affabea27e75607921d2d5f5098..b6452d96bb4038ba6d95d15fa01542baed886922 100644 (file)
@@ -973,13 +973,23 @@ var linuxAMD64Tests = []*asmTest{
                // make sure assembly output has matching offset and base register.
                `
                func f72(a, b int) int {
-                       var x [16]byte // use some frame
-                       _ = x
+                       //go:noinline
+                       func() {_, _ = a, b} () // use some frame
                        return b
                }
                `,
                []string{"b\\+40\\(SP\\)"},
        },
+       {
+               // check that stack store is optimized away
+               `
+               func $() int {
+                       var x int
+                       return *(&x)
+               }
+               `,
+               []string{"TEXT\t.*, [$]0-8"},
+       },
 }
 
 var linux386Tests = []*asmTest{
@@ -1015,6 +1025,16 @@ var linux386Tests = []*asmTest{
                }`,
                []string{"\tADDL\t[$]19", "\tIMULL"}, // (n+19)*a
        },
+       {
+               // check that stack store is optimized away
+               `
+               func $() int {
+                       var x int
+                       return *(&x)
+               }
+               `,
+               []string{"TEXT\t.*, [$]0-4"},
+       },
 }
 
 var linuxS390XTests = []*asmTest{
@@ -1293,6 +1313,16 @@ var linuxS390XTests = []*asmTest{
                `,
                []string{"\tFLOGR\t"},
        },
+       {
+               // check that stack store is optimized away
+               `
+               func $() int {
+                       var x int
+                       return *(&x)
+               }
+               `,
+               []string{"TEXT\t.*, [$]0-8"},
+       },
 }
 
 var linuxARMTests = []*asmTest{
@@ -1404,13 +1434,23 @@ var linuxARMTests = []*asmTest{
                // make sure assembly output has matching offset and base register.
                `
                func f13(a, b int) int {
-                       var x [16]byte // use some frame
-                       _ = x
+                       //go:noinline
+                       func() {_, _ = a, b} () // use some frame
                        return b
                }
                `,
                []string{"b\\+4\\(FP\\)"},
        },
+       {
+               // check that stack store is optimized away
+               `
+               func $() int {
+                       var x int
+                       return *(&x)
+               }
+               `,
+               []string{"TEXT\t.*, [$]-4-4"},
+       },
 }
 
 var linuxARM64Tests = []*asmTest{
@@ -1584,6 +1624,16 @@ var linuxARM64Tests = []*asmTest{
                `,
                []string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"},
        },
+       {
+               // check that stack store is optimized away
+               `
+               func $() int {
+                       var x int
+                       return *(&x)
+               }
+               `,
+               []string{"TEXT\t.*, [$]-8-8"},
+       },
 }
 
 var linuxMIPSTests = []*asmTest{
@@ -1667,6 +1717,16 @@ var linuxMIPSTests = []*asmTest{
                `,
                []string{"\tCLZ\t"},
        },
+       {
+               // check that stack store is optimized away
+               `
+               func $() int {
+                       var x int
+                       return *(&x)
+               }
+               `,
+               []string{"TEXT\t.*, [$]-4-4"},
+       },
 }
 
 var linuxPPC64LETests = []*asmTest{
@@ -1751,6 +1811,16 @@ var linuxPPC64LETests = []*asmTest{
                `,
                []string{"\tROTL\t"},
        },
+       {
+               // check that stack store is optimized away
+               `
+               func $() int {
+                       var x int
+                       return *(&x)
+               }
+               `,
+               []string{"TEXT\t.*, [$]0-8"},
+       },
 }
 
 // TestLineNumber checks to make sure the generated assembly has line numbers
index ca449b72bdf4129c0d212eeb5ccb6c975d124c8d..1bb714e837e5ba0f8c8bb207240a7ef694231e12 100644 (file)
@@ -291,7 +291,14 @@ func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) {
                return n, ssa.SymWrite
 
        case ssa.OpVarLive:
-               return v.Aux.(*Node), ssa.SymRead
+               switch a := v.Aux.(type) {
+               case *ssa.ArgSymbol:
+                       return a.Node.(*Node), ssa.SymRead
+               case *ssa.AutoSymbol:
+                       return a.Node.(*Node), ssa.SymRead
+               default:
+                       Fatalf("unknown VarLive aux type: %s", v.LongString())
+               }
        case ssa.OpVarDef, ssa.OpVarKill:
                return v.Aux.(*Node), ssa.SymWrite
        case ssa.OpKeepAlive:
index 798a01ae16a83f7d5ba00f3f5257f1d21f888b37..47fb6938a1862bf9235a1a6c0e508e20ba93df80 100644 (file)
@@ -936,7 +936,16 @@ func (s *state) stmt(n *Node) {
                if !n.Left.Addrtaken() {
                        s.Fatalf("VARLIVE variable %v must have Addrtaken set", n.Left)
                }
-               s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, n.Left, s.mem())
+               var aux interface{}
+               switch n.Left.Class() {
+               case PAUTO:
+                       aux = s.lookupSymbol(n.Left, &ssa.AutoSymbol{Node: n.Left})
+               case PPARAM, PPARAMOUT:
+                       aux = s.lookupSymbol(n.Left, &ssa.ArgSymbol{Node: n.Left})
+               default:
+                       s.Fatalf("VARLIVE variable %v must be Auto or Arg", n.Left)
+               }
+               s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, aux, s.mem())
 
        case OCHECKNIL:
                p := s.expr(n.Left)
index 315416babd0a7bb8a1fdd8546bd868fe2ab833c0..00a4b04ce500596a85bb78d0d5797c859e2b6933 100644 (file)
@@ -356,6 +356,7 @@ var passes = [...]pass{
        {name: "tighten", fn: tighten}, // move values closer to their uses
        {name: "lower", fn: lower, required: true},
        {name: "lowered cse", fn: cse},
+       {name: "elim unread autos", fn: elimUnreadAutos},
        {name: "lowered deadcode", fn: deadcode, required: true},
        {name: "checkLower", fn: checkLower, required: true},
        {name: "late phielim", fn: phielim},
index 08a2c6df14aa6061ca6d9e027fcc03259398127e..7506df8b19f14e73f4a08935b9033dfd4ebd9fd5 100644 (file)
@@ -131,3 +131,55 @@ func dse(f *Func) {
                }
        }
 }
+
+// elimUnreadAutos deletes stores to autos that are never read from.
+func elimUnreadAutos(f *Func) {
+       // Loop over all ops that affect autos taking note of which
+       // autos we need and also stores that we might be able to
+       // eliminate.
+       seen := make(map[GCNode]bool)
+       var stores []*Value
+       for _, b := range f.Blocks {
+               for _, v := range b.Values {
+                       var sym *AutoSymbol
+                       sym, ok := v.Aux.(*AutoSymbol)
+                       if !ok {
+                               continue
+                       }
+
+                       effect := v.Op.SymEffect()
+                       switch effect {
+                       case SymWrite:
+                               // If we haven't seen the auto yet
+                               // then this might be a store we can
+                               // eliminate.
+                               if !seen[sym.Node] {
+                                       stores = append(stores, v)
+                               }
+                       default:
+                               // Assume the auto is needed (loaded,
+                               // has its address taken, etc.).
+                               // Note we have to check the uses
+                               // because dead loads haven't been
+                               // eliminated yet.
+                               if v.Uses > 0 {
+                                       seen[sym.Node] = true
+                               }
+                       }
+               }
+       }
+
+       // Eliminate stores to unread autos.
+       for _, store := range stores {
+               sym, _ := store.Aux.(*AutoSymbol)
+               if seen[sym.Node] {
+                       continue
+               }
+
+               // replace store with OpCopy
+               store.SetArgs1(store.MemoryArg())
+               store.Aux = nil
+               store.AuxInt = 0
+               store.Op = OpCopy
+       }
+}
index 1318babdeaf6770cb37c996b2e269dcf2afa4d71..811d81f96111d7051f3b85e848bf8731a4263071 100644 (file)
@@ -84,7 +84,7 @@ func main() {
        slicevar := make([]string, 0, 16)
        slicevar = append(slicevar, mapvar["abc"])
        fmt.Println("hi") // line 13
-       _ = ptrvar
+       runtime.KeepAlive(ptrvar)
        gslice = slicevar
        runtime.KeepAlive(mapvar)
 }
index ef988a05e5ca8a5708c7f338b94d94b790924a17..2eb442cd2fd8392b27fe61880543e37206f0463f 100644 (file)
@@ -239,15 +239,6 @@ func f14() {
 
 func g14() string
 
-func f15() {
-       var x string
-       _ = &x
-       x = g15()      // ERROR "live at call to g15: x$"
-       printstring(x) // ERROR "live at call to printstring: x$"
-}
-
-func g15() string
-
 // Checking that various temporaries do not persist or cause
 // ambiguously live values that must be zeroed.
 // The exact temporary names are inconsequential but we are
@@ -384,10 +375,9 @@ func f25(b bool) {
                return
        }
        var x string
-       _ = &x
-       x = g15()      // ERROR "live at call to g15: x$"
-       printstring(x) // ERROR "live at call to printstring: x$"
-} // ERROR "live at call to deferreturn: x$"
+       x = g14()
+       printstring(x)
+}
 
 func g25()
 
@@ -641,6 +631,9 @@ type T40 struct {
        m map[int]int
 }
 
+//go:noescape
+func useT40(*T40)
+
 func newT40() *T40 {
        ret := T40{}
        ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret$"
@@ -658,7 +651,7 @@ func good40() {
        ret.m = make(map[int]int) // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
        t := &ret
        printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
-       _ = t
+       useT40(t) // ERROR "live at call to useT40: .autotmp_[0-9]+ ret$"
 }
 
 func ddd1(x, y *int) { // ERROR "live at entry to ddd1: x y$"
index 6138d369c97bfad6fc88366ad0cd57d08b9e3665..5c5706d225765064ee589b16ebf3fdf8721bc9ef 100644 (file)
@@ -14,6 +14,9 @@ package main
 
 func printnl()
 
+//go:noescape
+func useT40(*T40)
+
 type T40 struct {
        m map[int]int
 }
@@ -27,7 +30,7 @@ func newT40() *T40 {
 func bad40() {
        t := newT40() // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
        printnl()     // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
-       _ = t
+       useT40(t)     // ERROR "live at call to useT40: .autotmp_[0-9]+ ret$"
 }
 
 func good40() {
@@ -35,5 +38,5 @@ func good40() {
        ret.m = make(map[int]int) // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
        t := &ret
        printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
-       _ = t
+       useT40(t) // ERROR "live at call to useT40: .autotmp_[0-9]+ ret$"
 }