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:
|
||||
s.stmtList(n.List)
|
||||
b := s.endBlock()
|
||||
b.Kind = ssa.BlockRet
|
||||
b.AddEdgeTo(s.exit)
|
||||
|
||||
case OCONTINUE, OBREAK:
|
||||
@ -3358,6 +3359,7 @@ func genBlock(b, next *ssa.Block, branches []branch) []branch {
|
||||
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 {
|
||||
|
@ -59,6 +59,16 @@ func checkFunc(f *Func) {
|
||||
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)
|
||||
|
@ -9,7 +9,7 @@ package ssa
|
||||
// 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
|
||||
}
|
||||
|
||||
|
@ -375,6 +375,7 @@ var genericBlocks = []blockData{
|
||||
{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() {
|
||||
|
@ -28,6 +28,7 @@ const (
|
||||
BlockIf
|
||||
BlockCall
|
||||
BlockFirst
|
||||
BlockRet
|
||||
)
|
||||
|
||||
var blockString = [...]string{
|
||||
@ -54,6 +55,7 @@ var blockString = [...]string{
|
||||
BlockIf: "If",
|
||||
BlockCall: "Call",
|
||||
BlockFirst: "First",
|
||||
BlockRet: "Ret",
|
||||
}
|
||||
|
||||
func (k BlockKind) String() string { return blockString[k] }
|
||||
|
Loading…
x
Reference in New Issue
Block a user