diff options
author | Keith Randall <khr@golang.org> | 2016-01-05 14:56:26 -0800 |
---|---|---|
committer | Keith Randall <khr@golang.org> | 2016-01-13 18:42:00 +0000 |
commit | 3425295e915bc16236f2c021317705aca34319af (patch) | |
tree | 3d9adc97103ae2c92c95f777ca1339d0797a6bdd /src/cmd/compile/internal/ssa/deadcode.go | |
parent | 9094e3ada2de3cc8129b70730c2c0782a4040201 (diff) | |
download | go-3425295e915bc16236f2c021317705aca34319af.tar.gz go-3425295e915bc16236f2c021317705aca34319af.zip |
[dev.ssa] cmd/compile: clean up comparisons
Add new constant-flags opcodes. These can be generated from
comparisons that we know the result of, like x&31 < 32.
Constant-fold the constant-flags opcodes into all flag users.
Reorder some CMPxconst args so they read in the comparison direction.
Reorg deadcode removal a bit - it needs to remove the OpCopy ops it
generates when strength-reducing Phi ops. So it needs to splice out all
the dead blocks and do a copy elimination before it computes live
values.
Change-Id: Ie922602033592ad8212efe4345394973d3b94d9f
Reviewed-on: https://go-review.googlesource.com/18267
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Diffstat (limited to 'src/cmd/compile/internal/ssa/deadcode.go')
-rw-r--r-- | src/cmd/compile/internal/ssa/deadcode.go | 144 |
1 files changed, 78 insertions, 66 deletions
diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index e9d6525701..429708213f 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -6,22 +6,14 @@ package ssa // findlive returns the reachable blocks and live values in f. func findlive(f *Func) (reachable []bool, live []bool) { - // After regalloc, consider all blocks and values to be reachable and live. - // See the comment at the top of regalloc.go and in deadcode for details. - if f.RegAlloc != nil { - reachable = make([]bool, f.NumBlocks()) - for i := range reachable { - reachable[i] = true - } - live = make([]bool, f.NumValues()) - for i := range live { - live[i] = true - } - return reachable, live - } + reachable = reachableBlocks(f) + live = liveValues(f, reachable) + return +} - // Find all reachable basic blocks. - reachable = make([]bool, f.NumBlocks()) +// reachableBlocks returns the reachable blocks in f. +func reachableBlocks(f *Func) []bool { + reachable := make([]bool, f.NumBlocks()) reachable[f.Entry.ID] = true p := []*Block{f.Entry} // stack-like worklist for len(p) > 0 { @@ -40,10 +32,25 @@ func findlive(f *Func) (reachable []bool, live []bool) { } } } + return reachable +} + +// liveValues returns the live values in f. +// reachable is a map from block ID to whether the block is reachable. +func liveValues(f *Func, reachable []bool) []bool { + live := make([]bool, f.NumValues()) + + // After regalloc, consider all values to be live. + // See the comment at the top of regalloc.go and in deadcode for details. + if f.RegAlloc != nil { + for i := range live { + live[i] = true + } + return live + } // Find all live values - live = make([]bool, f.NumValues()) // flag to set for each live value - var q []*Value // stack-like worklist of unscanned values + var q []*Value // stack-like worklist of unscanned values // Starting set: all control values of reachable blocks are live. for _, b := range f.Blocks { @@ -72,7 +79,7 @@ func findlive(f *Func) (reachable []bool, live []bool) { } } - return reachable, live + return live } // deadcode removes dead code from f. @@ -85,27 +92,8 @@ func deadcode(f *Func) { f.Fatalf("deadcode after regalloc") } - reachable, live := findlive(f) - - // Remove dead values from blocks' value list. Return dead - // value ids to the allocator. - for _, b := range f.Blocks { - i := 0 - for _, v := range b.Values { - if live[v.ID] { - b.Values[i] = v - i++ - } else { - f.vid.put(v.ID) - } - } - // aid GC - tail := b.Values[i:] - for j := range tail { - tail[j] = nil - } - b.Values = b.Values[:i] - } + // Find reachable blocks. + reachable := reachableBlocks(f) // Get rid of edges from dead to live code. for _, b := range f.Blocks { @@ -131,6 +119,7 @@ func deadcode(f *Func) { b.Succs[1] = nil b.Succs = b.Succs[:1] b.Kind = BlockPlain + b.Likely = BranchUnknown if reachable[c.ID] { // Note: c must be reachable through some other edge. @@ -138,41 +127,20 @@ func deadcode(f *Func) { } } - // Remove unreachable blocks. Return dead block ids to allocator. - i := 0 - for _, b := range f.Blocks { - if reachable[b.ID] { - f.Blocks[i] = b - i++ - } else { - if len(b.Values) > 0 { - b.Fatalf("live values in unreachable block %v: %v", b, b.Values) - } - b.Preds = nil - b.Succs = nil - b.Control = nil - b.Kind = BlockDead - f.bid.put(b.ID) - } - } - // zero remainder to help GC - tail := f.Blocks[i:] - for j := range tail { - tail[j] = nil - } - f.Blocks = f.Blocks[:i] + // Splice out any copies introduced during dead block removal. + copyelim(f) + + // Find live values. + live := liveValues(f, reachable) // Remove dead & duplicate entries from namedValues map. s := newSparseSet(f.NumValues()) - i = 0 + i := 0 for _, name := range f.Names { j := 0 s.clear() values := f.NamedValues[name] for _, v := range values { - for v.Op == OpCopy { - v = v.Args[0] - } if live[v.ID] && !s.contains(v.ID) { values[j] = v j++ @@ -195,6 +163,50 @@ func deadcode(f *Func) { } f.Names = f.Names[:i] + // Remove dead values from blocks' value list. Return dead + // value ids to the allocator. + for _, b := range f.Blocks { + i := 0 + for _, v := range b.Values { + if live[v.ID] { + b.Values[i] = v + i++ + } else { + f.vid.put(v.ID) + } + } + // aid GC + tail := b.Values[i:] + for j := range tail { + tail[j] = nil + } + b.Values = b.Values[:i] + } + + // Remove unreachable blocks. Return dead block ids to allocator. + i = 0 + for _, b := range f.Blocks { + if reachable[b.ID] { + f.Blocks[i] = b + i++ + } else { + if len(b.Values) > 0 { + b.Fatalf("live values in unreachable block %v: %v", b, b.Values) + } + b.Preds = nil + b.Succs = nil + b.Control = nil + b.Kind = BlockDead + f.bid.put(b.ID) + } + } + // zero remainder to help GC + tail := f.Blocks[i:] + for j := range tail { + tail[j] = nil + } + f.Blocks = f.Blocks[:i] + // TODO: renumber Blocks and Values densely? // TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it? } |