]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: eliminate uses of Type.Down in alg.go
authorMatthew Dempsky <mdempsky@google.com>
Fri, 11 Mar 2016 04:07:00 +0000 (20:07 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Fri, 11 Mar 2016 05:30:49 +0000 (05:30 +0000)
This could be done by threading the Iter value down through memrun and
ispaddedfield, but that ends up a bit clunky. This way is also closer
to how we'll want the code to look once fields are kept in slices.

Passes toolstash -cmp.

Change-Id: I8a44445c85f921eb18d97199df2026c5ce0f4f67
Reviewed-on: https://go-review.googlesource.com/20558
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/cmd/compile/internal/gc/alg.go

index 5126ebd3a54f8aed90fd45c528c41959e3792221..0fe3d9f71eb7f1837985d7cf5ae50af301aca3bb 100644 (file)
@@ -129,13 +129,15 @@ func algtype1(t *Type, bad **Type) int {
                return -1 // needs special compare
 
        case TSTRUCT:
-               if t.Type != nil && t.Type.Down == nil && !isblanksym(t.Type.Sym) {
-                       // One-field struct is same as that one field alone.
-                       return algtype1(t.Type.Type, bad)
+               fields := t.FieldSlice()
+
+               // One-field struct is same as that one field alone.
+               if len(fields) == 1 && !isblanksym(fields[0].Sym) {
+                       return algtype1(fields[0].Type, bad)
                }
 
                ret := AMEM
-               for f, it := IterFields(t); f != nil; f = it.Next() {
+               for i, f := range fields {
                        // All fields must be comparable.
                        a := algtype1(f.Type, bad)
                        if a == ANOEQ {
@@ -144,7 +146,7 @@ func algtype1(t *Type, bad **Type) int {
 
                        // Blank fields, padded fields, fields with non-memory
                        // equality need special compare.
-                       if a != AMEM || isblanksym(f.Sym) || ispaddedfield(t, f) {
+                       if a != AMEM || isblanksym(f.Sym) || ispaddedfield(t, fields, i) {
                                ret = -1
                        }
                }
@@ -227,10 +229,12 @@ func genhash(sym *Sym, t *Type) {
        case TSTRUCT:
                // Walk the struct using memhash for runs of AMEM
                // and calling specific hash functions for the others.
-               for f := t.Type; f != nil; {
+               for i, fields := 0, t.FieldSlice(); i < len(fields); {
+                       f := fields[i]
+
                        // Skip blank fields.
                        if isblanksym(f.Sym) {
-                               f = f.Down
+                               i++
                                continue
                        }
 
@@ -244,12 +248,12 @@ func genhash(sym *Sym, t *Type) {
                                call.List.Append(na)
                                call.List.Append(nh)
                                fn.Nbody.Append(Nod(OAS, nh, call))
-                               f = f.Down
+                               i++
                                continue
                        }
 
                        // Otherwise, hash a maximal length run of raw memory.
-                       size, next := memrun(t, f)
+                       size, next := memrun(t, fields, i)
 
                        // h = hashel(&p.first, size, h)
                        hashel := hashmem(f.Type)
@@ -262,7 +266,7 @@ func genhash(sym *Sym, t *Type) {
                        call.List.Append(Nodintconst(size))
                        fn.Nbody.Append(Nod(OAS, nh, call))
 
-                       f = next
+                       i = next
                }
        }
 
@@ -410,57 +414,56 @@ func geneq(sym *Sym, t *Type) {
                fn.Nbody.Append(ret)
 
        case TSTRUCT:
-               var conjuncts []*Node
+               var cond *Node
+               and := func(n *Node) {
+                       if cond == nil {
+                               cond = n
+                               return
+                       }
+                       cond = Nod(OANDAND, cond, n)
+               }
 
                // Walk the struct using memequal for runs of AMEM
                // and calling specific equality tests for the others.
-               for f := t.Type; f != nil; {
+               for i, fields := 0, t.FieldSlice(); i < len(fields); {
+                       f := fields[i]
+
                        // Skip blank-named fields.
                        if isblanksym(f.Sym) {
-                               f = f.Down
+                               i++
                                continue
                        }
 
                        // Compare non-memory fields with field equality.
                        if algtype1(f.Type, nil) != AMEM {
-                               conjuncts = append(conjuncts, eqfield(np, nq, newname(f.Sym)))
-                               f = f.Down
+                               and(eqfield(np, nq, newname(f.Sym)))
+                               i++
                                continue
                        }
 
                        // Find maximal length run of memory-only fields.
-                       size, next := memrun(t, f)
+                       size, next := memrun(t, fields, i)
 
-                       // 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)))
+                       if s := fields[i:next]; len(s) <= 2 {
+                               // Two or fewer fields: use plain field equality.
+                               for _, f := range s {
+                                       and(eqfield(np, nq, newname(f.Sym)))
+                               }
                        } else {
                                // More than two fields: use memequal.
-                               conjuncts = append(conjuncts, eqmem(np, nq, newname(f.Sym), size))
+                               and(eqmem(np, nq, newname(f.Sym), size))
                        }
-                       f = next
+                       i = next
                }
 
-               var and *Node
-               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)
-                       }
+               if cond == nil {
+                       cond = Nodbool(true)
                }
 
                ret := Nod(ORETURN, nil, nil)
-               ret.List.Append(and)
+               ret.List.Append(cond)
                fn.Nbody.Append(ret)
        }
 
@@ -542,42 +545,41 @@ func eqmemfunc(size int64, t *Type) (fn *Node, needsize bool) {
 }
 
 // memrun finds runs of struct fields for which memory-only algs are appropriate.
-// t is the parent struct type, and start is the field that starts the run.
+// t is the parent struct type, and start is the field index at which to start the run.
+// The caller is responsible for providing t.FieldSlice() as fields.
 // size is the length in bytes of the memory included in the run.
-// next is the next field after the memory run.
-func memrun(t *Type, start *Type) (size int64, next *Type) {
-       var last *Type
+// next is the index just after the end of the memory run.
+// TODO(mdempsky): Eliminate fields parameter once struct fields are kept in slices.
+func memrun(t *Type, fields []*Type, start int) (size int64, next int) {
        next = start
        for {
-               last, next = next, next.Down
-               if next == nil {
+               next++
+               if next == len(fields) {
                        break
                }
                // Stop run after a padded field.
-               if ispaddedfield(t, last) {
+               if ispaddedfield(t, fields, next-1) {
                        break
                }
                // Also, stop before a blank or non-memory field.
-               if isblanksym(next.Sym) || algtype1(next.Type, nil) != AMEM {
+               if isblanksym(fields[next].Sym) || algtype1(fields[next].Type, nil) != AMEM {
                        break
                }
        }
-       end := last.Width + last.Type.Width
-       return end - start.Width, next
+       end := fields[next-1].Width + fields[next-1].Type.Width
+       return end - fields[start].Width, next
 }
 
-// ispaddedfield reports whether the given field f, assumed to be
-// a field in struct t, is followed by padding.
-func ispaddedfield(t *Type, f *Type) bool {
+// ispaddedfield reports whether the i'th field of struct type t is followed
+// by padding. The caller is responsible for providing t.FieldSlice() as fields.
+// TODO(mdempsky): Eliminate fields parameter once struct fields are kept in slices.
+func ispaddedfield(t *Type, fields []*Type, i int) bool {
        if t.Etype != TSTRUCT {
                Fatalf("ispaddedfield called non-struct %v", t)
        }
-       if f.Etype != TFIELD {
-               Fatalf("ispaddedfield called non-field %v", f)
-       }
        end := t.Width
-       if f.Down != nil {
-               end = f.Down.Width
+       if i+1 < len(fields) {
+               end = fields[i+1].Width
        }
-       return f.Width+f.Type.Width != end
+       return fields[i].Width+fields[i].Type.Width != end
 }