Repository: dotnet/runtime
File: src/libraries/System.IO.Hashing/src/System/IO/Hashing/Adler32.cs (C#)

Code before:
        public static uint HashToUInt32(ReadOnlySpan<byte> source)
            => Update(InitialState, source);

        private static uint Update(uint adler, ReadOnlySpan<byte> source)
        {
            if (source.IsEmpty)
            {
                return adler;
            }

#if NET
            if (BitConverter.IsLittleEndian &&
                Vector128.IsHardwareAccelerated &&
                source.Length >= Vector128<byte>.Count * 2)
            {
                if (AdvSimd.IsSupported)
                {
                    return UpdateArm128(adler, source);
                }

                if (Avx512BW.IsSupported && source.Length >= Vector512<byte>.Count)
                {
                    return UpdateVector512(adler, source);
                }

                if (Avx2.IsSupported && source.Length >= Vector256<byte>.Count)
                {
                    return UpdateVector256(adler, source);
                }

                return UpdateVector128(adler, source);
            }
#endif

            return UpdateScalar(adler, source);
        }

        private static uint UpdateScalar(uint adler, ReadOnlySpan<byte> source)
        {
            uint s1 = adler & 0xFFFF;
            uint s2 = (adler >> 16) & 0xFFFF;
            Debug.Assert(!source.IsEmpty);

            do
            {
                int k = source.Length < NMax ? source.Length : NMax;
                foreach (byte b in source.Slice(0, k))
                {
                    s1 += b;
                    s2 += s1;
                }

Review comment (performance):
Similar here for `Vector256.IsHardwareAccelerated`

In general we have a distinction between "it is supported" and "it is fast" with the nuance being because many first generation implementations of a given vector width would downclock the CPU. So while the vector code was technically faster, it had a much higher risk of making the rest of the app slower.

Users therefore only want to do only the `is supported` checks if they know they are in a workload that's heavy enough that this isn't a concern.

Code after:
        public static uint HashToUInt32(ReadOnlySpan<byte> source)
            => Update(InitialState, source);

        private static uint Update(uint adler, ReadOnlySpan<byte> source)
        {
            if (source.IsEmpty)
            {
                return adler;
            }

#if NET
            if (BitConverter.IsLittleEndian &&
                Vector128.IsHardwareAccelerated &&
                source.Length >= Vector128<byte>.Count * 2)
            {
                if (Vector512.IsHardwareAccelerated && Avx512BW.IsSupported && source.Length >= Vector512<byte>.Count)
                {
                    return UpdateVector512(adler, source);
                }

                if (Vector256.IsHardwareAccelerated && Avx2.IsSupported && source.Length >= Vector256<byte>.Count)
                {
                    return UpdateVector256(adler, source);
                }

                return UpdateVector128(adler, source);
            }
#endif

            return UpdateScalar(adler, source);
        }

        private static uint UpdateScalar(uint adler, ReadOnlySpan<byte> source)
        {
            uint s1 = adler & 0xFFFF;
            uint s2 = (adler >> 16) & 0xFFFF;
            Debug.Assert(!source.IsEmpty);

            do
            {
                int k = source.Length < NMax ? source.Length : NMax;
                foreach (byte b in source.Slice(0, k))
                {
                    s1 += b;
                    s2 += s1;
                }

                s1 %= ModBase;
                s2 %= ModBase;
                source = source.Slice(k);
            }