aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssa/deadcode.go
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2016-01-05 14:56:26 -0800
committerKeith Randall <khr@golang.org>2016-01-13 18:42:00 +0000
commit3425295e915bc16236f2c021317705aca34319af (patch)
tree3d9adc97103ae2c92c95f777ca1339d0797a6bdd /src/cmd/compile/internal/ssa/deadcode.go
parent9094e3ada2de3cc8129b70730c2c0782a4040201 (diff)
downloadgo-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.go144
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?
}