diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs index 2506043f6f7215..9844240e1058a3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs @@ -4,6 +4,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; #if SYSTEM_PRIVATE_CORELIB @@ -61,6 +62,11 @@ public static int LeadingZeroCount(uint value) return (int)Lzcnt.LeadingZeroCount(value); } + if (ArmBase.IsSupported) + { + return ArmBase.LeadingZeroCount(value); + } + // Unguarded fallback contract is 0->31 if (value == 0) { @@ -85,6 +91,11 @@ public static int LeadingZeroCount(ulong value) return (int)Lzcnt.X64.LeadingZeroCount(value); } + if (ArmBase.Arm64.IsSupported) + { + return ArmBase.Arm64.LeadingZeroCount(value); + } + uint hi = (uint)(value >> 32); if (hi == 0) @@ -104,6 +115,12 @@ public static int LeadingZeroCount(ulong value) [CLSCompliant(false)] public static int Log2(uint value) { + // Enforce conventional contract 0->0 (Log(0) is undefined) + if (value == 0) + { + return 0; + } + // value lzcnt actual expected // ..0000 32 0 0 (by convention, guard clause) // ..0001 31 31-31 0 @@ -113,16 +130,15 @@ public static int Log2(uint value) // 1000.. 0 31-0 31 if (Lzcnt.IsSupported) { - // Enforce conventional contract 0->0 (Log(0) is undefined) - if (value == 0) - { - return 0; - } - // LZCNT contract is 0->32 return 31 - (int)Lzcnt.LeadingZeroCount(value); } + if (ArmBase.IsSupported) + { + return 31 - ArmBase.LeadingZeroCount(value); + } + // Fallback contract is 0->0 return Log2SoftwareFallback(value); } @@ -136,18 +152,23 @@ public static int Log2(uint value) [CLSCompliant(false)] public static int Log2(ulong value) { - if (Lzcnt.X64.IsSupported) + // Enforce conventional contract 0->0 (Log(0) is undefined) + if (value == 0) { - // Enforce conventional contract 0->0 (Log(0) is undefined) - if (value == 0) - { - return 0; - } + return 0; + } + if (Lzcnt.X64.IsSupported) + { // LZCNT contract is 0->64 return 63 - (int)Lzcnt.X64.LeadingZeroCount(value); } + if (ArmBase.Arm64.IsSupported) + { + return 63 - ArmBase.Arm64.LeadingZeroCount(value); + } + uint hi = (uint)(value >> 32); if (hi == 0) @@ -275,6 +296,11 @@ public static int TrailingZeroCount(uint value) return (int)Bmi1.TrailingZeroCount(value); } + if (ArmBase.IsSupported) + { + return ArmBase.LeadingZeroCount(ArmBase.ReverseElementBits(value)); + } + // Unguarded fallback contract is 0->0 if (value == 0) { @@ -313,6 +339,10 @@ public static int TrailingZeroCount(ulong value) return (int)Bmi1.X64.TrailingZeroCount(value); } + if (ArmBase.Arm64.IsSupported) + { + return ArmBase.Arm64.LeadingZeroCount(ArmBase.Arm64.ReverseElementBits(value)); + } uint lo = (uint)value; if (lo == 0) diff --git a/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs b/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs index 12fba80e1a98f2..33c59a3f122db9 100644 --- a/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs +++ b/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs @@ -103,3 +103,19 @@ public abstract class X64 public static bool TestZ(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); } } + +namespace System.Runtime.Intrinsics.Arm +{ + internal abstract class ArmBase + { + public abstract class Arm64 + { + public const bool IsSupported = false; + public static int LeadingZeroCount(ulong value) => throw new PlatformNotSupportedException(); + public static uint ReverseElementBits(ulong value) => throw new PlatformNotSupportedException(); + } + public const bool IsSupported = false; + public static int LeadingZeroCount(uint value) => throw new PlatformNotSupportedException(); + public static uint ReverseElementBits(uint value) => throw new PlatformNotSupportedException(); + } +}