cmd/compile: inline x, ok := y.(T) where T is a scalar

When T is a scalar, there are no runtime calls
required, which makes this a clear win.

encoding/binary:
WriteInts-8                958ns ± 3%     864ns ± 2%   -9.80%  (p=0.000 n=15+15)

This also considerably shrinks a core fmt
routine:

Before: "".(*pp).printArg t=1 size=3952 args=0x20 locals=0xf0
After:  "".(*pp).printArg t=1 size=2624 args=0x20 locals=0x98

Unfortunately, I find it very hard to get stable
numbers out of the fmt benchmarks due to thermal scaling.

Change-Id: I1278006b030253bf8e48dc7631d18985cdaa143d
Reviewed-on: https://go-review.googlesource.com/26659
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 601e3c3..237a551 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -555,7 +555,7 @@
 		n.Left = walkexpr(n.Left, init)
 		n.Right = walkexpr(n.Right, init)
 
-	case OSPTR, OITAB:
+	case OSPTR, OITAB, OIDATA:
 		n.Left = walkexpr(n.Left, init)
 
 	case OLEN, OCAP:
@@ -961,11 +961,13 @@
 		toKind := t.iet()
 
 		res := n.List.First()
+		scalar := !haspointers(res.Type)
 
 		// 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(res) {
+		// Also avoid runtime calls for converting interfaces to scalar concrete types.
+		if isblank(res) || (scalar && toKind == 'T') {
 			var fast *Node
 			switch toKind {
 			case 'T':
@@ -985,11 +987,27 @@
 				fast = Nod(ONE, nodnil(), tab)
 			}
 			if fast != nil {
-				if Debug_typeassert > 0 {
-					Warn("type assertion (ok only) inlined")
+				if isblank(res) {
+					if Debug_typeassert > 0 {
+						Warn("type assertion (ok only) inlined")
+					}
+					n = Nod(OAS, ok, fast)
+					n = typecheck(n, Etop)
+				} else {
+					if Debug_typeassert > 0 {
+						Warn("type assertion (scalar result) inlined")
+					}
+					n = Nod(OIF, ok, nil)
+					n.Likely = 1
+					if isblank(ok) {
+						n.Left = fast
+					} else {
+						n.Ninit.Set1(Nod(OAS, ok, fast))
+					}
+					n.Nbody.Set1(Nod(OAS, res, ifaceData(from, res.Type)))
+					n.Rlist.Set1(Nod(OAS, res, nil))
+					n = typecheck(n, Etop)
 				}
-				n = Nod(OAS, ok, fast)
-				n = typecheck(n, Etop)
 				break
 			}
 		}