Commit ab9e8d06 authored by Russ Cox's avatar Russ Cox

cmd/gc: correct liveness for func ending in panic

The registerization code needs the function to end in a RET,
even if that RET is actually unreachable.

The liveness code needs to avoid such unreachable RETs.
It had a special case for final RET after JMP, but no case
for final RET after UNDEF. Instead of expanding the special
cases, let fixjmp - which already knows what is and is not
reachable definitively - mark the unreachable RET so that
the liveness code can identify it.

TBR=iant
CC=golang-codereviews
https://golang.org/cl/63680043
parent 02ae91f3
...@@ -519,12 +519,10 @@ newcfg(Prog *firstp) ...@@ -519,12 +519,10 @@ newcfg(Prog *firstp)
break; break;
bb->last = p; bb->last = p;
// Pattern match an unconditional branch followed by a // Stop before an unreachable RET, to avoid creating
// dead return instruction. This avoids a creating
// unreachable control flow nodes. // unreachable control flow nodes.
if(p->link != nil && p->link->link == nil) if(p->link != nil && p->link->as == ARET && p->link->mode == -1)
if (p->as == AJMP && p->link->as == ARET && p->link->opt == nil) break;
break;
// Collect basic blocks with selectgo calls. // Collect basic blocks with selectgo calls.
if(isselectgocall(p)) if(isselectgocall(p))
......
...@@ -146,7 +146,13 @@ fixjmp(Prog *firstp) ...@@ -146,7 +146,13 @@ fixjmp(Prog *firstp)
if(p->opt == dead) { if(p->opt == dead) {
if(p->link == P && p->as == ARET && last && last->as != ARET) { if(p->link == P && p->as == ARET && last && last->as != ARET) {
// This is the final ARET, and the code so far doesn't have one. // This is the final ARET, and the code so far doesn't have one.
// Let it stay. // Let it stay. The register allocator assumes that all live code in
// the function can be traversed by starting at all the RET instructions
// and following predecessor links. If we remove the final RET,
// this assumption will not hold in the case of an infinite loop
// at the end of a function.
// Keep the RET but mark it dead for the liveness analysis.
p->mode = -1;
} else { } else {
if(debug['R'] && debug['v']) if(debug['R'] && debug['v'])
print("del %P\n", p); print("del %P\n", p);
......
...@@ -113,3 +113,11 @@ func f9() bool { ...@@ -113,3 +113,11 @@ func f9() bool {
x := i9 x := i9
return x != 99 return x != 99
} }
// liveness formerly confused by UNDEF followed by RET,
// leading to "live at entry to f10: ~r1" (unnamed result).
func f10() string {
panic(1)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment