[dev.ssa] initial implementation of PAUTO|PHEAP variables

Call to the runtime to generate escaping variables and use the returned
address when accessing these variables.

Fix a couple of errors on the way. The rule for CALLstatic was missed
during the Aux refactor and OCONVNOP wasn't converted.

Change-Id: I2096beff92cca92d648bfb6e8ec0b120f02f44af
Reviewed-on: https://go-review.googlesource.com/11072
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index dec4de0..1d7cb28 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -226,8 +226,23 @@
 		s.stmtList(n.List)
 
 	case ODCL:
-		// TODO: old gen pass uses dcl node as the point where
-		// escaping variables' new functions are called. Do that here
+		if n.Left.Class&PHEAP == 0 {
+			return
+		}
+		if compiling_runtime != 0 {
+			log.Fatalf("%v escapes to heap, not allowed in runtime.", n)
+		}
+
+		// TODO: the old pass hides the details of PHEAP
+		// variables behind ONAME nodes. Figure out if it's better
+		// to rewrite the tree and make the heapaddr construct explicit
+		// or to keep this detail hidden behind the scenes.
+		palloc := prealloc[n.Left]
+		if palloc == nil {
+			palloc = callnew(n.Left.Type)
+			prealloc[n.Left] = palloc
+		}
+		s.assign(OAS, n.Left.Name.Heapaddr, palloc)
 
 	case OLABEL, OGOTO:
 		// get block at label, or make one
@@ -247,32 +262,8 @@
 		}
 
 	case OAS, OASWB:
-		// TODO: do write barrier
-		var val *ssa.Value
-		if n.Right == nil {
-			// n.Right == nil means use the zero value of the assigned type.
-			t := n.Left.Type
-			switch {
-			case t.IsString():
-				val = s.entryNewValue0(ssa.OpConst, n.Left.Type)
-			case t.IsInteger():
-				val = s.entryNewValue0(ssa.OpConst, n.Left.Type)
-			case t.IsBoolean():
-				val = s.entryNewValue0A(ssa.OpConst, n.Left.Type, false) // TODO: store bools as 0/1 in AuxInt?
-			default:
-				log.Fatalf("zero for type %v not implemented", t)
-			}
-		} else {
-			val = s.expr(n.Right)
-		}
-		if n.Left.Op == ONAME && canSSA(n.Left) {
-			// Update variable assignment.
-			s.vars[n.Left.Sym.Name] = val
-			return
-		}
-		// not ssa-able.  Treat as a store.
-		addr := s.addr(n.Left)
-		s.vars[".mem"] = s.newValue3(ssa.OpStore, ssa.TypeMem, addr, val, s.mem())
+		s.assign(n.Op, n.Left, n.Right)
+
 	case OIF:
 		cond := s.expr(n.Left)
 		b := s.endBlock()
@@ -478,6 +469,36 @@
 	}
 }
 
+func (s *state) assign(op uint8, left *Node, right *Node) {
+	// TODO: do write barrier
+	// if op == OASWB
+	var val *ssa.Value
+	if right == nil {
+		// right == nil means use the zero value of the assigned type.
+		t := left.Type
+		switch {
+		case t.IsString():
+			val = s.entryNewValue0(ssa.OpConst, left.Type)
+		case t.IsInteger():
+			val = s.entryNewValue0(ssa.OpConst, left.Type)
+		case t.IsBoolean():
+			val = s.entryNewValue0A(ssa.OpConst, left.Type, false) // TODO: store bools as 0/1 in AuxInt?
+		default:
+			log.Fatalf("zero for type %v not implemented", t)
+		}
+	} else {
+		val = s.expr(right)
+	}
+	if left.Op == ONAME && canSSA(left) {
+		// Update variable assignment.
+		s.vars[left.Sym.Name] = val
+		return
+	}
+	// not ssa-able.  Treat as a store.
+	addr := s.addr(left)
+	s.vars[".mem"] = s.newValue3(ssa.OpStore, ssa.TypeMem, addr, val, s.mem())
+}
+
 // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
 func (s *state) addr(n *Node) *ssa.Value {
 	switch n.Op {
@@ -489,6 +510,8 @@
 		case PPARAMOUT:
 			// store to parameter slot
 			return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.fp)
+		case PAUTO | PHEAP:
+			return s.expr(n.Name.Heapaddr)
 		default:
 			// TODO: address of locals
 			log.Fatalf("variable address of %v not implemented", n)
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index 58ab25b..b62c876 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -58,7 +58,7 @@
 (If (SETB cmp) yes no) -> (ULT cmp yes no)
 (If cond yes no) && cond.Op == OpAMD64MOVBload -> (NE (TESTB <TypeFlags> cond cond) yes no)
 
-(StaticCall [target] mem) -> (CALLstatic [target] mem)
+(StaticCall {target} mem) -> (CALLstatic {target} mem)
 (ClosureCall entry closure mem) -> (CALLclosure entry closure mem)
 
 // Rules below here apply some simple optimizations after lowering.
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index d466e15..a3ec3e7 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -1093,22 +1093,22 @@
 	end78e66b6fc298684ff4ac8aec5ce873c9:
 		;
 	case OpStaticCall:
-		// match: (StaticCall [target] mem)
+		// match: (StaticCall {target} mem)
 		// cond:
-		// result: (CALLstatic [target] mem)
+		// result: (CALLstatic {target} mem)
 		{
-			target := v.AuxInt
+			target := v.Aux
 			mem := v.Args[0]
 			v.Op = OpAMD64CALLstatic
 			v.AuxInt = 0
 			v.Aux = nil
 			v.resetArgs()
-			v.AuxInt = target
+			v.Aux = target
 			v.AddArg(mem)
 			return true
 		}
-		goto endcf02eb60d90086f6c42bfdc5842b145d
-	endcf02eb60d90086f6c42bfdc5842b145d:
+		goto end1948857a7cfc2a4f905045e58d3b9ec1
+	end1948857a7cfc2a4f905045e58d3b9ec1:
 		;
 	case OpStore:
 		// match: (Store ptr val mem)