cmd/compile: clean up ssa.Value memory arg usage

This change adds a method to replace expressions
of the form

   v.Args[len(v.Args)-1]

so that the code's intention to walk memory arguments
is explicit.

Passes toolstash-check.

Change-Id: I0c80d73bc00989dd3cdf72b4f2c8e1075a2515e0
Reviewed-on: https://go-review.googlesource.com/37757
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index b0a1629..9c9c6b5 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -158,7 +158,7 @@
 		// If the load is in a different block do not merge it.
 		return false
 	}
-	mem := load.Args[len(load.Args)-1]
+	mem := load.MemoryArg()
 
 	// We need the load's memory arg to still be alive at target. That
 	// can't be the case if one of target's args depends on a memory
@@ -230,7 +230,7 @@
 					if len(m.Args) == 0 {
 						break
 					}
-					m = m.Args[len(m.Args)-1]
+					m = m.MemoryArg()
 				}
 			}
 
diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go
index b0a2f23..356d447 100644
--- a/src/cmd/compile/internal/ssa/schedule.go
+++ b/src/cmd/compile/internal/ssa/schedule.go
@@ -314,11 +314,11 @@
 			if v.Op == OpInitMem || v.Op == OpPhi {
 				continue
 			}
-			a := v.Args[len(v.Args)-1]
+			a := v
 			if v.Op == OpSelect1 {
-				a = a.Args[len(a.Args)-1]
+				a = a.Args[0]
 			}
-			sset.add(a.ID) // record that a is used
+			sset.add(a.MemoryArg().ID) // record that v's memory arg is used
 		}
 		if v.Op == OpNilCheck {
 			hasNilCheck = true
@@ -364,7 +364,7 @@
 		if w.Op == OpSelect1 {
 			w = w.Args[0]
 		}
-		w = w.Args[len(w.Args)-1]
+		w = w.MemoryArg()
 	}
 	var stack []*Value
 	for _, v := range values {
diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go
index 6f19263..45cfb06 100644
--- a/src/cmd/compile/internal/ssa/tighten.go
+++ b/src/cmd/compile/internal/ssa/tighten.go
@@ -20,7 +20,7 @@
 				// Tuple selectors must stay with the tuple generator.
 				continue
 			}
-			if len(v.Args) > 0 && v.Args[len(v.Args)-1].Type.IsMemory() {
+			if v.MemoryArg() != nil {
 				// We can't move values which have a memory arg - it might
 				// make two memory values live across a block boundary.
 				continue
diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
index 00f2454..93172bc 100644
--- a/src/cmd/compile/internal/ssa/value.go
+++ b/src/cmd/compile/internal/ssa/value.go
@@ -311,3 +311,23 @@
 	}
 	return reg.(*Register).name
 }
+
+// MemoryArg returns the memory argument for the Value.
+// The returned value, if non-nil, will be memory-typed,
+// except in the case where v is Select1, in which case
+// the returned value will be a tuple containing a memory
+// type. Otherwise, nil is returned.
+func (v *Value) MemoryArg() *Value {
+	if v.Op == OpPhi {
+		v.Fatalf("MemoryArg on Phi")
+	}
+	na := len(v.Args)
+	if na == 0 {
+		return nil
+	}
+	if m := v.Args[na-1]; m.Type.IsMemory() ||
+		(v.Op == OpSelect1 && m.Type.FieldType(1).IsMemory()) {
+		return m
+	}
+	return nil
+}
diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go
index 53bbc4a..0b82a5b 100644
--- a/src/cmd/compile/internal/ssa/writebarrier.go
+++ b/src/cmd/compile/internal/ssa/writebarrier.go
@@ -120,7 +120,7 @@
 		b.Values = b.Values[:start]
 
 		// find the memory before the WB stores
-		mem := stores[0].Args[len(stores[0].Args)-1]
+		mem := stores[0].MemoryArg()
 		pos := stores[0].Pos
 		bThen := f.NewBlock(BlockPlain)
 		bElse := f.NewBlock(BlockPlain)