From: Josh Bleecher Snyder Date: Fri, 24 Apr 2020 18:00:44 +0000 (-0700) Subject: cmd/compile: refactor out eqinterface X-Git-Tag: go1.15beta1~359 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=f4e13b83aa771ef84073d783a0eb811d0004ed5e;p=gostls13.git cmd/compile: refactor out eqinterface Refactor out creating the two Nodes needed to check interface equality. Preliminary work to other optimizations. Passes toolstash-check. Change-Id: Id6b39e8e78f07289193423d0ef905d70826acf89 Reviewed-on: https://go-review.googlesource.com/c/go/+/230206 Run-TryBot: Josh Bleecher Snyder TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go index 33e8eca54e..16524773a0 100644 --- a/src/cmd/compile/internal/gc/alg.go +++ b/src/cmd/compile/internal/gc/alg.go @@ -699,6 +699,44 @@ func eqstring(s, t *Node) (eqlen, eqmem *Node) { return cmp, call } +// eqinterface returns the nodes +// s.tab == t.tab (or s.typ == t.typ, as appropriate) +// and +// ifaceeq(s.tab, s.data, t.data) (or efaceeq(s.typ, s.data, t.data), as appropriate) +// which can be used to construct interface equality comparison. +// eqtab must be evaluated before eqdata, and shortcircuiting is required. +func eqinterface(s, t *Node) (eqtab, eqdata *Node) { + if !types.Identical(s.Type, t.Type) { + Fatalf("eqinterface %v %v", s.Type, t.Type) + } + // func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool) + // func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool) + var fn *Node + if s.Type.IsEmptyInterface() { + fn = syslook("efaceeq") + } else { + fn = syslook("ifaceeq") + } + + stab := nod(OITAB, s, nil) + ttab := nod(OITAB, t, nil) + sdata := nod(OIDATA, s, nil) + tdata := nod(OIDATA, t, nil) + sdata.Type = types.Types[TUNSAFEPTR] + tdata.Type = types.Types[TUNSAFEPTR] + sdata.SetTypecheck(1) + tdata.SetTypecheck(1) + + call := nod(OCALL, fn, nil) + call.List.Append(stab, sdata, tdata) + call = typecheck(call, ctxExpr|ctxMultiOK) + + cmp := nod(OEQ, stab, ttab) + cmp = typecheck(cmp, ctxExpr) + cmp.Type = types.Types[TBOOL] + return cmp, call +} + // eqmem returns the node // memequal(&p.field, &q.field [, size]) func eqmem(p *Node, q *Node, field *types.Sym, size int64) *Node { diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 5dd98efc75..84ba528bc9 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -3379,36 +3379,15 @@ func tracecmpArg(n *Node, t *types.Type, init *Nodes) *Node { } func walkcompareInterface(n *Node, init *Nodes) *Node { - // ifaceeq(i1 any-1, i2 any-2) (ret bool); - if !types.Identical(n.Left.Type, n.Right.Type) { - Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type) - } - var fn *Node - if n.Left.Type.IsEmptyInterface() { - fn = syslook("efaceeq") - } else { - fn = syslook("ifaceeq") - } - n.Right = cheapexpr(n.Right, init) n.Left = cheapexpr(n.Left, init) - lt := nod(OITAB, n.Left, nil) - rt := nod(OITAB, n.Right, nil) - ld := nod(OIDATA, n.Left, nil) - rd := nod(OIDATA, n.Right, nil) - ld.Type = types.Types[TUNSAFEPTR] - rd.Type = types.Types[TUNSAFEPTR] - ld.SetTypecheck(1) - rd.SetTypecheck(1) - call := mkcall1(fn, n.Type, init, lt, ld, rd) - - // Check itable/type before full compare. - // Note: short-circuited because order matters. + eqtab, eqdata := eqinterface(n.Left, n.Right) var cmp *Node if n.Op == OEQ { - cmp = nod(OANDAND, nod(OEQ, lt, rt), call) + cmp = nod(OANDAND, eqtab, eqdata) } else { - cmp = nod(OOROR, nod(ONE, lt, rt), nod(ONOT, call, nil)) + eqtab.Op = ONE + cmp = nod(OOROR, eqtab, nod(ONOT, eqdata, nil)) } return finishcompare(n, cmp, init) }