Fix Or/Xor dropping bits when combining bitmaps of different lengths (#51)
* fix: union/xor of different-sized bitmaps drops bits in variadic path Or and Xor with extra bitmaps used _or_many/_xor_many, which apply a single word count to every input. The count came from pointersOf, whose length is the maximum over the extra slice only and ignores other, so a longer other lost its tail words. More generally a uniform count cannot combine operands of different lengths: a longer source is truncated and a shorter one is read past its end. Fold each source in with the single-operand SIMD primitive over its own length, matching the scalar reference in simd_generic.go. Fixes the amd64 accelerated and AVX-512 branches and the arm64 branch. * Keep the _many primitives for equal-sized operands, fold only ragged ones * test: cover longer ragged bitmap extras --------- Co-authored-by: Roman <roman.atachiants@gmail.com>
This commit is contained in:
1 parent
58b05bdfdd
commit
47698fd8b9
4 files changed
+146
-12
No files matched your search
+28
-8
@@ -83,16 +83,26 @@ func (dst *Bitmap) Or(other Bitmap, extra ...Bitmap) {
|
||||
case 0:
|
||||
_or(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
|
||||
default:
|
||||
vx, max := pointersOf(other, extra)
|
||||
_or_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
|
||||
// _or_many applies one word count to every input, so it only fits
|
||||
// sources that share a length; ragged ones are folded in one by one.
|
||||
if n := uniformLen(other, extra); n > 0 {
|
||||
vx, _ := pointersOf(other, extra)
|
||||
_or_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(n, len(extra)+1))
|
||||
} else {
|
||||
foldEach(dst, _or, other, extra)
|
||||
}
|
||||
}
|
||||
case isAVX512:
|
||||
switch len(extra) {
|
||||
case 0:
|
||||
_or_avx512(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
|
||||
default:
|
||||
vx, max := pointersOf(other, extra)
|
||||
_or_many_avx512(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
|
||||
if n := uniformLen(other, extra); n > 0 {
|
||||
vx, _ := pointersOf(other, extra)
|
||||
_or_many_avx512(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(n, len(extra)+1))
|
||||
} else {
|
||||
foldEach(dst, _or_avx512, other, extra)
|
||||
}
|
||||
}
|
||||
default:
|
||||
or(*dst, other, extra)
|
||||
@@ -113,16 +123,26 @@ func (dst *Bitmap) Xor(other Bitmap, extra ...Bitmap) {
|
||||
case 0:
|
||||
_xor(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
|
||||
default:
|
||||
vx, max := pointersOf(other, extra)
|
||||
_xor_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
|
||||
// _xor_many applies one word count to every input, so it only fits
|
||||
// sources that share a length; ragged ones are folded in one by one.
|
||||
if n := uniformLen(other, extra); n > 0 {
|
||||
vx, _ := pointersOf(other, extra)
|
||||
_xor_many(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(n, len(extra)+1))
|
||||
} else {
|
||||
foldEach(dst, _xor, other, extra)
|
||||
}
|
||||
}
|
||||
case isAVX512:
|
||||
switch len(extra) {
|
||||
case 0:
|
||||
_xor_avx512(unsafe.Pointer(&(*dst)[0]), unsafe.Pointer(&other[0]), uint64(len(other)))
|
||||
default:
|
||||
vx, max := pointersOf(other, extra)
|
||||
_xor_many_avx512(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(max, len(extra)+1))
|
||||
if n := uniformLen(other, extra); n > 0 {
|
||||
vx, _ := pointersOf(other, extra)
|
||||
_xor_many_avx512(unsafe.Pointer(&(*dst)[0]), vx, dimensionsOf(n, len(extra)+1))
|
||||
} else {
|
||||
foldEach(dst, _xor_avx512, other, extra)
|
||||
}
|
||||
}
|
||||
default:
|
||||
xor(*dst, other, extra)
|
||||
|
||||
Reference in new issue
Block a user