mirror of
https://github.com/golang/go
synced 2024-11-18 16:04:44 -07:00
cmd/compile: make runtime calls last in eq algs
type T struct { f float64 a [64]uint64 g float64 } Prior to this change, the generated equality algorithm for T was: func eqT(p, q *T) bool { return p.f == q.f && runtime.memequal(p.a, q.a, 512) && p.g == q.g } In handwritten code, we would normally put the cheapest checks first. This change takes a step in that direction. We now generate: func eqT(p, q *T) bool { return p.f == q.f && p.g == q.g && runtime.memequal(p.a, q.a, 512) } For most types, this also generates considerably shorter code. Examples: runtime .eq."".mstats 406 -> 391 (-3.69%) .eq.""._func 114 -> 101 (-11.40%) .eq."".itab 115 -> 102 (-11.30%) .eq."".scase 125 -> 116 (-7.20%) .eq."".traceStack 119 -> 102 (-14.29%) .eq."".gcControllerState 169 -> 161 (-4.73%) .eq."".sweepdata 121 -> 112 (-7.44%) However, for types in which we make unwise choices about inlining memory-only comparisons (#38494), this generates longer code. Example: cmd/internal/obj .eq."".objWriter 211 -> 214 (+1.42%) .eq."".Addr 185 -> 187 (+1.08%) Fortunately, such cases are not common. Change-Id: I47a27da93c1f88ec71fa350c192f36b29548a217 Reviewed-on: https://go-review.googlesource.com/c/go/+/230203 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
1cf357981e
commit
79648bde2d
@ -8,6 +8,7 @@ import (
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// AlgKind describes the kind of algorithms used for comparing and
|
||||
@ -553,13 +554,15 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
fn.Nbody.Append(ret)
|
||||
|
||||
case TSTRUCT:
|
||||
var cond *Node
|
||||
// Build a list of conditions to satisfy.
|
||||
// Track their order so that we can preserve aspects of that order.
|
||||
type nodeIdx struct {
|
||||
n *Node
|
||||
idx int
|
||||
}
|
||||
var conds []nodeIdx
|
||||
and := func(n *Node) {
|
||||
if cond == nil {
|
||||
cond = n
|
||||
return
|
||||
}
|
||||
cond = nod(OANDAND, cond, n)
|
||||
conds = append(conds, nodeIdx{n: n, idx: len(conds)})
|
||||
}
|
||||
|
||||
// Walk the struct using memequal for runs of AMEM
|
||||
@ -597,8 +600,24 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
i = next
|
||||
}
|
||||
|
||||
if cond == nil {
|
||||
// Sort conditions to put runtime calls last.
|
||||
// Preserve the rest of the ordering.
|
||||
sort.SliceStable(conds, func(i, j int) bool {
|
||||
x, y := conds[i], conds[j]
|
||||
if (x.n.Op != OCALL) == (y.n.Op != OCALL) {
|
||||
return x.idx < y.idx
|
||||
}
|
||||
return x.n.Op != OCALL
|
||||
})
|
||||
|
||||
var cond *Node
|
||||
if len(conds) == 0 {
|
||||
cond = nodbool(true)
|
||||
} else {
|
||||
cond = conds[0].n
|
||||
for _, c := range conds[1:] {
|
||||
cond = nod(OANDAND, cond, c.n)
|
||||
}
|
||||
}
|
||||
|
||||
ret := nod(ORETURN, nil, nil)
|
||||
|
Loading…
Reference in New Issue
Block a user