Commit 199cc194 authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: simplify eq and hash function generation

Passes toolstash -cmp.

Change-Id: Ie4675e6f713c3bbb90556f5347cbd7268a9c1a5d
Reviewed-on: https://go-review.googlesource.com/20357
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent e28a890d
...@@ -144,18 +144,16 @@ func algtype1(t *Type, bad **Type) int { ...@@ -144,18 +144,16 @@ func algtype1(t *Type, bad **Type) int {
} }
ret := AMEM ret := AMEM
var a int for f := t.Type; f != nil; f = f.Down {
for t1 := t.Type; t1 != nil; t1 = t1.Down {
// All fields must be comparable. // All fields must be comparable.
a = algtype1(t1.Type, bad) a := algtype1(f.Type, bad)
if a == ANOEQ { if a == ANOEQ {
return ANOEQ return ANOEQ
} }
// Blank fields, padded fields, fields with non-memory // Blank fields, padded fields, fields with non-memory
// equality need special compare. // equality need special compare.
if a != AMEM || isblanksym(t1.Sym) || ispaddedfield(t1, t.Width) { if a != AMEM || isblanksym(f.Sym) || ispaddedfield(t, f) {
ret = -1 ret = -1
continue continue
} }
...@@ -236,58 +234,45 @@ func genhash(sym *Sym, t *Type) { ...@@ -236,58 +234,45 @@ func genhash(sym *Sym, t *Type) {
fn.Nbody.Append(n) fn.Nbody.Append(n)
// Walk the struct using memhash for runs of AMEM
// and calling specific hash functions for the others.
case TSTRUCT: case TSTRUCT:
var call *Node // Walk the struct using memhash for runs of AMEM
var nx *Node // and calling specific hash functions for the others.
var na *Node for f := t.Type; f != nil; {
var hashel *Node // Skip blank fields.
if isblanksym(f.Sym) {
t1 := t.Type f = f.Down
for { continue
first, size, next := memrun(t, t1) }
t1 = next
// Run memhash for fields up to this one.
if first != nil {
hashel = hashmem(first.Type)
// h = hashel(&p.first, size, h)
call = Nod(OCALL, hashel, nil)
nx = Nod(OXDOT, np, newname(first.Sym)) // TODO: fields from other packages? // Hash non-memory fields with appropriate hash function.
na = Nod(OADDR, nx, nil) if algtype1(f.Type, nil) != AMEM {
hashel := hashfor(f.Type)
call := Nod(OCALL, hashel, nil)
nx := Nod(OXDOT, np, newname(f.Sym)) // TODO: fields from other packages?
na := Nod(OADDR, nx, nil)
na.Etype = 1 // no escape to heap na.Etype = 1 // no escape to heap
appendNodeSeqNode(&call.List, na) appendNodeSeqNode(&call.List, na)
appendNodeSeqNode(&call.List, nh) appendNodeSeqNode(&call.List, nh)
appendNodeSeqNode(&call.List, Nodintconst(size))
fn.Nbody.Append(Nod(OAS, nh, call)) fn.Nbody.Append(Nod(OAS, nh, call))
} f = f.Down
if t1 == nil {
break
}
if isblanksym(t1.Sym) {
t1 = t1.Down
continue
}
if algtype1(t1.Type, nil) == AMEM {
// Our memory run might have been stopped by padding or a blank field.
// If the next field is memory-ish, it could be the start of a new run.
continue continue
} }
hashel = hashfor(t1.Type) // Otherwise, hash a maximal length run of raw memory.
call = Nod(OCALL, hashel, nil) size, next := memrun(t, f)
nx = Nod(OXDOT, np, newname(t1.Sym)) // TODO: fields from other packages?
na = Nod(OADDR, nx, nil) // h = hashel(&p.first, size, h)
hashel := hashmem(f.Type)
call := Nod(OCALL, hashel, nil)
nx := Nod(OXDOT, np, newname(f.Sym)) // TODO: fields from other packages?
na := Nod(OADDR, nx, nil)
na.Etype = 1 // no escape to heap na.Etype = 1 // no escape to heap
appendNodeSeqNode(&call.List, na) appendNodeSeqNode(&call.List, na)
appendNodeSeqNode(&call.List, nh) appendNodeSeqNode(&call.List, nh)
appendNodeSeqNode(&call.List, Nodintconst(size))
fn.Nbody.Append(Nod(OAS, nh, call)) fn.Nbody.Append(Nod(OAS, nh, call))
t1 = t1.Down f = next
} }
} }
...@@ -438,51 +423,41 @@ func geneq(sym *Sym, t *Type) { ...@@ -438,51 +423,41 @@ func geneq(sym *Sym, t *Type) {
appendNodeSeqNode(&ret.List, Nodbool(true)) appendNodeSeqNode(&ret.List, Nodbool(true))
fn.Nbody.Append(ret) fn.Nbody.Append(ret)
// Walk the struct using memequal for runs of AMEM
// and calling specific equality tests for the others.
// Skip blank-named fields.
case TSTRUCT: case TSTRUCT:
var conjuncts []*Node var conjuncts []*Node
t1 := t.Type // Walk the struct using memequal for runs of AMEM
for { // and calling specific equality tests for the others.
first, size, next := memrun(t, t1) for f := t.Type; f != nil; {
t1 = next // Skip blank-named fields.
if isblanksym(f.Sym) {
// Run memequal for fields up to this one. f = f.Down
// TODO(rsc): All the calls to newname are wrong for
// cross-package unexported fields.
if first != nil {
if first.Down == t1 {
conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
} else if first.Down.Down == t1 {
conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
first = first.Down
if !isblanksym(first.Sym) {
conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
}
} else {
// More than two fields: use memequal.
conjuncts = append(conjuncts, eqmem(np, nq, newname(first.Sym), size))
}
}
if t1 == nil {
break
}
if isblanksym(t1.Sym) {
t1 = t1.Down
continue continue
} }
if algtype1(t1.Type, nil) == AMEM {
// Our memory run might have been stopped by padding or a blank field. // Compare non-memory fields with field equality.
// If the next field is memory-ish, it could be the start of a new run. if algtype1(f.Type, nil) != AMEM {
conjuncts = append(conjuncts, eqfield(np, nq, newname(f.Sym)))
f = f.Down
continue continue
} }
// Check this field, which is not just memory. // Find maximal length run of memory-only fields.
conjuncts = append(conjuncts, eqfield(np, nq, newname(t1.Sym))) size, next := memrun(t, f)
t1 = t1.Down
// Run memequal on fields from f to next.
// TODO(rsc): All the calls to newname are wrong for
// cross-package unexported fields.
if f.Down == next {
conjuncts = append(conjuncts, eqfield(np, nq, newname(f.Sym)))
} else if f.Down.Down == next {
conjuncts = append(conjuncts, eqfield(np, nq, newname(f.Sym)))
conjuncts = append(conjuncts, eqfield(np, nq, newname(f.Down.Sym)))
} else {
// More than two fields: use memequal.
conjuncts = append(conjuncts, eqmem(np, nq, newname(f.Sym), size))
}
f = next
} }
var and *Node var and *Node
...@@ -584,43 +559,42 @@ func eqmemfunc(size int64, type_ *Type, needsize *int) *Node { ...@@ -584,43 +559,42 @@ func eqmemfunc(size int64, type_ *Type, needsize *int) *Node {
} }
// memrun finds runs of struct fields for which memory-only algs are appropriate. // memrun finds runs of struct fields for which memory-only algs are appropriate.
// t is the parent struct type, and field is the field at which to start. // t is the parent struct type, and start is the field that starts the run.
// first is the first field in the memory run.
// size is the length in bytes of the memory included in the run. // size is the length in bytes of the memory included in the run.
// next is the next field after the memory run. // next is the next field after the memory run.
func memrun(t *Type, field *Type) (first *Type, size int64, next *Type) { func memrun(t *Type, start *Type) (size int64, next *Type) {
var offend int64 var last *Type
next = start
for { for {
if field == nil || algtype1(field.Type, nil) != AMEM || isblanksym(field.Sym) { last, next = next, next.Down
if next == nil {
break break
} }
offend = field.Width + field.Type.Width // Stop run after a padded field.
if first == nil { if ispaddedfield(t, last) {
first = field break
} }
// Also, stop before a blank or non-memory field.
// If it's a memory field but it's padded, stop here. if isblanksym(next.Sym) || algtype1(next.Type, nil) != AMEM {
if ispaddedfield(field, t.Width) {
field = field.Down
break break
} }
field = field.Down
}
if first != nil {
size = offend - first.Width // first.Width is offset
} }
return first, size, field end := last.Width + last.Type.Width
return end - start.Width, next
} }
// ispaddedfield reports whether the given field // ispaddedfield reports whether the given field f, assumed to be
// is followed by padding. For the case where t is // a field in struct t, is followed by padding.
// the last field, total gives the size of the enclosing struct. func ispaddedfield(t *Type, f *Type) bool {
func ispaddedfield(t *Type, total int64) bool { if t.Etype != TSTRUCT {
if t.Etype != TFIELD { Fatalf("ispaddedfield called non-struct %v", t)
Fatalf("ispaddedfield called non-field %v", t) }
if f.Etype != TFIELD {
Fatalf("ispaddedfield called non-field %v", f)
} }
if t.Down == nil { end := t.Width
return t.Width+t.Type.Width != total if f.Down != nil {
end = f.Down.Width
} }
return t.Width+t.Type.Width != t.Down.Width return f.Width+f.Type.Width != end
} }
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