From 2d458b98a1018a51bb8e1ac36be19e7a8b061942 Mon Sep 17 00:00:00 2001 From: Todd Gruben Date: Tue, 20 Feb 2018 10:41:02 -0600 Subject: [PATCH] merge conflicts --- roaring/assembly.go | 68 ------------------ roaring/assembly_amd64.s | 122 ------------------------------- roaring/assembly_asm.go | 87 ---------------------- roaring/assembly_generic.go | 27 ------- roaring/assembly_test.go | 139 ------------------------------------ roaring/roaring.go | 129 ++++++++++++++++++--------------- 6 files changed, 73 insertions(+), 499 deletions(-) delete mode 100644 roaring/assembly.go delete mode 100644 roaring/assembly_amd64.s delete mode 100644 roaring/assembly_asm.go delete mode 100644 roaring/assembly_generic.go delete mode 100644 roaring/assembly_test.go diff --git a/roaring/assembly.go b/roaring/assembly.go deleted file mode 100644 index ea67cf66e..000000000 --- a/roaring/assembly.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2017 Pilosa Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package roaring - - -// bit population count, take from -// https://code.google.com/p/go/issues/detail?id=4988#c11 -// credit: https://code.google.com/u/arnehormann/ -func popcntGo(x uint64) (n uint64) { - x -= (x >> 1) & 0x5555555555555555 - x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 - x += x >> 4 - x &= 0x0f0f0f0f0f0f0f0f - x *= 0x0101010101010101 - return x >> 56 -} - -func popcntSliceGo(s []uint64) uint64 { - cnt := uint64(0) - for _, x := range s { - cnt += popcntGo(x) - } - return cnt -} - -func popcntMaskSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcntGo(s[i] &^ m[i]) - } - return cnt -} - -func popcntAndSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcntGo(s[i] & m[i]) - } - return cnt -} - -func popcntOrSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcntGo(s[i] | m[i]) - } - return cnt -} - -func popcntXorSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcntGo(s[i] ^ m[i]) - } - return cnt -} diff --git a/roaring/assembly_amd64.s b/roaring/assembly_amd64.s deleted file mode 100644 index 5b65e0635..000000000 --- a/roaring/assembly_amd64.s +++ /dev/null @@ -1,122 +0,0 @@ -#include "textflag.h" - -TEXT ·hasAsm(SB),4,$0-1 - MOVQ $1, AX - CPUID - SHRQ $23, CX - ANDQ $1, CX - MOVB CX, ret+0(FP) - RET - -TEXT ·POPCNTQ(SB),NOSPLIT,$0-16 - MOVQ memory+0(FP), BP - POPCNTQ BP, BX - MOVQ BX, ret+8(FP) - RET - -TEXT ·BSFQ(SB),NOSPLIT,$0-16 - MOVQ memory+0(FP), BP - BSFQ BP, BX - MOVQ BX, ret+8(FP) - RET - -#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2 - -TEXT ·popcntSliceAsm(SB),4,$0-32 -XORQ AX, AX -MOVQ s_base+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntSliceEnd -popcntSliceLoop: -BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX -ADDQ DX, AX -ADDQ $8, SI -LOOP popcntSliceLoop -popcntSliceEnd: -MOVQ AX, ret+24(FP) -RET - -TEXT ·popcntMaskSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s_base+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntMaskSliceEnd -MOVQ m+24(FP), DI -popcntMaskSliceLoop: -MOVQ (DI), DX -NOTQ DX -ANDQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntMaskSliceLoop -popcntMaskSliceEnd: -MOVQ AX, ret+48(FP) -RET - -TEXT ·popcntAndSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s_base+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntAndSliceEnd -MOVQ m+24(FP), DI -popcntAndSliceLoop: -MOVQ (DI), DX -ANDQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntAndSliceLoop -popcntAndSliceEnd: -MOVQ AX, ret+48(FP) -RET - -TEXT ·popcntOrSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s_base+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntOrSliceEnd -MOVQ m+24(FP), DI -popcntOrSliceLoop: -MOVQ (DI), DX -ORQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntOrSliceLoop -popcntOrSliceEnd: -MOVQ AX, ret+48(FP) -RET - -TEXT ·popcntXorSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s_base+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntXorSliceEnd -MOVQ m+24(FP), DI -popcntXorSliceLoop: -MOVQ (DI), DX -XORQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntXorSliceLoop -popcntXorSliceEnd: -MOVQ AX, ret+48(FP) -RET - - -TEXT ·popcntAsm(SB),4,$0-16 - MOVQ x+0(FP), DX - POPCNTQ_DX_DX - MOVQ DX, ret+8(FP) - RET diff --git a/roaring/assembly_asm.go b/roaring/assembly_asm.go deleted file mode 100644 index 3eb182cce..000000000 --- a/roaring/assembly_asm.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2017 Pilosa Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build amd64 - -package roaring - -func hasAsm() bool - -func BSFQ(memory uint64) int - -func POPCNTQ(memory uint64) int - - -//go:noescape -var useAsm = hasAsm() - -//go:noescape -func popcntSliceAsm(s []uint64) uint64 - -//go:noescape -func popcntMaskSliceAsm(s, m []uint64) uint64 - -//go:noescape -func popcntAndSliceAsm(s, m []uint64) uint64 - -//go:noescape -func popcntOrSliceAsm(s, m []uint64) uint64 - -//go:noescape -func popcntXorSliceAsm(s, m []uint64) uint64 - -//go:noescape -func popcntAsm(x uint64) uint64 - -func popcntSlice(s []uint64) uint64 { - if useAsm { - return popcntSliceAsm(s) - } - return popcntSliceGo(s) -} - -func popcntMaskSlice(s, m []uint64) uint64 { - if useAsm { - return popcntMaskSliceAsm(s, m) - } - return popcntMaskSliceGo(s, m) -} - -func popcntAndSlice(s, m []uint64) uint64 { - if useAsm { - return popcntAndSliceAsm(s, m) - } - return popcntAndSliceGo(s, m) -} - -func popcntOrSlice(s, m []uint64) uint64 { - if useAsm { - return popcntOrSliceAsm(s, m) - } - return popcntOrSliceGo(s, m) -} - -func popcntXorSlice(s, m []uint64) uint64 { - if useAsm { - return popcntXorSliceAsm(s, m) - } - return popcntXorSliceGo(s, m) -} - -func popcnt(x uint64) uint64 { - if useAsm { - return popcntAsm(x) - } - return popcntGo(x) -} diff --git a/roaring/assembly_generic.go b/roaring/assembly_generic.go deleted file mode 100644 index 997bfdaa3..000000000 --- a/roaring/assembly_generic.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017 Pilosa Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !amd64 - -package roaring - -func hasAsm() bool {return false} - - -func popcntSlice(s []uint64) uint64 { return popcntSliceGo(s) } -func popcntMaskSlice(s, m []uint64) uint64 { return popcntMaskSliceGo(s, m) } -func popcntAndSlice(s, m []uint64) uint64 { return popcntAndSliceGo(s, m) } -func popcntOrSlice(s, m []uint64) uint64 { return popcntOrSliceGo(s, m) } -func popcntXorSlice(s, m []uint64) uint64 { return popcntXorSliceGo(s, m) } -func popcnt(s uint64) uint64 { return popcntGo(s) } diff --git a/roaring/assembly_test.go b/roaring/assembly_test.go deleted file mode 100644 index f18aa65ec..000000000 --- a/roaring/assembly_test.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2017 Pilosa Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package roaring - -import "testing" - -func TestBSFQ(t *testing.T) { - result := BSFQ(2) - if result != 1 { - t.Fatalf("BSF INCORRECT: %d", result) - } -} - -func TestBSFQ_CompareGo(t *testing.T) { - v := uint64(1) - for i := 0; i < 64; i++ { - if BSFQ(v) != trailingZeroN(v) { - t.Fatalf("BSF INCORRECT: %d %d", BSFQ(v), trailingZeroN(v)) - } - if v == 0 { - v = 1 - } else { - v *= 2 - } - } - /* - if bsfq(0) != trailingZeroN(0) { - fmt.Println(bsfq(0)) - t.Fatalf("BSF INCORRECT") - } - */ -} -func BenchmarkBSF(b *testing.B) { - for i := 0; i < b.N; i++ { - BSFQ(uint64(i)) - } -} - -func BenchmarkTrailingZeroN(b *testing.B) { - for i := 0; i < b.N; i++ { - trailingZeroN(uint64(i)) - } -} - -func BenchmarkPOPCNTQ(b *testing.B) { - for i := 0; i < b.N; i++ { - POPCNTQ(uint64(i)) - } -} - -func BenchmarkPopcount(b *testing.B) { - for i := 0; i < b.N; i++ { - popcount(uint64(i)) - } -} - -func BenchmarkPopcntAsm(b *testing.B) { - // run the Fib function b.N times - for n := 0; n < b.N; n++ { - popcntAsm(0xdeadbeef) - } -} - -func BenchmarkPopcntGo(b *testing.B) { - // run the Fib function b.N times - for n := 0; n < b.N; n++ { - popcntGo(0xdeadbeef) - } -} - -func getData() []uint64 { - return []uint64{ - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - 0xdeadbeef, - } -} - -func BenchmarkPopcntSliceGo(b *testing.B) { - d := getData() - for n := 0; n < b.N; n++ { - popcntSliceGo(d) - } -} - -func BenchmarkPopcntSliceAsm(b *testing.B) { - d := getData() - for n := 0; n < b.N; n++ { - popcntSliceAsm(d) - } -} - -func BenchmarkPopcntSlice(b *testing.B) { - d := getData() - for n := 0; n < b.N; n++ { - popcntSlice(d) - } -} diff --git a/roaring/roaring.go b/roaring/roaring.go index 8d88b2088..8ea82af83 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -21,6 +21,7 @@ import ( "fmt" "hash/fnv" "io" + "math/bits" "sort" "unsafe" ) @@ -1274,10 +1275,10 @@ func (c *container) contains(v uint16) bool { func (c *container) bitmapCountRuns() (r int) { for i := 0; i < 1023; i++ { v, v1 := c.bitmap[i], c.bitmap[i+1] - r = r + int(popcnt((v<<1)&^v)+((v>>63)&^v1)) + r = r + int(popcount((v<<1)&^v)+((v>>63)&^v1)) } vl := c.bitmap[len(c.bitmap)-1] - r = r + int(popcnt((vl<<1)&^vl)+vl>>63) + r = r + int(popcount((vl<<1)&^vl)+vl>>63) return r } @@ -1918,7 +1919,7 @@ func intersectionCountArrayBitmap(a, b *container) (n int) { } func intersectionCountBitmapBitmap(a, b *container) (n int) { - return int(popcntAndSlice(a.bitmap, b.bitmap)) + return int(popcountAndSlice(a.bitmap, b.bitmap)) } func intersect(a, b *container) *container { @@ -2061,22 +2062,22 @@ func intersectBitmapRun(a, b *container) *container { for valast >= vb.start && vastart <= vb.last && i < bitmapN { if vastart >= vb.start && valast <= vb.last { // a within b output.bitmap[i] = a.bitmap[i] - output.n += int(popcnt(a.bitmap[i])) + output.n += int(popcount(a.bitmap[i])) } else if vb.start >= vastart && vb.last <= valast { // b within a var mask uint64 = ((1 << (vb.last - vb.start + 1)) - 1) << (vb.start - vastart) bits := a.bitmap[i] & mask output.bitmap[i] |= bits - output.n += int(popcnt(bits)) + output.n += int(popcount(bits)) } else if vastart < vb.start { // a overlaps front of b offset := 64 - (1 + valast - vb.start) bits := (a.bitmap[i] >> offset) << offset output.bitmap[i] |= bits - output.n += int(popcnt(bits)) + output.n += int(popcount(bits)) } else if vb.start < vastart { // b overlaps front of a offset := 64 - (1 + vb.last - vastart) bits := (a.bitmap[i] << offset) >> offset output.bitmap[i] |= bits - output.n += int(popcnt(bits)) + output.n += int(popcount(bits)) } // update loop vars i++ @@ -2293,19 +2294,19 @@ func (c *container) bitmapSetRange(i, j uint64) { y := (j - 1) >> 6 var X uint64 = maxBitmap << (i % 64) var Y uint64 = maxBitmap >> (63 - ((j - 1) % 64)) - xcnt := popcnt(X) - ycnt := popcnt(Y) + xcnt := popcount(X) + ycnt := popcount(Y) if x == y { - c.n += int((j - i) - popcnt(c.bitmap[x]&(X&Y))) + c.n += int((j - i) - popcount(c.bitmap[x]&(X&Y))) c.bitmap[x] |= (X & Y) } else { - c.n += int(xcnt - popcnt(c.bitmap[x]&X)) + c.n += int(xcnt - popcount(c.bitmap[x]&X)) c.bitmap[x] |= X for i := x + 1; i < y; i++ { - c.n += int(64 - popcnt(c.bitmap[i])) + c.n += int(64 - popcount(c.bitmap[i])) c.bitmap[i] = maxBitmap } - c.n += int(ycnt - popcnt(c.bitmap[y]&Y)) + c.n += int(ycnt - popcount(c.bitmap[y]&Y)) c.bitmap[y] |= Y } } @@ -2317,21 +2318,21 @@ func (c *container) bitmapXorRange(i, j uint64) { var X uint64 = maxBitmap << (i % 64) var Y uint64 = maxBitmap >> (63 - ((j - 1) % 64)) if x == y { - cnt := popcnt(c.bitmap[x]) + cnt := popcount(c.bitmap[x]) c.bitmap[x] ^= (X & Y) //// flip - c.n += int(popcnt(c.bitmap[x]) - cnt) + c.n += int(popcount(c.bitmap[x]) - cnt) } else { - cnt := popcnt(c.bitmap[x]) + cnt := popcount(c.bitmap[x]) c.bitmap[x] ^= X - c.n += int(popcnt(c.bitmap[x]) - cnt) + c.n += int(popcount(c.bitmap[x]) - cnt) for i := x + 1; i < y; i++ { - cnt = popcnt(c.bitmap[i]) + cnt = popcount(c.bitmap[i]) c.bitmap[i] ^= maxBitmap - c.n += int(popcnt(c.bitmap[i]) - cnt) + c.n += int(popcount(c.bitmap[i]) - cnt) } - cnt = popcnt(c.bitmap[y]) + cnt = popcount(c.bitmap[y]) c.bitmap[y] ^= Y - c.n += int(popcnt(c.bitmap[y]) - cnt) + c.n += int(popcount(c.bitmap[y]) - cnt) } } @@ -2342,16 +2343,16 @@ func (c *container) bitmapZeroRange(i, j uint64) { var X uint64 = maxBitmap << (i % 64) var Y uint64 = maxBitmap >> (63 - ((j - 1) % 64)) if x == y { - c.n -= int(popcnt(c.bitmap[x] & (X & Y))) + c.n -= int(popcount(c.bitmap[x] & (X & Y))) c.bitmap[x] &= ^(X & Y) } else { - c.n -= int(popcnt(c.bitmap[x] & X)) + c.n -= int(popcount(c.bitmap[x] & X)) c.bitmap[x] &= ^X for i := x + 1; i < y; i++ { - c.n -= int(popcnt(c.bitmap[i])) + c.n -= int(popcount(c.bitmap[i])) c.bitmap[i] = 0 } - c.n -= int(popcnt(c.bitmap[y] & Y)) + c.n -= int(popcount(c.bitmap[y] & Y)) c.bitmap[y] &= ^Y } } @@ -2376,7 +2377,7 @@ func unionBitmapBitmap(a, b *container) *container { for i := 0; i < bitmapN; i++ { v := a.bitmap[i] | b.bitmap[i] output.bitmap[i] = v - output.n += int(popcnt(v)) + output.n += int(popcount(v)) } return output @@ -2812,7 +2813,7 @@ func xorBitmapBitmap(a, b *container) *container { for i := 0; i < bitmapN; i++ { v := a.bitmap[i] ^ b.bitmap[i] output.bitmap[i] = v - output.n += int(popcnt(v)) + output.n += int(popcount(v)) } if output.count() < ArrayMaxSize { @@ -2975,35 +2976,7 @@ func search64(a []uint64, value uint64) int { // trailingZeroN returns the number of trailing zeros in v. // v must be greater than zero. func trailingZeroN(v uint64) int { - n := int64(63) - if y := v << 32; y != 0 { - n, v = n-32, y - } - if y := v << 16; y != 0 { - n, v = n-16, y - } - if y := v << 8; y != 0 { - n, v = n-8, y - } - if y := v << 4; y != 0 { - n, v = n-4, y - } - if y := v << 2; y != 0 { - n, v = n-2, y - } - return int(n - int64(v<<1>>63)) -} - -// bit population count, taken from -// https://code.google.com/p/go/issues/detail?id=4988#c11 -// credit: https://code.google.com/u/arnehormann/ -func popcount(x uint64) (n uint64) { - x -= (x >> 1) & 0x5555555555555555 - x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 - x += x >> 4 - x &= 0x0f0f0f0f0f0f0f0f - x *= 0x0101010101010101 - return x >> 56 + return bits.TrailingZeros64(v) } // ErrorList represents a list of errors. @@ -3265,3 +3238,47 @@ func xorBitmapRun(a, b *container) *container { } return output } + +func popcount(x uint64) uint64 { + return uint64(bits.OnesCount64(x)) +} + +func popcountSlice(s []uint64) uint64 { + cnt := uint64(0) + for _, x := range s { + cnt += popcount(x) + } + return cnt +} + +func popcountMaskSlice(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] &^ m[i]) + } + return cnt +} + +func popcountAndSlice(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] & m[i]) + } + return cnt +} + +func popcountOrSlice(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] | m[i]) + } + return cnt +} + +func popcountXorSlice(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] ^ m[i]) + } + return cnt +}