Skip to content

Commit 2a4eea0

Browse files
committed
Faster Utf8Span.Equals, 4th iteration
Important to be branchless for the first vector. Important not to store equals (it exists for readability only, but is single use)
1 parent 433a0cc commit 2a4eea0

File tree

1 file changed

+20
-31
lines changed

1 file changed

+20
-31
lines changed

1brc/Utf8Span.cs

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -72,44 +72,36 @@ public bool Equals(Utf8Span other) //, bool isSimdSafe)
7272

7373
if (Vector256.IsHardwareAccelerated)
7474
{
75-
if (Length <= vectorSize)
76-
{
77-
var mask = Vector256.LoadUnsafe(in MemoryMarshal.GetReference(OnesAfterLength), (uint)Vector256<byte>.Count - Length);
78-
var bytes = Vector256.Load(Pointer);
79-
var otherBytes = Vector256.Load(other.Pointer);
80-
var bytesAnd = Vector256.Equals(bytes, otherBytes) | mask;
81-
var msbMask = Vector256.ExtractMostSignificantBits(bytesAnd);
82-
var equals = msbMask == uint.MaxValue;
83-
return equals;
84-
}
75+
var bytes = Vector256.Load(Pointer);
76+
var otherBytes = Vector256.Load(other.Pointer);
77+
var bytesAnd = Vector256.Equals(bytes, otherBytes);
8578

86-
return EqualsCont(this, other);
79+
var lenVec = Vector256.Create((byte)Length);
80+
var indices = Vector256.Create((byte)0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);
81+
var onesAfterLength = Vector256.LessThanOrEqual(lenVec, indices);
82+
bytesAnd |= onesAfterLength;
83+
84+
var equals = uint.MaxValue == Vector256.ExtractMostSignificantBits(bytesAnd);
85+
if (!equals) return false;
86+
return Length <= vectorSize || EqualsCont(this, other);
8787
}
8888

8989
return Span.SequenceEqual(other.Span);
9090

91-
[MethodImpl(MethodImplOptions.NoInlining)]
91+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9292
static bool EqualsCont(Utf8Span left, Utf8Span right)
9393
{
94-
var bytes = Vector256.Load(left.Pointer);
95-
var otherBytes = Vector256.Load(right.Pointer);
96-
var bytesAnd = Vector256.Equals(bytes, otherBytes);
97-
var msbMask = Vector256.ExtractMostSignificantBits(bytesAnd);
98-
if (msbMask != uint.MaxValue)
99-
return false;
10094

101-
bytes = Vector256.Load(left.Pointer + vectorSize);
102-
otherBytes = Vector256.Load(right.Pointer + vectorSize);
103-
bytesAnd = Vector256.Equals(bytes, otherBytes);
95+
var bytes = Vector256.Load(left.Pointer + vectorSize);
96+
var otherBytes = Vector256.Load(right.Pointer + vectorSize);
97+
var bytesAnd = Vector256.Equals(bytes, otherBytes);
10498
if (left.Length <= vectorSize * 2)
10599
{
106100
bytesAnd |= Vector256.LoadUnsafe(in MemoryMarshal.GetReference(OnesAfterLength), vectorSize * 2 - left.Length);
107-
msbMask = Vector256.ExtractMostSignificantBits(bytesAnd);
108-
return msbMask == uint.MaxValue;
101+
return uint.MaxValue == Vector256.ExtractMostSignificantBits(bytesAnd);
109102
}
110103

111-
msbMask = Vector256.ExtractMostSignificantBits(bytesAnd);
112-
if (msbMask != uint.MaxValue)
104+
if (uint.MaxValue != Vector256.ExtractMostSignificantBits(bytesAnd))
113105
return false;
114106

115107
bytes = Vector256.Load(left.Pointer + vectorSize * 2);
@@ -118,20 +110,17 @@ static bool EqualsCont(Utf8Span left, Utf8Span right)
118110
if (left.Length <= vectorSize * 3)
119111
{
120112
bytesAnd |= Vector256.LoadUnsafe(in MemoryMarshal.GetReference(OnesAfterLength), vectorSize * 3 - left.Length);
121-
msbMask = Vector256.ExtractMostSignificantBits(bytesAnd);
122-
return msbMask == uint.MaxValue;
113+
return uint.MaxValue == Vector256.ExtractMostSignificantBits(bytesAnd);
123114
}
124115

125-
msbMask = Vector256.ExtractMostSignificantBits(bytesAnd);
126-
if (msbMask != uint.MaxValue)
116+
if (uint.MaxValue != Vector256.ExtractMostSignificantBits(bytesAnd))
127117
return false;
128118

129119
bytes = Vector256.Load(left.Pointer + vectorSize * 3);
130120
otherBytes = Vector256.Load(right.Pointer + vectorSize * 3);
131121
bytesAnd = Vector256.Equals(bytes, otherBytes);
132122
bytesAnd |= Vector256.LoadUnsafe(in MemoryMarshal.GetReference(OnesAfterLength), vectorSize * 4 - left.Length);
133-
msbMask = Vector256.ExtractMostSignificantBits(bytesAnd);
134-
return msbMask == uint.MaxValue;
123+
return uint.MaxValue == Vector256.ExtractMostSignificantBits(bytesAnd);
135124
}
136125
}
137126

0 commit comments

Comments
 (0)