| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using System.Runtime.Intrinsics.X86;
- using Internal.Runtime.CompilerServices;
- // Some routines inspired by the Stanford Bit Twiddling Hacks by Sean Eron Anderson:
- // http://graphics.stanford.edu/~seander/bithacks.html
- namespace System
- {
- internal static class BitOps
- {
- // C# no-alloc optimization that directly wraps the data section of the dll (similar to string constants)
- // https://github.com/dotnet/roslyn/pull/24621
- private static ReadOnlySpan<byte> s_TrailingZeroCountDeBruijn => new byte[32]
- {
- 00, 01, 28, 02, 29, 14, 24, 03,
- 30, 22, 20, 15, 25, 17, 04, 08,
- 31, 27, 13, 23, 21, 19, 16, 07,
- 26, 12, 18, 06, 11, 05, 10, 09
- };
- /// <summary>
- /// Count the number of trailing zero bits in an integer value.
- /// Similar in behavior to the x86 instruction TZCNT.
- /// </summary>
- /// <param name="value">The value.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int TrailingZeroCount(int value)
- => TrailingZeroCount((uint)value);
- /// <summary>
- /// Count the number of trailing zero bits in an integer value.
- /// Similar in behavior to the x86 instruction TZCNT.
- /// </summary>
- /// <param name="value">The value.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int TrailingZeroCount(uint value)
- {
- if (Bmi1.IsSupported)
- {
- // Note that TZCNT contract specifies 0->32
- return (int)Bmi1.TrailingZeroCount(value);
- }
- // Main code has behavior 0->0, so special-case in order to match intrinsic path 0->32
- if (value == 0u)
- return 32;
- // uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check
- return Unsafe.AddByteOffset(
- ref MemoryMarshal.GetReference(s_TrailingZeroCountDeBruijn),
- // Using deBruijn sequence, k=2, n=5 (2^5=32) : 0b_0000_0111_0111_1100_1011_0101_0011_0001u
- ((uint)((value & -value) * 0x077CB531u)) >> 27);
- }
- }
- }
|