Commit e67d881b authored by Keith Randall's avatar Keith Randall

cmd/compile: simplify efaceeq and ifaceeq

Clean up code that does interface equality. Avoid doing checks
in efaceeq/ifaceeq that we already did before calling those routines.

No noticeable performance changes for existing benchmarks.

name            old time/op  new time/op  delta
EfaceCmpDiff-8   604ns ± 1%   553ns ± 1%  -8.41%  (p=0.000 n=9+10)

Fixes #18618

Change-Id: I3bd46db82b96494873045bc3300c56400bc582eb
Reviewed-on: https://go-review.googlesource.com/38606
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarJosh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: default avatarDavid Chase <drchase@google.com>
parent c026c37f
This diff is collapsed.
...@@ -87,8 +87,10 @@ func panicdottypeE(have, want, iface *byte) ...@@ -87,8 +87,10 @@ func panicdottypeE(have, want, iface *byte)
func panicdottypeI(have, want, iface *byte) func panicdottypeI(have, want, iface *byte)
func panicnildottype(want *byte) func panicnildottype(want *byte)
func ifaceeq(i1 any, i2 any) (ret bool) // interface equality. Type/itab pointers are already known to be equal, so
func efaceeq(i1 any, i2 any) (ret bool) // we only need to pass one.
func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool)
func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool)
// *byte is really *runtime.Type // *byte is really *runtime.Type
func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any) func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any)
......
...@@ -1560,24 +1560,29 @@ opswitch: ...@@ -1560,24 +1560,29 @@ opswitch:
n.Right = cheapexpr(n.Right, init) n.Right = cheapexpr(n.Right, init)
n.Left = cheapexpr(n.Left, init) n.Left = cheapexpr(n.Left, init)
fn = substArgTypes(fn, n.Right.Type, n.Left.Type) lt := nod(OITAB, n.Left, nil)
r := mkcall1(fn, n.Type, init, n.Left, n.Right) rt := nod(OITAB, n.Right, nil)
// TODO(marvin): Fix Node.EType type union. ld := nod(OIDATA, n.Left, nil)
if Op(n.Etype) == ONE { rd := nod(OIDATA, n.Right, nil)
r = nod(ONOT, r, nil) ld.Type = Types[TUNSAFEPTR]
} rd.Type = Types[TUNSAFEPTR]
ld.Typecheck = 1
// check itable/type before full compare. rd.Typecheck = 1
call := mkcall1(fn, n.Type, init, lt, ld, rd)
// Check itable/type before full compare.
// Note: short-circuited because order matters.
// TODO(marvin): Fix Node.EType type union. // TODO(marvin): Fix Node.EType type union.
var cmp *Node
if Op(n.Etype) == OEQ { if Op(n.Etype) == OEQ {
r = nod(OANDAND, nod(OEQ, nod(OITAB, n.Left, nil), nod(OITAB, n.Right, nil)), r) cmp = nod(OANDAND, nod(OEQ, lt, rt), call)
} else { } else {
r = nod(OOROR, nod(ONE, nod(OITAB, n.Left, nil), nod(OITAB, n.Right, nil)), r) cmp = nod(OOROR, nod(ONE, lt, rt), nod(ONOT, call, nil))
} }
r = typecheck(r, Erv) cmp = typecheck(cmp, Erv)
r = walkexpr(r, init) cmp = walkexpr(cmp, init)
r.Type = n.Type cmp.Type = n.Type
n = r n = cmp
case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT, OPTRLIT: case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
if isStaticCompositeLiteral(n) { if isStaticCompositeLiteral(n) {
......
...@@ -206,16 +206,16 @@ func strequal(p, q unsafe.Pointer) bool { ...@@ -206,16 +206,16 @@ func strequal(p, q unsafe.Pointer) bool {
return *(*string)(p) == *(*string)(q) return *(*string)(p) == *(*string)(q)
} }
func interequal(p, q unsafe.Pointer) bool { func interequal(p, q unsafe.Pointer) bool {
return ifaceeq(*(*iface)(p), *(*iface)(q)) x := *(*iface)(p)
y := *(*iface)(q)
return x.tab == y.tab && ifaceeq(x.tab, x.data, y.data)
} }
func nilinterequal(p, q unsafe.Pointer) bool { func nilinterequal(p, q unsafe.Pointer) bool {
return efaceeq(*(*eface)(p), *(*eface)(q)) x := *(*eface)(p)
y := *(*eface)(q)
return x._type == y._type && efaceeq(x._type, x.data, y.data)
} }
func efaceeq(x, y eface) bool { func efaceeq(t *_type, x, y unsafe.Pointer) bool {
t := x._type
if t != y._type {
return false
}
if t == nil { if t == nil {
return true return true
} }
...@@ -224,27 +224,23 @@ func efaceeq(x, y eface) bool { ...@@ -224,27 +224,23 @@ func efaceeq(x, y eface) bool {
panic(errorString("comparing uncomparable type " + t.string())) panic(errorString("comparing uncomparable type " + t.string()))
} }
if isDirectIface(t) { if isDirectIface(t) {
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data))) return eq(noescape(unsafe.Pointer(&x)), noescape(unsafe.Pointer(&y)))
} }
return eq(x.data, y.data) return eq(x, y)
} }
func ifaceeq(x, y iface) bool { func ifaceeq(tab *itab, x, y unsafe.Pointer) bool {
xtab := x.tab if tab == nil {
if xtab != y.tab {
return false
}
if xtab == nil {
return true return true
} }
t := xtab._type t := tab._type
eq := t.alg.equal eq := t.alg.equal
if eq == nil { if eq == nil {
panic(errorString("comparing uncomparable type " + t.string())) panic(errorString("comparing uncomparable type " + t.string()))
} }
if isDirectIface(t) { if isDirectIface(t) {
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data))) return eq(noescape(unsafe.Pointer(&x)), noescape(unsafe.Pointer(&y)))
} }
return eq(x.data, y.data) return eq(x, y)
} }
// Testing adapters for hash quality tests (see hash_test.go) // Testing adapters for hash quality tests (see hash_test.go)
......
...@@ -50,6 +50,23 @@ func BenchmarkIfaceCmpNil100(b *testing.B) { ...@@ -50,6 +50,23 @@ func BenchmarkIfaceCmpNil100(b *testing.B) {
} }
} }
var efaceCmp1 interface{}
var efaceCmp2 interface{}
func BenchmarkEfaceCmpDiff(b *testing.B) {
x := 5
efaceCmp1 = &x
y := 6
efaceCmp2 = &y
for i := 0; i < b.N; i++ {
for j := 0; j < 100; j++ {
if efaceCmp1 == efaceCmp2 {
b.Fatal("bad comparison")
}
}
}
}
func BenchmarkDefer(b *testing.B) { func BenchmarkDefer(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
defer1() defer1()
......
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