mirror of
https://github.com/golang/go.git
synced 2025-05-18 13:54:40 +00:00
[dev.ssa] cmd/compile/internal/ssa: distinguish exit and return blocks
It is confusing to have exceptional edges jump back into real code. Distinguish return blocks, which execute acutal code, and the exit block, which is a merge point for the regular and exceptional return flow. Prevent critical edge insertion from adding blocks on edges into the exit block. These added blocks serve no purpose and add a bunch of dead jumps to the assembly output. Furthermore, live variable analysis is confused by these jumps. Change-Id: Ifd69e6c00e90338ed147e7cb351b5100dc0364df Reviewed-on: https://go-review.googlesource.com/14254 Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
73024083b0
commit
10f38f51ef
@ -562,6 +562,7 @@ func (s *state) stmt(n *Node) {
|
|||||||
case ORETURN:
|
case ORETURN:
|
||||||
s.stmtList(n.List)
|
s.stmtList(n.List)
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
|
b.Kind = ssa.BlockRet
|
||||||
b.AddEdgeTo(s.exit)
|
b.AddEdgeTo(s.exit)
|
||||||
|
|
||||||
case OCONTINUE, OBREAK:
|
case OCONTINUE, OBREAK:
|
||||||
@ -3358,6 +3359,7 @@ func genBlock(b, next *ssa.Block, branches []branch) []branch {
|
|||||||
branches = append(branches, branch{p, b.Succs[0]})
|
branches = append(branches, branch{p, b.Succs[0]})
|
||||||
}
|
}
|
||||||
case ssa.BlockExit:
|
case ssa.BlockExit:
|
||||||
|
case ssa.BlockRet:
|
||||||
Prog(obj.ARET)
|
Prog(obj.ARET)
|
||||||
case ssa.BlockCall:
|
case ssa.BlockCall:
|
||||||
if b.Succs[0] != next {
|
if b.Succs[0] != next {
|
||||||
|
@ -59,6 +59,16 @@ func checkFunc(f *Func) {
|
|||||||
if !b.Control.Type.IsMemory() {
|
if !b.Control.Type.IsMemory() {
|
||||||
f.Fatalf("exit block %s has non-memory control value %s", b, b.Control.LongString())
|
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:
|
case BlockDead:
|
||||||
if len(b.Succs) != 0 {
|
if len(b.Succs) != 0 {
|
||||||
f.Fatalf("dead block %s has successors", b)
|
f.Fatalf("dead block %s has successors", b)
|
||||||
|
@ -9,7 +9,7 @@ package ssa
|
|||||||
// Regalloc wants a critical-edge-free CFG so it can implement phi values.
|
// Regalloc wants a critical-edge-free CFG so it can implement phi values.
|
||||||
func critical(f *Func) {
|
func critical(f *Func) {
|
||||||
for _, b := range f.Blocks {
|
for _, b := range f.Blocks {
|
||||||
if len(b.Preds) <= 1 {
|
if len(b.Preds) <= 1 || b.Kind == BlockExit {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,6 +375,7 @@ var genericBlocks = []blockData{
|
|||||||
{name: "If"}, // 2 successors, if control goto Succs[0] else goto Succs[1]
|
{name: "If"}, // 2 successors, if control goto Succs[0] else goto Succs[1]
|
||||||
{name: "Call"}, // 2 successors, normal return and panic
|
{name: "Call"}, // 2 successors, normal return and panic
|
||||||
{name: "First"}, // 2 successors, always takes the first one (second is dead)
|
{name: "First"}, // 2 successors, always takes the first one (second is dead)
|
||||||
|
{name: "Ret"}, // 1 successor, branches to exit
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -28,6 +28,7 @@ const (
|
|||||||
BlockIf
|
BlockIf
|
||||||
BlockCall
|
BlockCall
|
||||||
BlockFirst
|
BlockFirst
|
||||||
|
BlockRet
|
||||||
)
|
)
|
||||||
|
|
||||||
var blockString = [...]string{
|
var blockString = [...]string{
|
||||||
@ -54,6 +55,7 @@ var blockString = [...]string{
|
|||||||
BlockIf: "If",
|
BlockIf: "If",
|
||||||
BlockCall: "Call",
|
BlockCall: "Call",
|
||||||
BlockFirst: "First",
|
BlockFirst: "First",
|
||||||
|
BlockRet: "Ret",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k BlockKind) String() string { return blockString[k] }
|
func (k BlockKind) String() string { return blockString[k] }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user