[dev.ssa] cmd/compile/internal/ssa: fix defer in functions with no return

The after-defer test jumps to a deferreturn site.  Some functions
(those with infinite loops) have no deferreturn site.  Add one
so we have one to jump to.

Change-Id: I505e7f3f888f5e7d03ca49a3477b41cf1f78eb8a
Reviewed-on: https://go-review.googlesource.com/14349
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 098a1e1..70990bb 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -2621,6 +2621,12 @@
 	for _, br := range s.branches {
 		br.p.To.Val = s.bstart[br.b.ID]
 	}
+	if s.deferBranches != nil && s.deferTarget == nil {
+		// This can happen when the function has a defer but
+		// no return (because it has an infinite loop).
+		s.deferReturn()
+		Prog(obj.ARET)
+	}
 	for _, p := range s.deferBranches {
 		p.To.Val = s.deferTarget
 	}
@@ -3463,20 +3469,7 @@
 	case ssa.BlockExit:
 	case ssa.BlockRet:
 		if Hasdefer != 0 {
-			// Deferred calls will appear to be returning to
-			// the CALL deferreturn(SB) that we are about to emit.
-			// However, the stack trace code will show the line
-			// of the instruction byte before the return PC.
-			// To avoid that being an unrelated instruction,
-			// insert an actual hardware NOP that will have the right line number.
-			// This is different from obj.ANOP, which is a virtual no-op
-			// that doesn't make it into the instruction stream.
-			s.deferTarget = Pc
-			Thearch.Ginsnop()
-			p := Prog(obj.ACALL)
-			p.To.Type = obj.TYPE_MEM
-			p.To.Name = obj.NAME_EXTERN
-			p.To.Sym = Linksym(Deferreturn.Sym)
+			s.deferReturn()
 		}
 		Prog(obj.ARET)
 	case ssa.BlockCall:
@@ -3537,6 +3530,23 @@
 	}
 }
 
+func (s *genState) deferReturn() {
+	// Deferred calls will appear to be returning to
+	// the CALL deferreturn(SB) that we are about to emit.
+	// However, the stack trace code will show the line
+	// of the instruction byte before the return PC.
+	// To avoid that being an unrelated instruction,
+	// insert an actual hardware NOP that will have the right line number.
+	// This is different from obj.ANOP, which is a virtual no-op
+	// that doesn't make it into the instruction stream.
+	s.deferTarget = Pc
+	Thearch.Ginsnop()
+	p := Prog(obj.ACALL)
+	p.To.Type = obj.TYPE_MEM
+	p.To.Name = obj.NAME_EXTERN
+	p.To.Sym = Linksym(Deferreturn.Sym)
+}
+
 // addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
 func addAux(a *obj.Addr, v *ssa.Value) {
 	if a.Type != obj.TYPE_MEM {