case ORETURN:
s.stmtList(n.List)
b := s.endBlock()
+ b.Kind = ssa.BlockRet
b.AddEdgeTo(s.exit)
case OCONTINUE, OBREAK:
branches = append(branches, branch{p, b.Succs[0]})
}
case ssa.BlockExit:
+ case ssa.BlockRet:
Prog(obj.ARET)
case ssa.BlockCall:
if b.Succs[0] != next {
if !b.Control.Type.IsMemory() {
f.Fatalf("exit block %s has non-memory control value %s", b, b.Control.LongString())
}
+ case BlockRet:
+ if len(b.Succs) != 1 {
+ f.Fatalf("ret block %s len(Succs)==%d, want 1", b, len(b.Succs))
+ }
+ if b.Control != nil {
+ f.Fatalf("ret block %s has non-nil control %s", b, b.Control.LongString())
+ }
+ if b.Succs[0].Kind != BlockExit {
+ f.Fatalf("ret block %s has successor %s, not Exit", b, b.Succs[0].Kind)
+ }
case BlockDead:
if len(b.Succs) != 0 {
f.Fatalf("dead block %s has successors", b)
// Regalloc wants a critical-edge-free CFG so it can implement phi values.
func critical(f *Func) {
for _, b := range f.Blocks {
- if len(b.Preds) <= 1 {
+ if len(b.Preds) <= 1 || b.Kind == BlockExit {
continue
}
{name: "If"}, // 2 successors, if control goto Succs[0] else goto Succs[1]
{name: "Call"}, // 2 successors, normal return and panic
{name: "First"}, // 2 successors, always takes the first one (second is dead)
+ {name: "Ret"}, // 1 successor, branches to exit
}
func init() {
BlockIf
BlockCall
BlockFirst
+ BlockRet
)
var blockString = [...]string{
BlockIf: "If",
BlockCall: "Call",
BlockFirst: "First",
+ BlockRet: "Ret",
}
func (k BlockKind) String() string { return blockString[k] }