[dev.ssa] cmd/compile: be safer about uintptr/unsafe.Pointer conversions

Make sure that when a pointer value is live across a function
call, we save it as a pointer.  (And similarly a uintptr
live across a function call should not be saved as a pointer.)

Add a nasty test case.

This is probably what is preventing the merge from master
to dev.ssa.  Signs point to something like this bug happening
in mallocgc.

Change-Id: Ib23fa1251b8d1c50d82c6a448cb4a4fc28219029
Reviewed-on: https://go-review.googlesource.com/16830
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index 4364022..7d0aa4b 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -281,7 +281,7 @@
 (Store [1] ptr val mem) -> (MOVBstore ptr val mem)
 
 // We want this to stick out so the to/from ptr conversion is obvious
-(Convert <t> x) -> (LEAQ <t> x)
+(Convert <t> x mem) -> (MOVQconvert <t> x mem)
 
 // checks
 (IsNonNil p) -> (SETNE (TESTQ p p))
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
index fa5072f..ba53e81 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -465,6 +465,13 @@
 		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("DX")}}},
 		//arg0=ptr,arg1=mem, returns void.  Faults if ptr is nil.
 		{name: "LoweredNilCheck", reg: regInfo{inputs: []regMask{gpsp}, clobbers: flags}},
+
+		// MOVQconvert converts between pointers and integers.
+		// We have a special op for this so as to not confuse GC
+		// (particularly stack maps).  It takes a memory arg so it
+		// gets correctly ordered with respect to GC safepoints.
+		// arg0=ptr/int arg1=mem, output=int/ptr
+		{name: "MOVQconvert", reg: gp11nf, asm: "MOVQ"},
 	}
 
 	var AMD64blocks = []blockData{
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index d3de24d..5de877d 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -274,7 +274,8 @@
 (If (ConstBool [c]) yes no) && c == 0 -> (First nil no yes)
 
 // Get rid of Convert ops for pointer arithmetic on unsafe.Pointer.
-(Convert (Add64 (Convert ptr) off)) -> (Add64 ptr off)
+(Convert (Add64 (Convert ptr mem) off) mem) -> (Add64 ptr off)
+(Convert (Convert ptr mem) mem) -> ptr
 
 // Decompose compound argument values
 (Arg {n} [off]) && v.Type.IsString() ->
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index ead0cfd..e57dd93 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -236,9 +236,14 @@
 	{name: "Sqrt"}, // sqrt(arg0), float64 only
 
 	// Data movement
-	{name: "Phi"},     // select an argument based on which predecessor block we came from
-	{name: "Copy"},    // output = arg0
-	{name: "Convert"}, // output = arg0 -- a copy that converts to/from a pointer
+	{name: "Phi"},  // select an argument based on which predecessor block we came from
+	{name: "Copy"}, // output = arg0
+	// Convert converts between pointers and integers.
+	// We have a special op for this so as to not confuse GC
+	// (particularly stack maps).  It takes a memory arg so it
+	// gets correctly ordered with respect to GC safepoints.
+	// arg0=ptr/int arg1=mem, output=int/ptr
+	{name: "Convert"},
 
 	// constants.  Constant values are stored in the aux field.
 	// booleans have a bool aux field, strings have a string aux