Commit 1a7fc7b3 authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

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: default avatarKeith Randall <khr@golang.org>
parent 615a52b9
...@@ -3139,14 +3139,9 @@ func eqfor(t *Type, needsize *int) *Node { ...@@ -3139,14 +3139,9 @@ func eqfor(t *Type, needsize *int) *Node {
func walkcompare(n *Node, init *Nodes) *Node { func walkcompare(n *Node, init *Nodes) *Node {
// Given interface value l and concrete value r, rewrite // Given interface value l and concrete value r, rewrite
// l == r // l == r
// to // into types-equal && data-equal.
// x, ok := l.(type(r)); ok && x == r // This is efficient, avoids allocations, and avoids runtime calls.
// Handle != similarly. var l, r *Node
// This avoids the allocation that would be required
// to convert r to l for comparison.
var l *Node
var r *Node
if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() { if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() {
l = n.Left l = n.Left
r = n.Right r = n.Right
...@@ -3156,35 +3151,36 @@ func walkcompare(n *Node, init *Nodes) *Node { ...@@ -3156,35 +3151,36 @@ func walkcompare(n *Node, init *Nodes) *Node {
} }
if l != nil { if l != nil {
x := temp(r.Type) // Handle both == and !=.
if haspointers(r.Type) { eq := n.Op
a := Nod(OAS, x, nil) var andor Op
a = typecheck(a, Etop) if eq == OEQ {
init.Append(a) andor = OANDAND
}
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))
} else { } else {
r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r)) andor = OOROR
} }
init.Append(expr) // Check for types equal.
n = finishcompare(n, r, init) // 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 return n
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment