golang critical 代码
文件路径:/src/cmd/compile/internal/ssa/critical.go
/ Copyright 2015 The Go Authors. All rights reserved.
/ Use of this source code is governed by a BSD-style
/ license that can be found in the LICENSE file.
package ssa
/ critical splits critical edges (those that go from a block with
/ 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) {
/ 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 := 0; i < len(b.Preds); {
e := b.Preds[i]
p := e.b
pi := e.i
if p.Kind == BlockPlain {
i++
continue / only single output block
}
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 {
/ splitting doesn't necessarily remove the critical edge,
/ since we're iterating over len(f.Blocks) above, this forces
/ the new blocks to be re-examined.
d = f.NewBlock(BlockPlain)
d.Pos = p.Pos
blocks[argID] = d
if f.pass.debug > 0 {
f.Warnl(p.Pos, "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.Pos = p.Pos
if f.pass.debug > 0 {
f.Warnl(p.Pos, "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 {
/ Add p->d edge
p.Succs[pi] = Edge{d, len(d.Preds)}
d.Preds = append(d.Preds, Edge{p, pi})
/ Remove p as a predecessor from b.
b.removePred(i)
/ Update corresponding phi args
b.removePhiArg(phi, i)
/ splitting occasionally leads to a phi having
/ a single argument (occurs with -N)
/ TODO(cuonglm,khr): replace this with phielimValue, and
/ make removePhiArg incorporates that.
if len(b.Preds) == 1 {
phi.Op = OpCopy
}
/ Don't increment i in this case because we moved
/ an unprocessed predecessor down into slot i.
} else {
/ splice it in
p.Succs[pi] = Edge{d, 0}
b.Preds[i] = Edge{d, 0}
d.Preds = append(d.Preds, Edge{p, pi})
d.Succs = append(d.Succs, Edge{b, i})
i++
}
}
}
}