cmd/internal/gc, runtime: speed up some cases of _, ok := i.(T)

Some type assertions of the form _, ok := i.(T) allow efficient inlining.
Such type assertions commonly show up in type switches.
For example, with this optimization, using 6g, the length of
encoding/binary's intDataSize function shrinks from 2224 to 1728 bytes (-22%).

benchmark                    old ns/op     new ns/op     delta
BenchmarkAssertI2E2Blank     4.67          0.82          -82.44%
BenchmarkAssertE2T2Blank     4.38          0.83          -81.05%
BenchmarkAssertE2E2Blank     3.88          0.83          -78.61%
BenchmarkAssertE2E2          14.2          14.4          +1.41%
BenchmarkAssertE2T2          10.3          10.4          +0.97%
BenchmarkAssertI2E2          13.4          13.3          -0.75%

Change-Id: Ie9798c3e85432bb8e0f2c723afc376e233639df7
Reviewed-on: https://go-review.googlesource.com/7697
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go
index e55b415..1626c11 100644
--- a/src/cmd/internal/gc/walk.go
+++ b/src/cmd/internal/gc/walk.go
@@ -869,6 +869,32 @@
 			oktype = ok.Type
 		}
 
+		fromKind := type2IET(from.Type)
+		toKind := type2IET(t)
+
+		// Avoid runtime calls in a few cases of the form _, ok := i.(T).
+		// This is faster and shorter and allows the corresponding assertX2X2
+		// routines to skip nil checks on their last argument.
+		if isblank(n.List.N) {
+			var fast *Node
+			switch {
+			case fromKind == "E" && toKind == "T":
+				tab := Nod(OITAB, from, nil) // type:eface::tab:iface
+				typ := Nod(OCONVNOP, typename(t), nil)
+				typ.Type = Ptrto(Types[TUINTPTR])
+				fast = Nod(OEQ, tab, typ)
+			case fromKind == "I" && toKind == "E",
+				fromKind == "E" && toKind == "E":
+				tab := Nod(OITAB, from, nil)
+				fast = Nod(ONE, tab, nodnil())
+			}
+			if fast != nil {
+				n = Nod(OAS, ok, fast)
+				typecheck(&n, Etop)
+				goto ret
+			}
+		}
+
 		var resptr *Node // &res
 		if isblank(n.List.N) {
 			resptr = nodnil()
@@ -877,7 +903,7 @@
 		}
 		resptr.Etype = 1 // addr does not escape
 
-		buf := "assert" + type2IET(from.Type) + "2" + type2IET(t) + "2"
+		buf := "assert" + fromKind + "2" + toKind + "2"
 		fn := syslook(buf, 1)
 		substArgTypes(fn, from.Type, t)
 		call := mkcall1(fn, oktype, init, typename(t), from, resptr)