Commit bc8458ab authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/compile: use && in generated eq algs

This allows the compiler to generate better code
containing fewer jumps and only a single return value.

Cuts 12k off cmd/go and 16k off golang.org/x/tools/cmd/godoc, approx 0.1% each.

For #6853 and #9930

Change-Id: I009616df797760b01e09f06357a2d6fd6ebcf307
Reviewed-on: https://go-review.googlesource.com/19767Reviewed-by: default avatarDavid Crawshaw <crawshaw@golang.org>
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 4cef0e98
...@@ -2649,17 +2649,13 @@ func genhash(sym *Sym, t *Type) { ...@@ -2649,17 +2649,13 @@ func genhash(sym *Sym, t *Type) {
safemode = old_safemode safemode = old_safemode
} }
// Return node for // eqfield returns the node
// if p.field != q.field { return false } // p.field == q.field
func eqfield(p *Node, q *Node, field *Node) *Node { func eqfield(p *Node, q *Node, field *Node) *Node {
nx := Nod(OXDOT, p, field) nx := Nod(OXDOT, p, field)
ny := Nod(OXDOT, q, field) ny := Nod(OXDOT, q, field)
nif := Nod(OIF, nil, nil) ne := Nod(OEQ, nx, ny)
nif.Left = Nod(ONE, nx, ny) return ne
r := Nod(ORETURN, nil, nil)
r.List = list(r.List, Nodbool(false))
nif.Nbody = list(nif.Nbody, r)
return nif
} }
func eqmemfunc(size int64, type_ *Type, needsize *int) *Node { func eqmemfunc(size int64, type_ *Type, needsize *int) *Node {
...@@ -2680,8 +2676,8 @@ func eqmemfunc(size int64, type_ *Type, needsize *int) *Node { ...@@ -2680,8 +2676,8 @@ func eqmemfunc(size int64, type_ *Type, needsize *int) *Node {
return fn return fn
} }
// Return node for // eqmem returns the node
// if !memequal(&p.field, &q.field [, size]) { return false } // memequal(&p.field, &q.field [, size])
func eqmem(p *Node, q *Node, field *Node, size int64) *Node { func eqmem(p *Node, q *Node, field *Node, size int64) *Node {
var needsize int var needsize int
...@@ -2699,15 +2695,11 @@ func eqmem(p *Node, q *Node, field *Node, size int64) *Node { ...@@ -2699,15 +2695,11 @@ func eqmem(p *Node, q *Node, field *Node, size int64) *Node {
call.List = list(call.List, Nodintconst(size)) call.List = list(call.List, Nodintconst(size))
} }
nif := Nod(OIF, nil, nil) return call
nif.Left = Nod(ONOT, call, nil)
r := Nod(ORETURN, nil, nil)
r.List = list(r.List, Nodbool(false))
nif.Nbody = list(nif.Nbody, r)
return nif
} }
// Generate a helper function to check equality of two values of type t. // geneq generates a helper function to
// check equality of two values of type t.
func geneq(sym *Sym, t *Type) { func geneq(sym *Sym, t *Type) {
if Debug['r'] != 0 { if Debug['r'] != 0 {
fmt.Printf("geneq %v %v\n", sym, t) fmt.Printf("geneq %v %v\n", sym, t)
...@@ -2777,12 +2769,18 @@ func geneq(sym *Sym, t *Type) { ...@@ -2777,12 +2769,18 @@ func geneq(sym *Sym, t *Type) {
nrange.Nbody = list(nrange.Nbody, nif) nrange.Nbody = list(nrange.Nbody, nif)
fn.Nbody = list(fn.Nbody, nrange) fn.Nbody = list(fn.Nbody, nrange)
// Walk the struct using memequal for runs of AMEM // return true
ret := Nod(ORETURN, nil, nil)
ret.List = list(ret.List, Nodbool(true))
fn.Nbody = list(fn.Nbody, ret)
// Walk the struct using memequal for runs of AMEM
// and calling specific equality tests for the others. // and calling specific equality tests for the others.
// Skip blank-named fields. // Skip blank-named fields.
case TSTRUCT: case TSTRUCT:
var first *Type var first *Type
var conjuncts []*Node
offend := int64(0) offend := int64(0)
var size int64 var size int64
for t1 := t.Type; ; t1 = t1.Down { for t1 := t.Type; ; t1 = t1.Down {
...@@ -2805,17 +2803,17 @@ func geneq(sym *Sym, t *Type) { ...@@ -2805,17 +2803,17 @@ func geneq(sym *Sym, t *Type) {
// cross-package unexported fields. // cross-package unexported fields.
if first != nil { if first != nil {
if first.Down == t1 { if first.Down == t1 {
fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym))) conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
} else if first.Down.Down == t1 { } else if first.Down.Down == t1 {
fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym))) conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
first = first.Down first = first.Down
if !isblanksym(first.Sym) { if !isblanksym(first.Sym) {
fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym))) conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
} }
} else { } else {
// More than two fields: use memequal. // More than two fields: use memequal.
size = offend - first.Width // first->width is offset size = offend - first.Width // first->width is offset
fn.Nbody = list(fn.Nbody, eqmem(np, nq, newname(first.Sym), size)) conjuncts = append(conjuncts, eqmem(np, nq, newname(first.Sym), size))
} }
first = nil first = nil
...@@ -2829,15 +2827,26 @@ func geneq(sym *Sym, t *Type) { ...@@ -2829,15 +2827,26 @@ func geneq(sym *Sym, t *Type) {
} }
// Check this field, which is not just memory. // Check this field, which is not just memory.
fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(t1.Sym))) conjuncts = append(conjuncts, eqfield(np, nq, newname(t1.Sym)))
} }
}
// return true var and *Node
r := Nod(ORETURN, nil, nil) switch len(conjuncts) {
case 0:
and = Nodbool(true)
case 1:
and = conjuncts[0]
default:
and = Nod(OANDAND, conjuncts[0], conjuncts[1])
for _, conjunct := range conjuncts[2:] {
and = Nod(OANDAND, and, conjunct)
}
}
r.List = list(r.List, Nodbool(true)) ret := Nod(ORETURN, nil, nil)
fn.Nbody = list(fn.Nbody, r) ret.List = list(ret.List, and)
fn.Nbody = list(fn.Nbody, ret)
}
if Debug['r'] != 0 { if Debug['r'] != 0 {
dumplist("geneq body", fn.Nbody) dumplist("geneq body", fn.Nbody)
......
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