mirror of
https://github.com/golang/go
synced 2024-09-15 22:20:06 +00:00
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: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
f2f2434d47
commit
50bc546d43
|
@ -8,28 +8,85 @@ package ssa
|
|||
// 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.
|
||||
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 {
|
||||
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.
|
||||
for i, c := range b.Preds {
|
||||
for i := 0; i < len(b.Preds); i++ {
|
||||
c := b.Preds[i]
|
||||
if c.Kind == BlockPlain {
|
||||
continue // only single output block
|
||||
}
|
||||
|
||||
// allocate a new block to place on the edge
|
||||
d := f.NewBlock(BlockPlain)
|
||||
var d *Block // new block used to remove critical edge
|
||||
reusedBlock := false // if true, then this is not the first use of this block
|
||||
if phi != nil {
|
||||
argID := phi.Args[i].ID
|
||||
// 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
|
||||
}
|
||||
|
||||
// replace b with d in c's successor list.
|
||||
for j, b2 := range c.Succs {
|
||||
if b2 == b {
|
||||
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue