11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
33
4- using System . Buffers . Binary ;
54using System . Diagnostics ;
65using System . Diagnostics . CodeAnalysis ;
76using System . Numerics ;
@@ -1130,23 +1129,21 @@ private static unsafe nuint UnalignedCountVector128(ref byte searchSpace)
11301129
11311130 public static void Reverse ( ref byte buf , nuint length )
11321131 {
1133- Debug . Assert ( length > 1 ) ;
1134-
1135- nint remainder = ( nint ) length ;
1136- nint offset = 0 ;
1137-
1138- if ( Avx2 . IsSupported && remainder >= Vector256 < byte > . Count )
1132+ if ( Avx2 . IsSupported && ( nuint ) Vector256 < byte > . Count * 2 <= length )
11391133 {
11401134 Vector256 < byte > reverseMask = Vector256 . Create (
11411135 ( byte ) 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 , // first 128-bit lane
11421136 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ) ; // second 128-bit lane
1143-
1144- nint lastOffset = remainder - Vector256 < byte > . Count ;
1145- do
1137+ nuint numElements = ( nuint ) Vector256 < byte > . Count ;
1138+ nuint numIters = ( length / numElements ) / 2 ;
1139+ for ( nuint i = 0 ; i < numIters ; i ++ )
11461140 {
1147- // Load the values into vectors
1148- Vector256 < byte > tempFirst = Vector256 . LoadUnsafe ( ref buf , ( nuint ) offset ) ;
1149- Vector256 < byte > tempLast = Vector256 . LoadUnsafe ( ref buf , ( nuint ) lastOffset ) ;
1141+ nuint firstOffset = i * numElements ;
1142+ nuint lastOffset = length - ( ( 1 + i ) * numElements ) ;
1143+
1144+ // Load in values from beginning and end of the array.
1145+ Vector256 < byte > tempFirst = Vector256 . LoadUnsafe ( ref buf , firstOffset ) ;
1146+ Vector256 < byte > tempLast = Vector256 . LoadUnsafe ( ref buf , lastOffset ) ;
11501147
11511148 // Avx2 operates on two 128-bit lanes rather than the full 256-bit vector.
11521149 // Perform a shuffle to reverse each 128-bit lane, then permute to finish reversing the vector:
@@ -1173,23 +1170,24 @@ public static void Reverse(ref byte buf, nuint length)
11731170 tempLast = Avx2 . Permute2x128 ( tempLast , tempLast , 0b00_01 ) ;
11741171
11751172 // Store the reversed vectors
1176- tempLast . StoreUnsafe ( ref buf , ( nuint ) offset ) ;
1177- tempFirst . StoreUnsafe ( ref buf , ( nuint ) lastOffset ) ;
1178-
1179- offset += Vector256 < byte > . Count ;
1180- lastOffset -= Vector256 < byte > . Count ;
1181- } while ( lastOffset >= offset ) ;
1182-
1183- remainder = lastOffset + Vector256 < byte > . Count - offset ;
1173+ tempLast . StoreUnsafe ( ref buf , firstOffset ) ;
1174+ tempFirst . StoreUnsafe ( ref buf , lastOffset ) ;
1175+ }
1176+ buf = ref Unsafe . Add ( ref buf , numIters * numElements ) ;
1177+ length -= numIters * numElements * 2 ;
11841178 }
1185- else if ( Vector128 . IsHardwareAccelerated && remainder >= Vector128 < byte > . Count )
1179+ else if ( Vector128 . IsHardwareAccelerated && ( nuint ) Vector128 < byte > . Count * 2 <= length )
11861180 {
1187- nint lastOffset = remainder - Vector128 < byte > . Count ;
1188- do
1181+ nuint numElements = ( nuint ) Vector128 < byte > . Count ;
1182+ nuint numIters = ( length / numElements ) / 2 ;
1183+ for ( nuint i = 0 ; i < numIters ; i ++ )
11891184 {
1190- // Load the values into vectors
1191- Vector128 < byte > tempFirst = Vector128 . LoadUnsafe ( ref buf , ( nuint ) offset ) ;
1192- Vector128 < byte > tempLast = Vector128 . LoadUnsafe ( ref buf , ( nuint ) lastOffset ) ;
1185+ nuint firstOffset = i * numElements ;
1186+ nuint lastOffset = length - ( ( 1 + i ) * numElements ) ;
1187+
1188+ // Load in values from beginning and end of the array.
1189+ Vector128 < byte > tempFirst = Vector128 . LoadUnsafe ( ref buf , firstOffset ) ;
1190+ Vector128 < byte > tempLast = Vector128 . LoadUnsafe ( ref buf , lastOffset ) ;
11931191
11941192 // Shuffle to reverse each vector:
11951193 // +---------------------------------------------------------------+
@@ -1205,58 +1203,15 @@ public static void Reverse(ref byte buf, nuint length)
12051203 ( byte ) 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ) ) ;
12061204
12071205 // Store the reversed vectors
1208- tempLast . StoreUnsafe ( ref buf , ( nuint ) offset ) ;
1209- tempFirst . StoreUnsafe ( ref buf , ( nuint ) lastOffset ) ;
1210-
1211- offset += Vector128 < byte > . Count ;
1212- lastOffset -= Vector128 < byte > . Count ;
1213- } while ( lastOffset >= offset ) ;
1214-
1215- remainder = lastOffset + Vector128 < byte > . Count - offset ;
1216- }
1217-
1218- if ( remainder >= sizeof ( long ) )
1219- {
1220- nint lastOffset = ( nint ) length - offset - sizeof ( long ) ;
1221- do
1222- {
1223- long tempFirst = Unsafe . ReadUnaligned < long > ( ref Unsafe . Add ( ref buf , offset ) ) ;
1224- long tempLast = Unsafe . ReadUnaligned < long > ( ref Unsafe . Add ( ref buf , lastOffset ) ) ;
1225-
1226- // swap and store in reversed position
1227- Unsafe . WriteUnaligned ( ref Unsafe . Add ( ref buf , offset ) , BinaryPrimitives . ReverseEndianness ( tempLast ) ) ;
1228- Unsafe . WriteUnaligned ( ref Unsafe . Add ( ref buf , lastOffset ) , BinaryPrimitives . ReverseEndianness ( tempFirst ) ) ;
1229-
1230- offset += sizeof ( long ) ;
1231- lastOffset -= sizeof ( long ) ;
1232- } while ( lastOffset >= offset ) ;
1233-
1234- remainder = lastOffset + sizeof ( long ) - offset ;
1235- }
1236-
1237- if ( remainder >= sizeof ( int ) )
1238- {
1239- nint lastOffset = ( nint ) length - offset - sizeof ( int ) ;
1240- do
1241- {
1242- int tempFirst = Unsafe . ReadUnaligned < int > ( ref Unsafe . Add ( ref buf , offset ) ) ;
1243- int tempLast = Unsafe . ReadUnaligned < int > ( ref Unsafe . Add ( ref buf , lastOffset ) ) ;
1244-
1245- // swap and store in reversed position
1246- Unsafe . WriteUnaligned ( ref Unsafe . Add ( ref buf , offset ) , BinaryPrimitives . ReverseEndianness ( tempLast ) ) ;
1247- Unsafe . WriteUnaligned ( ref Unsafe . Add ( ref buf , lastOffset ) , BinaryPrimitives . ReverseEndianness ( tempFirst ) ) ;
1248-
1249- offset += sizeof ( int ) ;
1250- lastOffset -= sizeof ( int ) ;
1251- } while ( lastOffset >= offset ) ;
1252-
1253- remainder = lastOffset + sizeof ( int ) - offset ;
1206+ tempLast . StoreUnsafe ( ref buf , firstOffset ) ;
1207+ tempFirst . StoreUnsafe ( ref buf , lastOffset ) ;
1208+ }
1209+ buf = ref Unsafe . Add ( ref buf , numIters * numElements ) ;
1210+ length -= numIters * numElements * 2 ;
12541211 }
12551212
1256- if ( remainder > 1 )
1257- {
1258- ReverseInner ( ref Unsafe . Add ( ref buf , offset ) , ( nuint ) remainder ) ;
1259- }
1213+ // Store any remaining values one-by-one
1214+ ReverseInner ( ref buf , length ) ;
12601215 }
12611216 }
12621217}
0 commit comments