]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: correct liveness for func ending in panic
authorRuss Cox <rsc@golang.org>
Fri, 14 Feb 2014 04:56:53 +0000 (23:56 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 14 Feb 2014 04:56:53 +0000 (23:56 -0500)
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

src/cmd/gc/plive.c
src/cmd/gc/popt.c
test/live.go

index 20aeb51557b32b3e7fd9a5a58a4c4ce997fa308e..d353672985e48d0c5c4796fab86dab317f2bf1b2 100644 (file)
@@ -519,12 +519,10 @@ newcfg(Prog *firstp)
                                break;
                        bb->last = p;
 
-                       // Pattern match an unconditional branch followed by a
-                       // dead return instruction.  This avoids a creating
+                       // Stop before an unreachable RET, to avoid creating
                        // unreachable control flow nodes.
-                       if(p->link != nil && p->link->link == nil)
-                               if (p->as == AJMP && p->link->as == ARET && p->link->opt == nil)
-                                       break;
+                       if(p->link != nil && p->link->as == ARET && p->link->mode == -1)
+                               break;
 
                        // Collect basic blocks with selectgo calls.
                        if(isselectgocall(p))
index cfb2791acf237cd9ad49844fd31c1627767ea7e8..7fcf5db10d57b1d7813f9b11ba147dddbfe664fa 100644 (file)
@@ -146,7 +146,13 @@ fixjmp(Prog *firstp)
                if(p->opt == dead) {
                        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.
-                               // 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 {
                                if(debug['R'] && debug['v'])
                                        print("del %P\n", p);
index ec2df7e5f8f1994a7fef0c75da26180dd24a3915..032d39812d8e79c9ae069373a3916b6100cacde7 100644 (file)
@@ -113,3 +113,11 @@ func f9() bool {
        x := i9
        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)
+}
+