]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: handle e == T comparison more efficiently
authorJosh Bleecher Snyder <josharian@gmail.com>
Mon, 6 Jun 2016 20:01:48 +0000 (13:01 -0700)
committerJosh Bleecher Snyder <josharian@gmail.com>
Wed, 17 Aug 2016 01:12:23 +0000 (01:12 +0000)
Instead of making a runtime call, compare types and values.

Change-Id: Id302083d5a6a5f18e04f36f304f3d290c46976ad
Reviewed-on: https://go-review.googlesource.com/26660
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/gc/walk.go

index 237a5519ec02800ca717a4a7fb6bb8d92018cc2e..55a29e5bad668075ac518ba15afc19ec063b3184 100644 (file)
@@ -3139,14 +3139,9 @@ func eqfor(t *Type, needsize *int) *Node {
 func walkcompare(n *Node, init *Nodes) *Node {
        // Given interface value l and concrete value r, rewrite
        //   l == r
-       // to
-       //   x, ok := l.(type(r)); ok && x == r
-       // Handle != similarly.
-       // This avoids the allocation that would be required
-       // to convert r to l for comparison.
-       var l *Node
-
-       var r *Node
+       // into types-equal && data-equal.
+       // This is efficient, avoids allocations, and avoids runtime calls.
+       var l, r *Node
        if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() {
                l = n.Left
                r = n.Right
@@ -3156,35 +3151,36 @@ func walkcompare(n *Node, init *Nodes) *Node {
        }
 
        if l != nil {
-               x := temp(r.Type)
-               if haspointers(r.Type) {
-                       a := Nod(OAS, x, nil)
-                       a = typecheck(a, Etop)
-                       init.Append(a)
-               }
-               ok := temp(Types[TBOOL])
-
-               // l.(type(r))
-               a := Nod(ODOTTYPE, l, nil)
-
-               a.Type = r.Type
-
-               // x, ok := l.(type(r))
-               expr := Nod(OAS2, nil, nil)
-
-               expr.List.Append(x)
-               expr.List.Append(ok)
-               expr.Rlist.Append(a)
-               expr = typecheck(expr, Etop)
-               expr = walkexpr(expr, init)
-
-               if n.Op == OEQ {
-                       r = Nod(OANDAND, ok, Nod(OEQ, x, r))
+               // Handle both == and !=.
+               eq := n.Op
+               var andor Op
+               if eq == OEQ {
+                       andor = OANDAND
                } else {
-                       r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
-               }
-               init.Append(expr)
-               n = finishcompare(n, r, init)
+                       andor = OOROR
+               }
+               // Check for types equal.
+               // For empty interface, this is:
+               //   l.tab == type(r)
+               // For non-empty interface, this is:
+               //   l.tab != nil && l.tab._type == type(r)
+               var eqtype *Node
+               tab := Nod(OITAB, l, nil)
+               rtyp := typename(r.Type)
+               if l.Type.IsEmptyInterface() {
+                       tab.Type = Ptrto(Types[TUINT8])
+                       tab.Typecheck = 1
+                       eqtype = Nod(eq, tab, rtyp)
+               } else {
+                       nonnil := Nod(Brcom(eq), nodnil(), tab)
+                       match := Nod(eq, itabType(tab), rtyp)
+                       eqtype = Nod(andor, nonnil, match)
+               }
+               // Check for data equal.
+               eqdata := Nod(eq, ifaceData(l, r.Type), r)
+               // Put it all together.
+               expr := Nod(andor, eqtype, eqdata)
+               n = finishcompare(n, expr, init)
                return n
        }