b.Kind = ssa.BlockRet
b.Control = m
b.AddEdgeTo(s.exit)
+ case ORETJMP:
+ s.stmtList(n.List)
+ m := s.mem()
+ b := s.endBlock()
+ b.Kind = ssa.BlockRetJmp
+ b.Aux = n.Left.Sym
+ b.Control = m
+ b.AddEdgeTo(s.exit)
case OCONTINUE, OBREAK:
var op string
case PEXTERN, PPARAMOUT, PPARAMREF:
return false
}
+ if n.Class == PPARAM && n.String() == ".this" {
+ // wrappers generated by genwrapper need to update
+ // the .this pointer in place.
+ return false
+ }
return canSSAType(n.Type)
// TODO: try to make more variables SSAable?
}
s.deferReturn()
}
Prog(obj.ARET)
+ case ssa.BlockRetJmp:
+ p := Prog(obj.AJMP)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = Linksym(b.Aux.(*Sym))
case ssa.BlockCall:
if b.Succs[0] != next {
p := Prog(obj.AJMP)
// has a memory control value.
Control *Value
+ // Auxiliary info for the block. Its value depends on the Kind.
+ Aux interface{}
+
// The unordered set of Values that define the operation of this block.
// The list must include the control value, if any. (TODO: need this last condition?)
// After the scheduling pass, this list is ordered.
// long form print
func (b *Block) LongString() string {
s := b.Kind.String()
+ if b.Aux != nil {
+ s += fmt.Sprintf(" %s", b.Aux)
+ }
if b.Control != nil {
s += fmt.Sprintf(" %s", b.Control)
}
if b.Succs[0].Kind != BlockExit {
f.Fatalf("ret block %s has successor %s, not Exit", b, b.Succs[0].Kind)
}
+ case BlockRetJmp:
+ if len(b.Succs) != 1 {
+ f.Fatalf("retjmp block %s len(Succs)==%d, want 1", b, len(b.Succs))
+ }
+ if b.Control == nil {
+ f.Fatalf("retjmp block %s has nil control %s", b)
+ }
+ if !b.Control.Type.IsMemory() {
+ f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Control.LongString())
+ }
+ if b.Succs[0].Kind != BlockExit {
+ f.Fatalf("retjmp block %s has successor %s, not Exit", b, b.Succs[0].Kind)
+ }
+ if b.Aux == nil {
+ f.Fatalf("retjmp block %s has nil Aux field", b)
+ }
case BlockDead:
if len(b.Succs) != 0 {
f.Fatalf("dead block %s has successors", b)
// First nil [always,never]
var genericBlocks = []blockData{
- {name: "Exit"}, // no successors. There should only be 1 of these.
- {name: "Dead"}, // no successors; determined to be dead but not yet removed
- {name: "Plain"}, // a single successor
- {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
+ {name: "Exit"}, // no successors. There should only be 1 of these.
+ {name: "Dead"}, // no successors; determined to be dead but not yet removed
+ {name: "Plain"}, // a single successor
+ {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
+ {name: "RetJmp"}, // 1 successor, branches to exit. Jumps to b.Aux.(*gc.Sym)
}
func init() {
func (b *Block) LongHTML() string {
// TODO: improve this for HTML?
s := fmt.Sprintf("<span class=\"%s ssa-block\">%s</span>", html.EscapeString(b.String()), html.EscapeString(b.Kind.String()))
+ if b.Aux != nil {
+ s += html.EscapeString(fmt.Sprintf(" {%v}", b.Aux))
+ }
if b.Control != nil {
s += fmt.Sprintf(" %s", b.Control.HTML())
}
BlockCall
BlockFirst
BlockRet
+ BlockRetJmp
)
var blockString = [...]string{
BlockAMD64ORD: "ORD",
BlockAMD64NAN: "NAN",
- BlockExit: "Exit",
- BlockDead: "Dead",
- BlockPlain: "Plain",
- BlockIf: "If",
- BlockCall: "Call",
- BlockFirst: "First",
- BlockRet: "Ret",
+ BlockExit: "Exit",
+ BlockDead: "Dead",
+ BlockPlain: "Plain",
+ BlockIf: "If",
+ BlockCall: "Call",
+ BlockFirst: "First",
+ BlockRet: "Ret",
+ BlockRetJmp: "RetJmp",
}
func (k BlockKind) String() string { return blockString[k] }