Skip to content

Commit

Permalink
Move internal BitOperations.LeadingZeroCount({U}Int128) (dotnet#93068)
Browse files Browse the repository at this point in the history
* Move internal BitOperations.LeadingZeroCount({U}Int128)

With no other signed overloads exposed, it's easy to accidentally use these for int/long/etc.  They exist only for the implementation of {U}Int128 at this point, so just move them to be in those types.

* Address PR feedback
  • Loading branch information
stephentoub authored Oct 6, 2023
1 parent 7f32a81 commit 93c1912
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 34 deletions.
13 changes: 9 additions & 4 deletions src/libraries/System.Private.CoreLib/src/System/Int128.cs
Original file line number Diff line number Diff line change
Expand Up @@ -742,12 +742,17 @@ public static (Int128 Quotient, Int128 Remainder) DivRem(Int128 left, Int128 rig

/// <inheritdoc cref="IBinaryInteger{TSelf}.LeadingZeroCount(TSelf)" />
public static Int128 LeadingZeroCount(Int128 value)
=> LeadingZeroCountAsInt32(value);

/// <summary>Computes the number of leading zero bits in this value.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LeadingZeroCountAsInt32(Int128 value)
{
if (value._upper == 0)
{
return 64 + ulong.LeadingZeroCount(value._lower);
return 64 + BitOperations.LeadingZeroCount(value._lower);
}
return ulong.LeadingZeroCount(value._upper);
return BitOperations.LeadingZeroCount(value._upper);
}

/// <inheritdoc cref="IBinaryInteger{TSelf}.PopCount(TSelf)" />
Expand Down Expand Up @@ -946,11 +951,11 @@ int IBinaryInteger<Int128>.GetShortestBitLength()

if (IsPositive(value))
{
return (Size * 8) - BitOperations.LeadingZeroCount(value);
return (Size * 8) - LeadingZeroCountAsInt32(value);
}
else
{
return (Size * 8) + 1 - BitOperations.LeadingZeroCount(~value);
return (Size * 8) + 1 - LeadingZeroCountAsInt32(~value);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,18 +164,6 @@ public static nuint RoundUpToPowerOf2(nuint value)
#endif
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int LeadingZeroCount(Int128 value)
{
ulong upper = value.Upper;

if (upper == 0)
{
return 64 + LeadingZeroCount(value.Lower);
}
return LeadingZeroCount(upper);
}

/// <summary>
/// Count the number of leading zero bits in a mask.
/// Similar in behavior to the x86 instruction LZCNT.
Expand Down Expand Up @@ -261,18 +249,6 @@ public static int LeadingZeroCount(ulong value)
return LeadingZeroCount(hi);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int LeadingZeroCount(UInt128 value)
{
ulong upper = value.Upper;

if (upper == 0)
{
return 64 + LeadingZeroCount(value.Lower);
}
return LeadingZeroCount(upper);
}

/// <summary>
/// Count the number of leading zero bits in a mask.
/// Similar in behavior to the x86 instruction LZCNT.
Expand Down
16 changes: 10 additions & 6 deletions src/libraries/System.Private.CoreLib/src/System/UInt128.cs
Original file line number Diff line number Diff line change
Expand Up @@ -802,12 +802,17 @@ public static (UInt128 Quotient, UInt128 Remainder) DivRem(UInt128 left, UInt128

/// <inheritdoc cref="IBinaryInteger{TSelf}.LeadingZeroCount(TSelf)" />
public static UInt128 LeadingZeroCount(UInt128 value)
=> (uint)LeadingZeroCountAsInt32(value);

/// <summary>Computes the number of leading zero bits in this value.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LeadingZeroCountAsInt32(UInt128 value)
{
if (value._upper == 0)
{
return 64 + ulong.LeadingZeroCount(value._lower);
return 64 + BitOperations.LeadingZeroCount(value._lower);
}
return ulong.LeadingZeroCount(value._upper);
return BitOperations.LeadingZeroCount(value._upper);
}

/// <inheritdoc cref="IBinaryInteger{TSelf}.PopCount(TSelf)" />
Expand Down Expand Up @@ -950,8 +955,7 @@ static bool IBinaryInteger<UInt128>.TryReadLittleEndian(ReadOnlySpan<byte> sourc
/// <inheritdoc cref="IBinaryInteger{TSelf}.GetShortestBitLength()" />
int IBinaryInteger<UInt128>.GetShortestBitLength()
{
UInt128 value = this;
return (Size * 8) - BitOperations.LeadingZeroCount(value);
return (Size * 8) - LeadingZeroCountAsInt32(this);
}

/// <inheritdoc cref="IBinaryInteger{TSelf}.GetByteCount()" />
Expand Down Expand Up @@ -1158,7 +1162,7 @@ unsafe static UInt128 DivideSlow(UInt128 quotient, UInt128 divisor)
Unsafe.WriteUnaligned(ref *(byte*)(pLeft + 2), (uint)(quotient._upper >> 00));
Unsafe.WriteUnaligned(ref *(byte*)(pLeft + 3), (uint)(quotient._upper >> 32));

Span<uint> left = new Span<uint>(pLeft, (Size / sizeof(uint)) - (BitOperations.LeadingZeroCount(quotient) / 32));
Span<uint> left = new Span<uint>(pLeft, (Size / sizeof(uint)) - (LeadingZeroCountAsInt32(quotient) / 32));

// Repeat the same operation with the divisor

Expand All @@ -1170,7 +1174,7 @@ unsafe static UInt128 DivideSlow(UInt128 quotient, UInt128 divisor)
Unsafe.WriteUnaligned(ref *(byte*)(pRight + 2), (uint)(divisor._upper >> 00));
Unsafe.WriteUnaligned(ref *(byte*)(pRight + 3), (uint)(divisor._upper >> 32));

Span<uint> right = new Span<uint>(pRight, (Size / sizeof(uint)) - (BitOperations.LeadingZeroCount(divisor) / 32));
Span<uint> right = new Span<uint>(pRight, (Size / sizeof(uint)) - (LeadingZeroCountAsInt32(divisor) / 32));

Span<uint> rawBits = stackalloc uint[Size / sizeof(uint)];
rawBits.Clear();
Expand Down

0 comments on commit 93c1912

Please sign in to comment.