From: Josh Bleecher Snyder Date: Mon, 6 Jun 2016 20:01:48 +0000 (-0700) Subject: cmd/compile: handle e == T comparison more efficiently X-Git-Tag: go1.8beta1~1826 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=1a7fc7b3a783031ec91844460a44ebffe34a6af1;p=gostls13.git cmd/compile: handle e == T comparison more efficiently 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 TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 237a5519ec..55a29e5bad 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -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 }