[dev.ssa] cmd/compile: fixed heap-escaped-paramout

Changed tree generation to correctly use PARAMOUT instead
of PARAM.

Emit Func.Exit before any returns.

Change-Id: I2fa53cc7fad05fb4eea21081ba33d1f66db4ed49
Reviewed-on: https://go-review.googlesource.com/15610
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: David Chase <drchase@google.com>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 69a9b86..629774c 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -30,6 +30,7 @@
 		fmt.Println("generating SSA for", name)
 		dumplist("buildssa-enter", fn.Func.Enter)
 		dumplist("buildssa-body", fn.Nbody)
+		dumplist("buildssa-exit", fn.Func.Exit)
 	}
 
 	var s state
@@ -43,6 +44,7 @@
 	s.config = ssa.NewConfig(Thearch.Thestring, &e)
 	s.f = s.config.NewFunc()
 	s.f.Name = name
+	s.exitCode = fn.Func.Exit
 
 	if name == os.Getenv("GOSSAFUNC") {
 		// TODO: tempfile? it is handy to have the location
@@ -97,8 +99,8 @@
 			// TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
 			aux := &ssa.AutoSymbol{Typ: n.Type, Node: n}
 			s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
-		case PPARAM | PHEAP: // PPARAMOUT | PHEAP seems to not occur
-			// This ends up wrong, have to do it at the PARAM node instead.
+		case PPARAM | PHEAP, PPARAMOUT | PHEAP:
+		// This ends up wrong, have to do it at the PARAM node instead.
 		case PAUTO, PPARAMOUT:
 			// processed at each use, to prevent Addr coming
 			// before the decl.
@@ -122,6 +124,7 @@
 
 	// fallthrough to exit
 	if s.curBlock != nil {
+		s.stmtList(s.exitCode)
 		m := s.mem()
 		b := s.endBlock()
 		b.Kind = ssa.BlockRet
@@ -156,6 +159,9 @@
 	// Link up variable uses to variable definitions
 	s.linkForwardReferences()
 
+	// Don't carry reference this around longer than necessary
+	s.exitCode = nil
+
 	// Main call to ssa package to compile function
 	ssa.Compile(s.f)
 
@@ -207,6 +213,9 @@
 
 	// gotos that jump forward; required for deferred checkgoto calls
 	fwdGotos []*Node
+	// Code that must precede any return
+	// (e.g., copying value of heap-escaped paramout back to true paramout)
+	exitCode *NodeList
 
 	// unlabeled break and continue statement tracking
 	breakTo    *ssa.Block // current target for plain break statement
@@ -641,12 +650,14 @@
 
 	case ORETURN:
 		s.stmtList(n.List)
+		s.stmtList(s.exitCode)
 		m := s.mem()
 		b := s.endBlock()
 		b.Kind = ssa.BlockRet
 		b.Control = m
 	case ORETJMP:
 		s.stmtList(n.List)
+		s.stmtList(s.exitCode)
 		m := s.mem()
 		b := s.endBlock()
 		b.Kind = ssa.BlockRetJmp