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 <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
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 237a551..55a29e5 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -3139,14 +3139,9 @@
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 @@
}
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))
+ andor = OOROR
}
- init.Append(expr)
- n = finishcompare(n, r, init)
+ // 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
}