]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: invalidate zero-use values during rewrite
authorKeith Randall <khr@golang.org>
Tue, 30 Jun 2020 22:59:40 +0000 (15:59 -0700)
committerKeith Randall <khr@golang.org>
Thu, 27 Aug 2020 22:56:29 +0000 (22:56 +0000)
This helps remove uses that aren't needed any more.
That in turn helps other rules with Uses==1 conditions fire.

Update #39918

Change-Id: I68635b675472f1d59e59604e4d34b949a0016533
Reviewed-on: https://go-review.googlesource.com/c/go/+/249463
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
src/cmd/compile/internal/ssa/decompose.go
src/cmd/compile/internal/ssa/lower.go
src/cmd/compile/internal/ssa/opt.go
src/cmd/compile/internal/ssa/rewrite.go
src/cmd/compile/internal/ssa/softfloat.go
src/cmd/compile/internal/ssa/value.go

index 6e72e3825ce0a7fa585d3f14c2d4ed41e31f6aef..ab27ba85ae789ea84e6368e9a20e5d74dc6ce6e1 100644 (file)
@@ -23,9 +23,11 @@ func decomposeBuiltIn(f *Func) {
        }
 
        // Decompose other values
-       applyRewrite(f, rewriteBlockdec, rewriteValuedec)
+       // Note: deadcode is false because we need to keep the original
+       // values around so the name component resolution below can still work.
+       applyRewrite(f, rewriteBlockdec, rewriteValuedec, leaveDeadValues)
        if f.Config.RegSize == 4 {
-               applyRewrite(f, rewriteBlockdec64, rewriteValuedec64)
+               applyRewrite(f, rewriteBlockdec64, rewriteValuedec64, leaveDeadValues)
        }
 
        // Split up named values into their components.
@@ -215,7 +217,7 @@ func decomposeInterfacePhi(v *Value) {
 }
 
 func decomposeArgs(f *Func) {
-       applyRewrite(f, rewriteBlockdecArgs, rewriteValuedecArgs)
+       applyRewrite(f, rewriteBlockdecArgs, rewriteValuedecArgs, removeDeadValues)
 }
 
 func decomposeUser(f *Func) {
index ab0fa803bfdeab72c955c2db7ab97905c8144563..f332b2e028e72e96b78fd250cd8dc7c0bc920933 100644 (file)
@@ -7,7 +7,7 @@ package ssa
 // convert to machine-dependent ops
 func lower(f *Func) {
        // repeat rewrites until we find no more rewrites
-       applyRewrite(f, f.Config.lowerBlock, f.Config.lowerValue)
+       applyRewrite(f, f.Config.lowerBlock, f.Config.lowerValue, removeDeadValues)
 }
 
 // checkLower checks for unlowered opcodes and fails if we find one.
index 6e91fd7da3533cb936e30e0253471a5cb30aa860..128e6141750dd39c7696d4ab5e558391d196133c 100644 (file)
@@ -6,5 +6,5 @@ package ssa
 
 // machine-independent optimization
 func opt(f *Func) {
-       applyRewrite(f, rewriteBlockgeneric, rewriteValuegeneric)
+       applyRewrite(f, rewriteBlockgeneric, rewriteValuegeneric, removeDeadValues)
 }
index fb356912960285c9de0fe72045a50c1691251a0f..3df9ad24f91a3c0c3a163290a5f69bf75237c936 100644 (file)
@@ -20,7 +20,15 @@ import (
        "path/filepath"
 )
 
-func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter) {
+type deadValueChoice bool
+
+const (
+       leaveDeadValues  deadValueChoice = false
+       removeDeadValues                 = true
+)
+
+// deadcode indicates that rewrite should try to remove any values that become dead.
+func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValueChoice) {
        // repeat rewrites until we find no more rewrites
        pendingLines := f.cachedLineStarts // Holds statement boundaries that need to be moved to a new value/block
        pendingLines.clear()
@@ -56,6 +64,18 @@ func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter) {
                                        *v0 = *v
                                        v0.Args = append([]*Value{}, v.Args...) // make a new copy, not aliasing
                                }
+                               if v.Uses == 0 && v.removeable() {
+                                       if v.Op != OpInvalid && deadcode == removeDeadValues {
+                                               // Reset any values that are now unused, so that we decrement
+                                               // the use count of all of its arguments.
+                                               // Not quite a deadcode pass, because it does not handle cycles.
+                                               // But it should help Uses==1 rules to fire.
+                                               v.reset(OpInvalid)
+                                               change = true
+                                       }
+                                       // No point rewriting values which aren't used.
+                                       continue
+                               }
 
                                vchange := phielimValue(v)
                                if vchange && debug > 1 {
index 4b578b133b567334341a73bd62854eaef5cfd9fa..8db4334fef8536fca94403c5d739bf6660ef0bf8 100644 (file)
@@ -72,7 +72,7 @@ func softfloat(f *Func) {
        if newInt64 && f.Config.RegSize == 4 {
                // On 32bit arch, decompose Uint64 introduced in the switch above.
                decomposeBuiltIn(f)
-               applyRewrite(f, rewriteBlockdec64, rewriteValuedec64)
+               applyRewrite(f, rewriteBlockdec64, rewriteValuedec64, removeDeadValues)
        }
 
 }
index 7ead0ff3001351440e63a9b8bcfeff12d8c0b9a3..7fc33772d3a6e1150ba9715899fdd22667e76cca 100644 (file)
@@ -460,3 +460,23 @@ func (v *Value) LackingPos() bool {
        return v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive || v.Op == OpPhi ||
                (v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem
 }
+
+// removeable reports whether the value v can be removed from the SSA graph entirely
+// if its use count drops to 0.
+func (v *Value) removeable() bool {
+       if v.Type.IsVoid() {
+               // Void ops, like nil pointer checks, must stay.
+               return false
+       }
+       if v.Type.IsMemory() {
+               // All memory ops aren't needed here, but we do need
+               // to keep calls at least (because they might have
+               // syncronization operations we can't see).
+               return false
+       }
+       if v.Op.HasSideEffects() {
+               // These are mostly synchronization operations.
+               return false
+       }
+       return true
+}