public static void Reverse(ref long buf, nuint length) { if (Avx2.IsSupported && (nuint)Vector256 <long> .Count * 2 <= length) { nuint numElements = (nuint)Vector256 <long> .Count; nuint numIters = (length / numElements) / 2; for (nuint i = 0; i < numIters; i++) { nuint firstOffset = i * numElements; nuint lastOffset = length - ((1 + i) * numElements); // Load the values into vectors Vector256 <long> tempFirst = Vector256.LoadUnsafe(ref buf, firstOffset); Vector256 <long> tempLast = Vector256.LoadUnsafe(ref buf, lastOffset); // Permute to reverse each vector: // +---------------+ // | A | B | C | D | // +---------------+ // ---> // +---------------+ // | D | C | B | A | // +---------------+ tempFirst = Avx2.Permute4x64(tempFirst, 0b00_01_10_11); tempLast = Avx2.Permute4x64(tempLast, 0b00_01_10_11); // Store the values into final location tempLast.StoreUnsafe(ref buf, firstOffset); tempFirst.StoreUnsafe(ref buf, lastOffset); } buf = ref Unsafe.Add(ref buf, numIters * numElements); length -= numIters * numElements * 2; } else if (Vector128.IsHardwareAccelerated && (nuint)Vector128 <long> .Count * 2 <= length) { nuint numElements = (nuint)Vector128 <long> .Count; nuint numIters = (length / numElements) / 2; for (nuint i = 0; i < numIters; i++) { nuint firstOffset = i * numElements; nuint lastOffset = length - ((1 + i) * numElements); // Load the values into vectors Vector128 <long> tempFirst = Vector128.LoadUnsafe(ref buf, firstOffset); Vector128 <long> tempLast = Vector128.LoadUnsafe(ref buf, lastOffset); // Shuffle to reverse each vector: // +-------+ // | A | B | // +-------+ // ---> // +-------+ // | B | A | // +-------+ tempFirst = Vector128.Shuffle(tempFirst, Vector128.Create(1, 0)); tempLast = Vector128.Shuffle(tempLast, Vector128.Create(1, 0)); // Store the values into final location tempLast.StoreUnsafe(ref buf, firstOffset); tempFirst.StoreUnsafe(ref buf, lastOffset); } buf = ref Unsafe.Add(ref buf, numIters * numElements); length -= numIters * (nuint)Vector128 <long> .Count * 2; } // Store any remaining values one-by-one ReverseInner(ref buf, length); }
public static void Reverse(ref int buf, nuint length) { if (Avx2.IsSupported && (nuint)Vector256 <int> .Count * 2 <= length) { nuint numElements = (nuint)Vector256 <int> .Count; nuint numIters = (length / numElements) / 2; Vector256 <int> reverseMask = Vector256.Create(7, 6, 5, 4, 3, 2, 1, 0); for (nuint i = 0; i < numIters; i++) { nuint firstOffset = i * numElements; nuint lastOffset = length - ((1 + i) * numElements); // Load the values into vectors Vector256 <int> tempFirst = Vector256.LoadUnsafe(ref buf, firstOffset); Vector256 <int> tempLast = Vector256.LoadUnsafe(ref buf, lastOffset); // Permute to reverse each vector: // +-------------------------------+ // | A | B | C | D | E | F | G | H | // +-------------------------------+ // ---> // +-------------------------------+ // | H | G | F | E | D | C | B | A | // +-------------------------------+ tempFirst = Avx2.PermuteVar8x32(tempFirst, reverseMask); tempLast = Avx2.PermuteVar8x32(tempLast, reverseMask); // Store the values into final location tempLast.StoreUnsafe(ref buf, firstOffset); tempFirst.StoreUnsafe(ref buf, lastOffset); } buf = ref Unsafe.Add(ref buf, numIters * numElements); length -= numIters * numElements * 2; } else if (Vector128.IsHardwareAccelerated && (nuint)Vector128 <int> .Count * 2 <= length) { nuint numElements = (nuint)Vector128 <int> .Count; nuint numIters = (length / numElements) / 2; for (nuint i = 0; i < numIters; i++) { nuint firstOffset = i * numElements; nuint lastOffset = length - ((1 + i) * numElements); // Load the values into vectors Vector128 <int> tempFirst = Vector128.LoadUnsafe(ref buf, firstOffset); Vector128 <int> tempLast = Vector128.LoadUnsafe(ref buf, lastOffset); // Shuffle to reverse each vector: // +---------------+ // | A | B | C | D | // +---------------+ // ---> // +---------------+ // | D | C | B | A | // +---------------+ tempFirst = Vector128.Shuffle(tempFirst, Vector128.Create(3, 2, 1, 0)); tempLast = Vector128.Shuffle(tempLast, Vector128.Create(3, 2, 1, 0)); // Store the values into final location tempLast.StoreUnsafe(ref buf, firstOffset); tempFirst.StoreUnsafe(ref buf, lastOffset); } buf = ref Unsafe.Add(ref buf, numIters * numElements); length -= numIters * numElements * 2; } ReverseInner(ref buf, length); }