From: Josh Bleecher Snyder Date: Mon, 30 Dec 2019 21:16:28 +0000 (-0800) Subject: cmd/compile: remove dead values after flagalloc X-Git-Tag: go1.15beta1~416 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=6303c34d7f16eab5824a586f1ac30ec8921e7602;p=gostls13.git cmd/compile: remove dead values after flagalloc 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 TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/ssa/flagalloc.go b/src/cmd/compile/internal/ssa/flagalloc.go index 7e7ce11482..d50b615912 100644 --- a/src/cmd/compile/internal/ssa/flagalloc.go +++ b/src/cmd/compile/internal/ssa/flagalloc.go @@ -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 {