diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/bv.go')
-rw-r--r-- | src/cmd/compile/internal/gc/bv.go | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/gc/bv.go b/src/cmd/compile/internal/gc/bv.go new file mode 100644 index 0000000..e32ab97 --- /dev/null +++ b/src/cmd/compile/internal/gc/bv.go @@ -0,0 +1,278 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gc + +import ( + "math/bits" +) + +const ( + wordBits = 32 + wordMask = wordBits - 1 + wordShift = 5 +) + +// A bvec is a bit vector. +type bvec struct { + n int32 // number of bits in vector + b []uint32 // words holding bits +} + +func bvalloc(n int32) bvec { + nword := (n + wordBits - 1) / wordBits + return bvec{n, make([]uint32, nword)} +} + +type bulkBvec struct { + words []uint32 + nbit int32 + nword int32 +} + +func bvbulkalloc(nbit int32, count int32) bulkBvec { + nword := (nbit + wordBits - 1) / wordBits + size := int64(nword) * int64(count) + if int64(int32(size*4)) != size*4 { + Fatalf("bvbulkalloc too big: nbit=%d count=%d nword=%d size=%d", nbit, count, nword, size) + } + return bulkBvec{ + words: make([]uint32, size), + nbit: nbit, + nword: nword, + } +} + +func (b *bulkBvec) next() bvec { + out := bvec{b.nbit, b.words[:b.nword]} + b.words = b.words[b.nword:] + return out +} + +func (bv1 bvec) Eq(bv2 bvec) bool { + if bv1.n != bv2.n { + Fatalf("bvequal: lengths %d and %d are not equal", bv1.n, bv2.n) + } + for i, x := range bv1.b { + if x != bv2.b[i] { + return false + } + } + return true +} + +func (dst bvec) Copy(src bvec) { + copy(dst.b, src.b) +} + +func (bv bvec) Get(i int32) bool { + if i < 0 || i >= bv.n { + Fatalf("bvget: index %d is out of bounds with length %d\n", i, bv.n) + } + mask := uint32(1 << uint(i%wordBits)) + return bv.b[i>>wordShift]&mask != 0 +} + +func (bv bvec) Set(i int32) { + if i < 0 || i >= bv.n { + Fatalf("bvset: index %d is out of bounds with length %d\n", i, bv.n) + } + mask := uint32(1 << uint(i%wordBits)) + bv.b[i/wordBits] |= mask +} + +func (bv bvec) Unset(i int32) { + if i < 0 || i >= bv.n { + Fatalf("bvunset: index %d is out of bounds with length %d\n", i, bv.n) + } + mask := uint32(1 << uint(i%wordBits)) + bv.b[i/wordBits] &^= mask +} + +// bvnext returns the smallest index >= i for which bvget(bv, i) == 1. +// If there is no such index, bvnext returns -1. +func (bv bvec) Next(i int32) int32 { + if i >= bv.n { + return -1 + } + + // Jump i ahead to next word with bits. + if bv.b[i>>wordShift]>>uint(i&wordMask) == 0 { + i &^= wordMask + i += wordBits + for i < bv.n && bv.b[i>>wordShift] == 0 { + i += wordBits + } + } + + if i >= bv.n { + return -1 + } + + // Find 1 bit. + w := bv.b[i>>wordShift] >> uint(i&wordMask) + i += int32(bits.TrailingZeros32(w)) + + return i +} + +func (bv bvec) IsEmpty() bool { + for _, x := range bv.b { + if x != 0 { + return false + } + } + return true +} + +func (bv bvec) Not() { + for i, x := range bv.b { + bv.b[i] = ^x + } +} + +// union +func (dst bvec) Or(src1, src2 bvec) { + if len(src1.b) == 0 { + return + } + _, _ = dst.b[len(src1.b)-1], src2.b[len(src1.b)-1] // hoist bounds checks out of the loop + + for i, x := range src1.b { + dst.b[i] = x | src2.b[i] + } +} + +// intersection +func (dst bvec) And(src1, src2 bvec) { + if len(src1.b) == 0 { + return + } + _, _ = dst.b[len(src1.b)-1], src2.b[len(src1.b)-1] // hoist bounds checks out of the loop + + for i, x := range src1.b { + dst.b[i] = x & src2.b[i] + } +} + +// difference +func (dst bvec) AndNot(src1, src2 bvec) { + if len(src1.b) == 0 { + return + } + _, _ = dst.b[len(src1.b)-1], src2.b[len(src1.b)-1] // hoist bounds checks out of the loop + + for i, x := range src1.b { + dst.b[i] = x &^ src2.b[i] + } +} + +func (bv bvec) String() string { + s := make([]byte, 2+bv.n) + copy(s, "#*") + for i := int32(0); i < bv.n; i++ { + ch := byte('0') + if bv.Get(i) { + ch = '1' + } + s[2+i] = ch + } + return string(s) +} + +func (bv bvec) Clear() { + for i := range bv.b { + 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 (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.extractUniqe. +// 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 + } + } +} + +// extractUniqe returns this slice of unique bit vectors in m, as +// indexed by the result of bvecSet.add. +func (m *bvecSet) extractUniqe() []bvec { + return m.uniq +} |