33using Reloaded . Memory . Utilities ;
44using static Reloaded . Memory . Internals . Backports . System . Text . Unicode . Utf16Utility ;
55#if NET7_0_OR_GREATER
6+ using static Reloaded . Memory . Internals . Algorithms . UnstableStringHash ;
67using Reloaded . Memory . Extensions ;
78using Reloaded . Memory . Internals . Backports . System . Globalization ;
89using System . Numerics ;
@@ -48,7 +49,7 @@ internal static unsafe nuint GetHashCodeUnstableLower(this ReadOnlySpan<char> te
4849 return text . UnstableHashVec256Lower ( ) ;
4950
5051 // Over 4 Vec128 regs (16 * 4 = 64 bytes)
51- if ( Vector256 . IsHardwareAccelerated && length >= ( sizeof ( Vector128 < ulong > ) / sizeof ( char ) ) * 4 )
52+ if ( Vector128 . IsHardwareAccelerated && length >= ( sizeof ( Vector128 < ulong > ) / sizeof ( char ) ) * 4 )
5253 return text . UnstableHashVec128Lower ( ) ;
5354#endif
5455
@@ -104,6 +105,9 @@ internal static unsafe nuint GetHashCodeUnstableLowerSlow(this ReadOnlySpan<char
104105 }
105106
106107 #if NET7_0_OR_GREATER
108+ #if NET8_0 // Bug in .NET 8 seems to cause this to not re-jit to tier1 till like 200k calls on Linux x64
109+ [ MethodImpl ( MethodImplOptions . AggressiveOptimization ) ]
110+ #endif
107111 internal static unsafe UIntPtr UnstableHashVec128Lower ( this ReadOnlySpan < char > text )
108112 {
109113 fixed ( char * src = & text . GetPinnableReference ( ) )
@@ -113,59 +117,59 @@ internal static unsafe UIntPtr UnstableHashVec128Lower(this ReadOnlySpan<char> t
113117 var hash2 = hash1 ;
114118 var ptr = ( nuint * ) ( src ) ;
115119
116- var prime = Vector128 . Create ( ( uint ) 0x01000193 ) ;
117- var hash1_128 = Vector128 . Create ( 0x811c9dc5 ) ;
118- var hash2_128 = Vector128 . Create ( 0x811c9dc5 ) ;
120+ var prime = Vector128 . Create ( ( ulong ) 0x100000001b3 ) ;
121+ var hash1_128 = Vector128 . Create ( 0xcbf29ce484222325 ) ;
122+ var hash2_128 = Vector128 . Create ( 0xcbf29ce484222325 ) ;
119123
120124 // We "normalize to lowercase" every char by ORing with 0x0020. This casts
121125 // a very wide net because it will change, e.g., '^' to '~'. But that should
122126 // be ok because we expect this to be very rare in practice.
123- var toLower = Vector128 . Create < uint > ( 0x0020_0020 ) ;
127+ var toLower = Vector128 . Create < short > ( 0x0020 ) . AsUInt64 ( ) ;
124128
125129 while ( length >= sizeof ( Vector128 < ulong > ) / sizeof ( char ) * 4 ) // 64 byte chunks.
126130 {
127131 length -= ( sizeof ( Vector128 < ulong > ) / sizeof ( char ) ) * 4 ;
128132
129- var v0 = Vector128 . Load ( ( ulong * ) ptr ) . AsUInt32 ( ) ;
130- if ( ! AllCharsInVector128AreAscii ( v0 ) )
133+ var v0 = Vector128 . Load ( ( ulong * ) ptr ) ;
134+ if ( ! AllCharsInVector128AreAscii ( v0 . AsUInt16 ( ) ) )
131135 goto NotAscii ;
132136
133137 hash1_128 = Vector128 . Xor ( hash1_128 , Vector128 . BitwiseOr ( v0 , toLower ) ) ;
134- hash1_128 = Vector128 . Multiply ( hash1_128 , prime ) ;
138+ hash1_128 = HashMultiply128 ( hash1_128 , prime ) ;
135139
136- v0 = Vector128 . Load ( ( ulong * ) ptr + 2 ) . AsUInt32 ( ) ;
137- if ( ! AllCharsInVector128AreAscii ( v0 ) )
140+ v0 = Vector128 . Load ( ( ulong * ) ptr + 2 ) ;
141+ if ( ! AllCharsInVector128AreAscii ( v0 . AsUInt16 ( ) ) )
138142 goto NotAscii ;
139143
140144 hash2_128 = Vector128 . Xor ( hash2_128 , Vector128 . BitwiseOr ( v0 , toLower ) ) ;
141- hash2_128 = Vector128 . Multiply ( hash2_128 , prime ) ;
145+ hash2_128 = HashMultiply128 ( hash2_128 , prime ) ;
142146
143- v0 = Vector128 . Load ( ( ulong * ) ptr + 4 ) . AsUInt32 ( ) ;
144- if ( ! AllCharsInVector128AreAscii ( v0 ) )
147+ v0 = Vector128 . Load ( ( ulong * ) ptr + 4 ) ;
148+ if ( ! AllCharsInVector128AreAscii ( v0 . AsUInt16 ( ) ) )
145149 goto NotAscii ;
146150
147151 hash1_128 = Vector128 . Xor ( hash1_128 , Vector128 . BitwiseOr ( v0 , toLower ) ) ;
148- hash1_128 = Vector128 . Multiply ( hash1_128 , prime ) ;
152+ hash1_128 = HashMultiply128 ( hash1_128 , prime ) ;
149153
150- v0 = Vector128 . Load ( ( ulong * ) ptr + 6 ) . AsUInt32 ( ) ;
151- if ( ! AllCharsInVector128AreAscii ( v0 ) )
154+ v0 = Vector128 . Load ( ( ulong * ) ptr + 6 ) ;
155+ if ( ! AllCharsInVector128AreAscii ( v0 . AsUInt16 ( ) ) )
152156 goto NotAscii ;
153157
154158 hash2_128 = Vector128 . Xor ( hash2_128 , Vector128 . BitwiseOr ( v0 , toLower ) ) ;
155- hash2_128 = Vector128 . Multiply ( hash2_128 , prime ) ;
159+ hash2_128 = HashMultiply128 ( hash2_128 , prime ) ;
156160 ptr += ( sizeof ( Vector128 < ulong > ) / sizeof ( nuint ) ) * 4 ;
157161 }
158162
159163 while ( length >= sizeof ( Vector128 < ulong > ) / sizeof ( char ) ) // 16 byte chunks.
160164 {
161165 length -= sizeof ( Vector128 < ulong > ) / sizeof ( char ) ;
162166
163- var v0 = Vector128 . Load ( ( ulong * ) ptr ) . AsUInt32 ( ) ;
164- if ( ! AllCharsInVector128AreAscii ( v0 ) )
167+ var v0 = Vector128 . Load ( ( ulong * ) ptr ) ;
168+ if ( ! AllCharsInVector128AreAscii ( v0 . AsUInt16 ( ) ) )
165169 goto NotAscii ;
166170
167171 hash1_128 = Vector128 . Xor ( hash1_128 , Vector128 . BitwiseOr ( v0 , toLower ) ) ;
168- hash1_128 = Vector128 . Multiply ( hash1_128 , prime ) ;
172+ hash1_128 = HashMultiply128 ( hash1_128 , prime ) ;
169173 ptr += ( sizeof ( Vector128 < ulong > ) / sizeof ( nuint ) ) ;
170174 }
171175
@@ -224,6 +228,9 @@ internal static unsafe UIntPtr UnstableHashVec128Lower(this ReadOnlySpan<char> t
224228 return GetHashCodeUnstableLowerSlow ( text ) ;
225229 }
226230
231+ #if NET8_0 // Bug in .NET 8 seems to cause this to not re-jit to tier1 till like 200k calls on Linux x64
232+ [ MethodImpl ( MethodImplOptions . AggressiveOptimization ) ]
233+ #endif
227234 internal static unsafe UIntPtr UnstableHashVec256Lower ( this ReadOnlySpan < char > text )
228235 {
229236 fixed ( char * src = & text . GetPinnableReference ( ) )
@@ -233,59 +240,59 @@ internal static unsafe UIntPtr UnstableHashVec256Lower(this ReadOnlySpan<char> t
233240 var hash2 = hash1 ;
234241 var ptr = ( nuint * ) ( src ) ;
235242
236- var prime = Vector256 . Create ( ( uint ) 0x01000193 ) ;
237- var hash1_256 = Vector256 . Create ( 0x811c9dc5 ) ;
238- var hash2_256 = Vector256 . Create ( 0x811c9dc5 ) ;
243+ var prime = Vector256 . Create ( ( ulong ) 0x100000001b3 ) ;
244+ var hash1_256 = Vector256 . Create ( 0xcbf29ce484222325 ) ;
245+ var hash2_256 = Vector256 . Create ( 0xcbf29ce484222325 ) ;
239246
240247 // We "normalize to lowercase" every char by ORing with 0x0020. This casts
241248 // a very wide net because it will change, e.g., '^' to '~'. But that should
242249 // be ok because we expect this to be very rare in practice.
243- var toLower = Vector256 . Create < uint > ( 0x0020_0020 ) ;
250+ var toLower = Vector256 . Create < short > ( 0x0020 ) . AsUInt64 ( ) ;
244251
245252 while ( length >= sizeof ( Vector256 < ulong > ) / sizeof ( char ) * 4 ) // 128 byte chunks.
246253 {
247254 length -= ( sizeof ( Vector256 < ulong > ) / sizeof ( char ) ) * 4 ;
248255
249- var v0 = Vector256 . Load ( ( ulong * ) ptr ) . AsUInt32 ( ) ;
250- if ( ! AllCharsInVector256AreAscii ( v0 ) )
256+ var v0 = Vector256 . Load ( ( ulong * ) ptr ) ;
257+ if ( ! AllCharsInVector256AreAscii ( v0 . AsUInt16 ( ) ) )
251258 goto NotAscii ;
252259
253260 hash1_256 = Vector256 . Xor ( hash1_256 , Vector256 . BitwiseOr ( v0 , toLower ) ) ;
254- hash1_256 = Vector256 . Multiply ( hash1_256 . AsUInt32 ( ) , prime . AsUInt32 ( ) ) ;
261+ hash1_256 = HashMultiply256 ( hash1_256 , prime ) ;
255262
256- v0 = Vector256 . Load ( ( ulong * ) ptr + 4 ) . AsUInt32 ( ) ;
257- if ( ! AllCharsInVector256AreAscii ( v0 ) )
263+ v0 = Vector256 . Load ( ( ulong * ) ptr + 4 ) ;
264+ if ( ! AllCharsInVector256AreAscii ( v0 . AsUInt16 ( ) ) )
258265 goto NotAscii ;
259266
260267 hash2_256 = Vector256 . Xor ( hash2_256 , Vector256 . BitwiseOr ( v0 , toLower ) ) ;
261- hash2_256 = Vector256 . Multiply ( hash2_256 . AsUInt32 ( ) , prime . AsUInt32 ( ) ) ;
268+ hash2_256 = HashMultiply256 ( hash2_256 , prime ) ;
262269
263- v0 = Vector256 . Load ( ( ulong * ) ptr + 8 ) . AsUInt32 ( ) ;
264- if ( ! AllCharsInVector256AreAscii ( v0 ) )
270+ v0 = Vector256 . Load ( ( ulong * ) ptr + 8 ) ;
271+ if ( ! AllCharsInVector256AreAscii ( v0 . AsUInt16 ( ) ) )
265272 goto NotAscii ;
266273
267274 hash1_256 = Vector256 . Xor ( hash1_256 , Vector256 . BitwiseOr ( v0 , toLower ) ) ;
268- hash1_256 = Vector256 . Multiply ( hash1_256 . AsUInt32 ( ) , prime . AsUInt32 ( ) ) ;
275+ hash1_256 = HashMultiply256 ( hash1_256 , prime ) ;
269276
270- v0 = Vector256 . Load ( ( ulong * ) ptr + 12 ) . AsUInt32 ( ) ;
271- if ( ! AllCharsInVector256AreAscii ( v0 ) )
277+ v0 = Vector256 . Load ( ( ulong * ) ptr + 12 ) ;
278+ if ( ! AllCharsInVector256AreAscii ( v0 . AsUInt16 ( ) ) )
272279 goto NotAscii ;
273280
274281 hash2_256 = Vector256 . Xor ( hash2_256 , Vector256 . BitwiseOr ( v0 , toLower ) ) ;
275- hash2_256 = Vector256 . Multiply ( hash2_256 . AsUInt32 ( ) , prime . AsUInt32 ( ) ) ;
282+ hash2_256 = HashMultiply256 ( hash2_256 , prime ) ;
276283 ptr += ( sizeof ( Vector256 < ulong > ) / sizeof ( nuint ) ) * 4 ;
277284 }
278285
279286 while ( length >= sizeof ( Vector256 < ulong > ) / sizeof ( char ) ) // 32 byte chunks.
280287 {
281288 length -= sizeof ( Vector256 < ulong > ) / sizeof ( char ) ;
282289
283- var v0 = Vector256 . Load ( ( ulong * ) ptr ) . AsUInt32 ( ) ;
284- if ( ! AllCharsInVector256AreAscii ( v0 ) )
290+ var v0 = Vector256 . Load ( ( ulong * ) ptr ) ;
291+ if ( ! AllCharsInVector256AreAscii ( v0 . AsUInt16 ( ) ) )
285292 goto NotAscii ;
286293
287294 hash1_256 = Vector256 . Xor ( hash1_256 , Vector256 . BitwiseOr ( v0 , toLower ) ) ;
288- hash1_256 = Vector256 . Multiply ( hash1_256 . AsUInt32 ( ) , prime . AsUInt32 ( ) ) ;
295+ hash1_256 = HashMultiply256 ( hash1_256 , prime ) ;
289296 ptr += ( sizeof ( Vector256 < ulong > ) / sizeof ( nuint ) ) ;
290297 }
291298
@@ -347,7 +354,7 @@ internal static unsafe UIntPtr UnstableHashVec256Lower(this ReadOnlySpan<char> t
347354 NotAscii :
348355 return GetHashCodeUnstableLowerSlow ( text ) ;
349356 }
350- #endif
357+ #endif
351358
352359 internal static unsafe nuint UnstableHashNonVectorLower ( this ReadOnlySpan < char > text )
353360 {
0 commit comments