]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: abstract bvec sets
authorAustin Clements <austin@google.com>
Thu, 19 Apr 2018 19:56:19 +0000 (15:56 -0400)
committerAustin Clements <austin@google.com>
Tue, 22 May 2018 20:44:02 +0000 (20:44 +0000)
This moves the bvec hash table logic out of Liveness.compact and into
a bvecSet type. Furthermore, the bvecSet type has the ability to grow
dynamically, which the current implementation doesn't. In addition to
making the code cleaner, this will make it possible to incrementally
compact liveness bitmaps.

Passes toolstash -cmp

Updates #24543.

Change-Id: I46c53e504494206061a1f790ae4a02d768a65681
Reviewed-on: https://go-review.googlesource.com/110176
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/gc/bv.go
src/cmd/compile/internal/gc/plive.go

index db0185e5a804dee5105e28d81dc4e90d26b8875d..7f5a432249c8a4b364d3bf58f75a48b1ad0d21f7 100644 (file)
@@ -201,3 +201,98 @@ func (bv bvec) Clear() {
                bv.b[i] = 0
        }
 }
+
+// FNV-1 hash function constants.
+const (
+       H0 = 2166136261
+       Hp = 16777619
+)
+
+func hashbitmap(h uint32, bv bvec) uint32 {
+       n := int((bv.n + 31) / 32)
+       for i := 0; i < n; i++ {
+               w := bv.b[i]
+               h = (h * Hp) ^ (w & 0xff)
+               h = (h * Hp) ^ ((w >> 8) & 0xff)
+               h = (h * Hp) ^ ((w >> 16) & 0xff)
+               h = (h * Hp) ^ ((w >> 24) & 0xff)
+       }
+
+       return h
+}
+
+// bvecSet is a set of bvecs, in initial insertion order.
+type bvecSet struct {
+       index []int  // hash -> uniq index. -1 indicates empty slot.
+       uniq  []bvec // unique bvecs, in insertion order
+}
+
+func newBvecSet(size int) bvecSet {
+       // bvecSet is a linear probing hash table.
+       // The hash table has 4n entries to keep the linear
+       // scan short.
+       index := make([]int, size*4)
+       for i := range index {
+               index[i] = -1
+       }
+       return bvecSet{index, nil}
+}
+
+func (m *bvecSet) grow() {
+       // Allocate new index.
+       n := len(m.index) * 2
+       if n == 0 {
+               n = 32
+       }
+       newIndex := make([]int, n)
+       for i := range newIndex {
+               newIndex[i] = -1
+       }
+
+       // Rehash into newIndex.
+       for i, bv := range m.uniq {
+               h := hashbitmap(H0, bv) % uint32(len(newIndex))
+               for {
+                       j := newIndex[h]
+                       if j < 0 {
+                               newIndex[h] = i
+                               break
+                       }
+                       h++
+                       if h == uint32(len(newIndex)) {
+                               h = 0
+                       }
+               }
+       }
+       m.index = newIndex
+}
+
+// add adds bv to the set and returns its index in m.uniq.
+// The caller must not modify bv after this.
+func (m *bvecSet) add(bv bvec) int {
+       if len(m.uniq)*4 >= len(m.index) {
+               m.grow()
+       }
+
+       index := m.index
+       h := hashbitmap(H0, bv) % uint32(len(index))
+       for {
+               j := index[h]
+               if j < 0 {
+                       // New bvec.
+                       index[h] = len(m.uniq)
+                       m.uniq = append(m.uniq, bv)
+                       return len(m.uniq) - 1
+               }
+               jlive := m.uniq[j]
+               if bv.Eq(jlive) {
+                       // Existing bvec.
+                       return j
+               }
+
+               h++
+               if h == uint32(len(index)) {
+                       h = 0
+               }
+       }
+}
index 47bc1a98a516381c9fb72b3802ebaa3c779bba85..f63530235fe4e70927c0a371c2741c6335f31b3f 100644 (file)
@@ -1292,25 +1292,6 @@ func (lv *Liveness) avarinitanyall(b *ssa.Block, any, all bvec) {
        }
 }
 
-// FNV-1 hash function constants.
-const (
-       H0 = 2166136261
-       Hp = 16777619
-)
-
-func hashbitmap(h uint32, bv bvec) uint32 {
-       n := int((bv.n + 31) / 32)
-       for i := 0; i < n; i++ {
-               w := bv.b[i]
-               h = (h * Hp) ^ (w & 0xff)
-               h = (h * Hp) ^ ((w >> 8) & 0xff)
-               h = (h * Hp) ^ ((w >> 16) & 0xff)
-               h = (h * Hp) ^ ((w >> 24) & 0xff)
-       }
-
-       return h
-}
-
 // Compact liveness information by coalescing identical per-call-site bitmaps.
 // The merging only happens for a single function, not across the entire binary.
 //
@@ -1326,53 +1307,14 @@ func hashbitmap(h uint32, bv bvec) uint32 {
 // PCDATA tables cost about 100k. So for now we keep using a single index for
 // both bitmap lists.
 func (lv *Liveness) compact() {
-       // Linear probing hash table of bitmaps seen so far.
-       // The hash table has 4n entries to keep the linear
-       // scan short. An entry of -1 indicates an empty slot.
-       n := len(lv.livevars)
-
-       tablesize := 4 * n
-       table := make([]int, tablesize)
-       for i := range table {
-               table[i] = -1
-       }
-
-       // remap[i] = the new index of the old bit vector #i.
-       remap := make([]int, n)
-       for i := range remap {
-               remap[i] = -1
-       }
-
-       // Consider bit vectors in turn.
-       // If new, assign next number using uniq,
-       // record in remap, record in lv.livevars
-       // under the new index, and add entry to hash table.
-       // If already seen, record earlier index in remap.
-Outer:
+       // Compact livevars.
+       // remap[i] = the index in lv.stackMaps of for bitmap lv.livevars[i].
+       remap := make([]int, len(lv.livevars))
+       set := newBvecSet(len(lv.livevars))
        for i, live := range lv.livevars {
-               h := hashbitmap(H0, live.vars) % uint32(tablesize)
-
-               for {
-                       j := table[h]
-                       if j < 0 {
-                               break
-                       }
-                       jlive := lv.stackMaps[j]
-                       if live.vars.Eq(jlive) {
-                               remap[i] = j
-                               continue Outer
-                       }
-
-                       h++
-                       if h == uint32(tablesize) {
-                               h = 0
-                       }
-               }
-
-               table[h] = len(lv.stackMaps)
-               remap[i] = len(lv.stackMaps)
-               lv.stackMaps = append(lv.stackMaps, live.vars)
+               remap[i] = set.add(live.vars)
        }
+       lv.stackMaps = set.uniq
 
        // Compact register maps.
        remapRegs := make([]int, len(lv.livevars))