Skip to content

Commit

Permalink
BitSet.Exclusive is now vectorized.
Browse files Browse the repository at this point in the history
  • Loading branch information
genaray committed Sep 14, 2023
1 parent b1a2ccc commit a3225f8
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 16 deletions.
48 changes: 45 additions & 3 deletions src/Arch.Tests/BitSetTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,58 @@ public void BitsetNone(int[] values, int multiplier)
That(allResult, Is.EqualTo(false));
}

/// <summary>
/// Checks <see cref="BitSet"/> exclusive.
/// <param name="values">The values being set or cleared.</param>
/// <param name="multiplier">The multiplier for the passed values. Mainly for vectorization-testing to increase the set bits.</param>
/// </summary>
[Test]
[TestCase(new []{5,6,25}, 1)]
[TestCase(new []{5,6,25}, 100)]
public void BitsetExclusive(int[] values, int multiplier)
{
var bitSet1 = new BitSet();
bitSet1.SetBit(values[0] * multiplier);
bitSet1.SetBit(values[1] * multiplier);
var bitSet2 = new BitSet();
bitSet2.SetBit(values[0] * multiplier);
bitSet2.SetBit(values[1] * multiplier);

// Both are totally equal
var exclusive = bitSet2.Exclusive(bitSet1);
That(exclusive, Is.EqualTo(true));

// Bitset2 is not equal anymore
bitSet2.SetBit(values[2] * multiplier);
exclusive = bitSet2.Exclusive(bitSet1);
That(exclusive, Is.EqualTo(false));

// Bitset2 is back to default, but bitset1 is now different -> both differ, should be false
bitSet2.ClearBit(values[2] * multiplier);
bitSet1.SetBit(values[2] * multiplier);
exclusive = bitSet2.Exclusive(bitSet1);
That(exclusive, Is.EqualTo(false));

// Bitset2 is now the same as bitset 1 -> should be true
bitSet2.SetBit(values[2] * multiplier);
exclusive = bitSet2.Exclusive(bitSet1);
That(exclusive, Is.EqualTo(true));
}

/// <summary>
/// Checks whether different sized <see cref="BitSet"/>'s work correctly.
/// <param name="values">The values being set or cleared.</param>
/// <param name="multiplier">The multiplier for the passed values. Mainly for vectorization-testing to increase the set bits.</param>
/// </summary>
[Test]
public void AllWithDifferentLengthBitSet()
[TestCase(new []{5,33}, 1)]
[TestCase(new []{5,33}, 100)]
public void AllWithDifferentLengthBitSet(int[] values, int multiplier)
{
var bitSet1 = new BitSet();
bitSet1.SetBit(5);
bitSet1.SetBit(values[0] * multiplier);
var bitSet2 = new BitSet();
bitSet2.SetBit(33);
bitSet2.SetBit(values[1] * multiplier);

var allResult = bitSet2.All(bitSet1);
var anyResult = bitSet2.Any(bitSet1);
Expand Down
56 changes: 43 additions & 13 deletions src/Arch/Core/Utils/BitSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,26 +324,56 @@ public bool None(BitSet other)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Exclusive(BitSet other)
{
var bits = _bits.AsSpan();
var otherBits = other._bits.AsSpan();
var count = Math.Min(_bits.Length, otherBits.Length);
var max = (_highestBit/sizeof(uint)/Padding)+1;
var min = Math.Min(Math.Min(Length, other.Length), max);

for (var i = 0; i < count; i++)
if (!Vector.IsHardwareAccelerated || min < Padding)
{
var bit = bits[i];
if ((bit ^ otherBits[i]) != 0)
var bits = _bits.AsSpan();
var otherBits = other._bits.AsSpan();

// Bitwise xor, if both are not totally equal, return false
for (var i = 0; i < min; i++)
{
return false;
var bit = bits[i];
if ((bit ^ otherBits[i]) != 0)
{
return false;
}
}
}

// handle extra bits on our side that might just be all zero
var bitCount = _bits.Length;
for (var i = count; i < bitCount; i++)
// handle extra bits on our side that might just be all zero
for (var i = min; i < max; i++)
{
if (bits[i] != 0)
{
return false;
}
}
}
else
{
if (bits[i] != 0)
// Vectorized bitwise xor, return true since any is met
for (var i = 0; i < min; i += Padding)
{
var vector = new Vector<uint>(_bits, i);
var otherVector = new Vector<uint>(other._bits, i);

var resultVector = Vector.Xor(vector, otherVector);
if (!Vector.EqualsAll(resultVector, Vector<uint>.Zero))
{
return false;
}
}

// Handle extra bits on our side that might just be all zero.
for (var i = min; i < max; i += Padding)
{
return false;
var vector = new Vector<uint>(_bits, i);
if (!Vector.EqualsAll(vector, Vector<uint>.Zero)) // Vectors are not zero bits[0] != 0 basically
{
return false;
}
}
}

Expand Down

0 comments on commit a3225f8

Please sign in to comment.