1
0
mirror of https://github.com/golang/go synced 2024-11-23 18:40:03 -07:00

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>
This commit is contained in:
Josh Bleecher Snyder 2016-06-06 13:01:48 -07:00
parent 615a52b95b
commit 1a7fc7b3a7

View 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))
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
}