Commit 50bc546d authored by Todd Neal's avatar Todd Neal

cmd/compile: reuse blocks in critical pass

If a phi has duplicate arguments, then the new block that is constructed
to remove the critical edge can be used for all of the duplicate
arguments.

read-only data = -904 bytes (-0.058308%)
global text (code) = -2240 bytes (-0.060056%)
Total difference -3144 bytes (-0.056218%)

Change-Id: Iee3762744d6a8c9d26cdfa880bb23feb62b03c9c
Reviewed-on: https://go-review.googlesource.com/20746
Run-TryBot: Todd Neal <todd@tneal.org>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent f2f2434d
...@@ -8,28 +8,85 @@ package ssa ...@@ -8,28 +8,85 @@ package ssa
// more than one outedge to a block with more than one inedge). // more than one outedge to a block with more than one inedge).
// Regalloc wants a critical-edge-free CFG so it can implement phi values. // Regalloc wants a critical-edge-free CFG so it can implement phi values.
func critical(f *Func) { func critical(f *Func) {
for _, b := range f.Blocks { // maps from phi arg ID to the new block created for that argument
blocks := make([]*Block, f.NumValues())
// need to iterate over f.Blocks without range, as we might
// need to split critical edges on newly constructed blocks
for j := 0; j < len(f.Blocks); j++ {
b := f.Blocks[j]
if len(b.Preds) <= 1 { if len(b.Preds) <= 1 {
continue continue
} }
var phi *Value
// determine if we've only got a single phi in this
// block, this is easier to handle than the general
// case of a block with multiple phi values.
for _, v := range b.Values {
if v.Op == OpPhi {
if phi != nil {
phi = nil
break
}
phi = v
}
}
// reset our block map
if phi != nil {
for _, v := range phi.Args {
blocks[v.ID] = nil
}
}
// split input edges coming from multi-output blocks. // split input edges coming from multi-output blocks.
for i, c := range b.Preds { for i := 0; i < len(b.Preds); i++ {
c := b.Preds[i]
if c.Kind == BlockPlain { if c.Kind == BlockPlain {
continue // only single output block continue // only single output block
} }
// allocate a new block to place on the edge var d *Block // new block used to remove critical edge
d := f.NewBlock(BlockPlain) reusedBlock := false // if true, then this is not the first use of this block
d.Line = c.Line if phi != nil {
if f.pass.debug > 0 { argID := phi.Args[i].ID
f.Config.Warnl(c.Line, "split critical edge") // find or record the block that we used to split
// critical edges for this argument
if d = blocks[argID]; d == nil {
d = f.NewBlock(BlockPlain)
d.Line = c.Line
blocks[argID] = d
if f.pass.debug > 0 {
f.Config.Warnl(c.Line, "split critical edge")
}
} else {
reusedBlock = true
}
} else {
// no existing block, so allocate a new block
// to place on the edge
d = f.NewBlock(BlockPlain)
d.Line = c.Line
if f.pass.debug > 0 {
f.Config.Warnl(c.Line, "split critical edge")
}
}
// if this not the first argument for the
// block, then we need to remove the
// corresponding elements from the block
// predecessors and phi args
if reusedBlock {
d.Preds = append(d.Preds, c)
b.Preds[i] = nil
phi.Args[i] = nil
} else {
// splice it in
d.Preds = append(d.Preds, c)
d.Succs = append(d.Succs, b)
b.Preds[i] = d
} }
// splice it in
d.Preds = append(d.Preds, c)
d.Succs = append(d.Succs, b)
b.Preds[i] = d
// replace b with d in c's successor list. // replace b with d in c's successor list.
for j, b2 := range c.Succs { for j, b2 := range c.Succs {
if b2 == b { if b2 == b {
...@@ -38,5 +95,33 @@ func critical(f *Func) { ...@@ -38,5 +95,33 @@ func critical(f *Func) {
} }
} }
} }
// clean up phi's args and b's predecessor list
if phi != nil {
phi.Args = filterNilValues(phi.Args)
b.Preds = filterNilBlocks(b.Preds)
}
}
}
// filterNilValues preserves the order of v, while filtering out nils.
func filterNilValues(v []*Value) []*Value {
nv := v[:0]
for i := range v {
if v[i] != nil {
nv = append(nv, v[i])
}
}
return nv
}
// filterNilBlocks preserves the order of b, while filtering out nils.
func filterNilBlocks(b []*Block) []*Block {
nb := b[:0]
for i := range b {
if b[i] != nil {
nb = append(nb, b[i])
}
} }
return nb
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment