bb := newblock(firstp)
cfg = append(cfg, bb)
- for p := firstp; p != nil; p = p.Link {
+ for p := firstp; p != nil && p.As != obj.AEND; p = p.Link {
Thearch.Proginfo(p)
if p.To.Type == obj.TYPE_BRANCH {
if p.To.Val == nil {
// contained instructions until a label is reached. Add edges
// for branches and fall-through instructions.
for _, bb := range cfg {
- for p := bb.last; p != nil; p = p.Link {
+ for p := bb.last; p != nil && p.As != obj.AEND; p = p.Link {
if p.Opt != nil && p != bb.last {
break
}
// Stop before an unreachable RET, to avoid creating
// unreachable control flow nodes.
if p.Link != nil && p.Link.As == obj.ARET && p.Link.Mode == 1 {
+ // TODO: remove after SSA is done. SSA does not
+ // generate any unreachable RET instructions.
break
}
s.stmtList(fn.Nbody)
// fallthrough to exit
- if b := s.endBlock(); b != nil {
+ if s.curBlock != nil {
+ m := s.mem()
+ b := s.endBlock()
b.Kind = ssa.BlockRet
+ b.Control = m
b.AddEdgeTo(s.exit)
}
case ORETURN:
s.stmtList(n.List)
+ m := s.mem()
b := s.endBlock()
b.Kind = ssa.BlockRet
+ b.Control = m
b.AddEdgeTo(s.exit)
case OCONTINUE, OBREAK:
p.To.Val = s.deferTarget
}
- Pc.As = obj.ARET // overwrite AEND
-
if logProgs {
for p := ptxt; p != nil; p = p.Link {
var s string
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.Control == nil {
+ f.Fatalf("ret block %s has nil control %s", b)
+ }
+ if !b.Control.Type.IsMemory() {
+ f.Fatalf("ret block %s has non-memory control value %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)
// kind control successors
// ------------------------------------------
// Exit return mem []
+// Ret return mem [exit]
// Plain nil [next]
// If a boolean Value [then, else]
-// Call mem [nopanic, panic] (control opcode should be OpCall or OpStaticCall)
+// Call mem [nopanic, exit] (control opcode should be OpCall or OpStaticCall)
+// First nil [always,never]
var genericBlocks = []blockData{
{name: "Exit"}, // no successors. There should only be 1 of these.