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 (Sse2.IsSupported && (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 = Sse2.Shuffle(tempFirst, 0b00_01_10_11); tempLast = Sse2.Shuffle(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; } // Store any remaining values one-by-one for (nuint i = 0; i < (length / 2); i++) { ref int firstInt = ref Unsafe.Add(ref buf, i); ref int lastInt = ref Unsafe.Add(ref buf, length - 1 - i);
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 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 (Sse2.IsSupported && (nuint)Vector128 <long> .Count * 2 <= length) { ref int bufInt = ref Unsafe.As <long, int>(ref buf); nuint intLength = length * (sizeof(long) / sizeof(int)); nuint numElements = (nuint)Vector128 <int> .Count; nuint numIters = (intLength / numElements) / 2; for (nuint i = 0; i < numIters; i++) { nuint firstOffset = i * numElements; nuint lastOffset = intLength - ((1 + i) * numElements); // Load the values into vectors Vector128 <int> tempFirst = Vector128.LoadUnsafe(ref bufInt, firstOffset); Vector128 <int> tempLast = Vector128.LoadUnsafe(ref bufInt, lastOffset); // Shuffle to reverse each vector: // +-------+ // | A | B | // +-------+ // ---> // +-------+ // | B | A | // +-------+ tempFirst = Sse2.Shuffle(tempFirst, 0b0100_1110); tempLast = Sse2.Shuffle(tempLast, 0b0100_1110); // Store the values into final location tempLast.StoreUnsafe(ref bufInt, firstOffset); tempFirst.StoreUnsafe(ref bufInt, lastOffset); } bufInt = ref Unsafe.Add(ref bufInt, numIters * numElements); buf = ref Unsafe.As <int, long>(ref bufInt); length -= numIters * (nuint)Vector128 <long> .Count * 2; }
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); }