mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
When the number of variables in a function is very large, liveness analysis gets less efficient, since every bit vector is O(number of variables). Improve the situation by returning a sparse representation from progeffects. In all scenarios, progeffects either returns a slice that is shared function-wide, and which is usually small, or a slice that is guaranteed to have at most three values. Reduces compilation time for the code in #8225 Comment 1 by ~10%. Minor effects on regular packages (below). Passes toolstash -cmp. Updates #8225 name old time/op new time/op delta Template 215ms ± 2% 212ms ± 4% -1.31% (p=0.001 n=30+30) Unicode 98.3ms ± 3% 98.4ms ± 5% ~ (p=0.971 n=30+30) GoTypes 657ms ± 3% 651ms ± 2% -0.98% (p=0.001 n=30+27) Compiler 2.78s ± 2% 2.77s ± 2% -0.60% (p=0.006 n=30+30) Flate 130ms ± 4% 130ms ± 4% ~ (p=0.712 n=29+30) GoParser 159ms ± 5% 158ms ± 3% ~ (p=0.331 n=29+30) Reflect 406ms ± 3% 404ms ± 3% -0.69% (p=0.041 n=29+30) Tar 117ms ± 4% 117ms ± 3% ~ (p=0.886 n=30+29) XML 219ms ± 2% 217ms ± 2% ~ (p=0.091 n=29+24) name old user-ns/op new user-ns/op delta Template 272user-ms ± 3% 270user-ms ± 3% -1.03% (p=0.004 n=30+30) Unicode 138user-ms ± 2% 138user-ms ± 3% ~ (p=0.902 n=29+29) GoTypes 891user-ms ± 2% 883user-ms ± 2% -0.95% (p=0.000 n=29+29) Compiler 3.85user-s ± 2% 3.84user-s ± 2% ~ (p=0.236 n=30+30) Flate 167user-ms ± 2% 166user-ms ± 4% ~ (p=0.511 n=28+30) GoParser 211user-ms ± 4% 210user-ms ± 3% ~ (p=0.287 n=29+30) Reflect 539user-ms ± 3% 536user-ms ± 2% -0.59% (p=0.034 n=29+30) Tar 154user-ms ± 3% 155user-ms ± 4% ~ (p=0.786 n=30+30) XML 289user-ms ± 3% 288user-ms ± 4% ~ (p=0.249 n=30+26) name old alloc/op new alloc/op delta Template 40.7MB ± 0% 40.8MB ± 0% +0.09% (p=0.001 n=30+30) Unicode 30.8MB ± 0% 30.8MB ± 0% ~ (p=0.112 n=30+30) GoTypes 123MB ± 0% 124MB ± 0% +0.09% (p=0.000 n=30+30) Compiler 473MB ± 0% 473MB ± 0% +0.05% (p=0.000 n=30+30) Flate 26.5MB ± 0% 26.5MB ± 0% ~ (p=0.186 n=29+30) GoParser 32.3MB ± 0% 32.4MB ± 0% +0.07% (p=0.021 n=28+30) Reflect 84.4MB ± 0% 84.6MB ± 0% +0.21% (p=0.000 n=30+30) Tar 27.3MB ± 0% 27.3MB ± 0% +0.09% (p=0.010 n=30+28) XML 44.7MB ± 0% 44.7MB ± 0% +0.07% (p=0.002 n=30+30) name old allocs/op new allocs/op delta Template 401k ± 1% 400k ± 1% ~ (p=0.321 n=30+30) Unicode 331k ± 1% 331k ± 1% ~ (p=0.357 n=30+28) GoTypes 1.24M ± 0% 1.24M ± 1% -0.19% (p=0.001 n=30+30) Compiler 4.27M ± 0% 4.27M ± 0% -0.13% (p=0.000 n=30+30) Flate 252k ± 1% 251k ± 1% -0.30% (p=0.005 n=30+30) GoParser 325k ± 1% 325k ± 1% ~ (p=0.224 n=28+30) Reflect 1.06M ± 0% 1.05M ± 0% -0.34% (p=0.000 n=30+30) Tar 266k ± 1% 266k ± 1% ~ (p=0.333 n=30+30) XML 416k ± 1% 415k ± 1% ~ (p=0.144 n=30+29) Change-Id: I6ba67a9203516373062a2618122306da73333d98 Reviewed-on: https://go-review.googlesource.com/36211 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
171 lines
3.1 KiB
Go
171 lines
3.1 KiB
Go
// 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
|
|
|
|
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
|
|
return bulkBvec{
|
|
words: make([]uint32, nword*count),
|
|
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)
|
|
|
|
for w&1 == 0 {
|
|
w >>= 1
|
|
i++
|
|
}
|
|
|
|
return i
|
|
}
|
|
|
|
func (bv bvec) IsEmpty() bool {
|
|
for i := int32(0); i < bv.n; i += WORDBITS {
|
|
if bv.b[i>>WORDSHIFT] != 0 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (bv bvec) Not() {
|
|
i := int32(0)
|
|
w := int32(0)
|
|
for ; i < bv.n; i, w = i+WORDBITS, w+1 {
|
|
bv.b[w] = ^bv.b[w]
|
|
}
|
|
}
|
|
|
|
// union
|
|
func (dst bvec) Or(src1, src2 bvec) {
|
|
for i, x := range src1.b {
|
|
dst.b[i] = x | src2.b[i]
|
|
}
|
|
}
|
|
|
|
// intersection
|
|
func (dst bvec) And(src1, src2 bvec) {
|
|
for i, x := range src1.b {
|
|
dst.b[i] = x & src2.b[i]
|
|
}
|
|
}
|
|
|
|
// difference
|
|
func (dst bvec) AndNot(src1, src2 bvec) {
|
|
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
|
|
}
|
|
}
|