[dev.ssa] cmd/compile: implement OCAP

And dependent fixes and misc cleanup.

Co-hacking with josharian at Gophercon.

Change-Id: Ib85dc13b303929017eb0a4d2fc2f603485f7479b
Reviewed-on: https://go-review.googlesource.com/12027
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index ab16a33..90c1e0a 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -6,6 +6,7 @@
 
 import (
 	"fmt"
+	"strings"
 
 	"cmd/compile/internal/ssa"
 	"cmd/internal/obj"
@@ -18,7 +19,7 @@
 // it will never return nil, and the bool can be removed.
 func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
 	name := fn.Func.Nname.Sym.Name
-	usessa = len(name) > 4 && name[len(name)-4:] == "_ssa"
+	usessa = strings.HasSuffix(name, "_ssa")
 
 	if usessa {
 		dumplist("buildssa-enter", fn.Func.Enter)
@@ -293,6 +294,8 @@
 	case OBLOCK:
 		s.stmtList(n.List)
 
+	case OEMPTY:
+
 	case ODCL:
 		if n.Left.Class&PHEAP == 0 {
 			return
@@ -527,14 +530,18 @@
 			return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
 		}
 
-	case OLEN:
+	case OLEN, OCAP:
 		switch {
-		case n.Left.Type.Bound < 0: // slice
-			return s.newValue1(ssa.OpSliceLen, s.config.Uintptr, s.expr(n.Left))
-		case n.Left.Type.IsString(): // string
-			return s.newValue1(ssa.OpStringLen, s.config.Uintptr, s.expr(n.Left))
+		case n.Left.Type.IsSlice():
+			op := ssa.OpSliceLen
+			if n.Op == OCAP {
+				op = ssa.OpSliceCap
+			}
+			return s.newValue1(op, s.config.Int, s.expr(n.Left))
+		case n.Left.Type.IsString(): // string; not reachable for OCAP
+			return s.newValue1(ssa.OpStringLen, s.config.Int, s.expr(n.Left))
 		default: // array
-			return s.constInt(s.config.Uintptr, n.Left.Type.Bound)
+			return s.constInt(s.config.Int, n.Left.Type.Bound)
 		}
 
 	case OCALLFUNC:
@@ -645,19 +652,19 @@
 		// used for storing/loading arguments/returns to/from callees
 		return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
 	case OINDEX:
-		if n.Left.Type.Bound >= 0 { // array
-			a := s.addr(n.Left)
-			i := s.expr(n.Right)
-			len := s.constInt(s.config.Uintptr, n.Left.Type.Bound)
-			s.boundsCheck(i, len)
-			return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
-		} else { // slice
+		if n.Left.Type.IsSlice() {
 			a := s.expr(n.Left)
 			i := s.expr(n.Right)
 			len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, a)
 			s.boundsCheck(i, len)
 			p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a)
 			return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i)
+		} else { // array
+			a := s.addr(n.Left)
+			i := s.expr(n.Right)
+			len := s.constInt(s.config.Uintptr, n.Left.Type.Bound)
+			s.boundsCheck(i, len)
+			return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
 		}
 	default:
 		s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0))