]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: remove dead values after flagalloc
authorJosh Bleecher Snyder <josharian@gmail.com>
Mon, 30 Dec 2019 21:16:28 +0000 (13:16 -0800)
committerJosh Bleecher Snyder <josharian@gmail.com>
Thu, 23 Apr 2020 19:40:07 +0000 (19:40 +0000)
Fix a longstanding TODO.

Provides widespread, minor improvements.
Negligible compiler cost.

Because the freeze nears, put in a safety flag to easily disable.

Change-Id: I338812181ab6d806fecf22afd3c3502e2c94f7a0
Reviewed-on: https://go-review.googlesource.com/c/go/+/229600
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/ssa/flagalloc.go

index 7e7ce1148204308c9c65bbe578264666bd78352d..d50b6159121b0f6864074917120109e4181f1db3 100644 (file)
@@ -106,7 +106,7 @@ func flagalloc(f *Func) {
        }
 
        // Add flag spill and recomputation where they are needed.
-       // TODO: Remove original instructions if they are never used.
+       var remove []*Value // values that should be checked for possible removal
        var oldSched []*Value
        for _, b := range f.Blocks {
                oldSched = append(oldSched[:0], b.Values...)
@@ -131,6 +131,7 @@ func flagalloc(f *Func) {
                        // If v will be spilled, and v uses memory, then we must split it
                        // into a load + a flag generator.
                        if spill[v.ID] && v.MemoryArg() != nil {
+                               remove = append(remove, v)
                                if !f.Config.splitLoad(v) {
                                        f.Fatalf("can't split flag generator: %s", v.LongString())
                                }
@@ -164,6 +165,7 @@ func flagalloc(f *Func) {
                for i, v := range b.ControlValues() {
                        if v != flag && v.Type.IsFlags() {
                                // Recalculate control value.
+                               remove = append(remove, v)
                                c := copyFlags(v, b)
                                b.ReplaceControl(i, c)
                                flag = v
@@ -172,12 +174,15 @@ func flagalloc(f *Func) {
                if v := end[b.ID]; v != nil && v != flag {
                        // Need to reissue flag generator for use by
                        // subsequent blocks.
+                       remove = append(remove, v)
                        copyFlags(v, b)
                        // Note: this flag generator is not properly linked up
                        // with the flag users. This breaks the SSA representation.
                        // We could fix up the users with another pass, but for now
-                       // we'll just leave it.  (Regalloc has the same issue for
+                       // we'll just leave it. (Regalloc has the same issue for
                        // standard regs, and it runs next.)
+                       // For this reason, take care not to add this flag
+                       // generator to the remove list.
                }
        }
 
@@ -185,6 +190,58 @@ func flagalloc(f *Func) {
        for _, b := range f.Blocks {
                b.FlagsLiveAtEnd = end[b.ID] != nil
        }
+
+       const go115flagallocdeadcode = true
+       if !go115flagallocdeadcode {
+               return
+       }
+
+       // Remove any now-dead values.
+       // The number of values to remove is likely small,
+       // and removing them requires processing all values in a block,
+       // so minimize the number of blocks that we touch.
+
+       // Shrink remove to contain only dead values, and clobber those dead values.
+       for i := 0; i < len(remove); i++ {
+               v := remove[i]
+               if v.Uses == 0 {
+                       v.reset(OpInvalid)
+                       continue
+               }
+               // Remove v.
+               last := len(remove) - 1
+               remove[i] = remove[last]
+               remove[last] = nil
+               remove = remove[:last]
+               i-- // reprocess value at i
+       }
+
+       if len(remove) == 0 {
+               return
+       }
+
+       removeBlocks := f.newSparseSet(f.NumBlocks())
+       defer f.retSparseSet(removeBlocks)
+       for _, v := range remove {
+               removeBlocks.add(v.Block.ID)
+       }
+
+       // Process affected blocks, preserving value order.
+       for _, b := range f.Blocks {
+               if !removeBlocks.contains(b.ID) {
+                       continue
+               }
+               i := 0
+               for j := 0; j < len(b.Values); j++ {
+                       v := b.Values[j]
+                       if v.Op == OpInvalid {
+                               continue
+                       }
+                       b.Values[i] = v
+                       i++
+               }
+               b.truncateValues(i)
+       }
 }
 
 func (v *Value) clobbersFlags() bool {