Commit 3c4aaf8a authored by Austin Clements's avatar Austin Clements

cmd/compile: abstract bvec sets

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: 's avatarKeith Randall <khr@golang.org>
parent 577c05ca
......@@ -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
}
}
}
......@@ -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))
......
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