From a60c2206ca3e08a1a49881c40d843eccadd5bc7f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 27 Apr 2020 09:23:45 -0700 Subject: [PATCH 1/6] Intrinsicy BitOperations.PopCount() for arm64 --- .../src/System/Numerics/BitOperations.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 c8356a0c9eb01d..8b0a1b61fdfbcf 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; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; @@ -243,6 +244,14 @@ public static int PopCount(uint value) return (int)Popcnt.PopCount(value); } + if (AdvSimd.IsSupported && AdvSimd.Arm64.IsSupported) + { + // PopCount works on vector so convert input value to vector first. + Vector64 input = Vector64.CreateScalar(value); + Vector64 aggregated = AdvSimd.Arm64.AddAcross(AdvSimd.PopCount(input.AsByte())); + return (int)AdvSimd.Extract(aggregated, 0); + } + return SoftwareFallback(value); static int SoftwareFallback(uint value) @@ -274,6 +283,14 @@ public static int PopCount(ulong value) return (int)Popcnt.X64.PopCount(value); } + if (AdvSimd.IsSupported && AdvSimd.Arm64.IsSupported) + { + // PopCount works on vector so convert input value to vector first. + Vector128 input = Vector128.CreateScalar(value); + Vector64 aggregated = AdvSimd.Arm64.AddAcross(AdvSimd.PopCount(input.AsByte())); + return (int)AdvSimd.Extract(aggregated, 0); + } + #if TARGET_32BIT return PopCount((uint)value) // lo + PopCount((uint)(value >> 32)); // hi From aa02fafe5e59fcfc458431a2d6d2ec61a18f0ea9 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 6 May 2020 18:43:57 -0700 Subject: [PATCH 2/6] Review feedback --- .../src/System/Numerics/BitOperations.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) 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 8b0a1b61fdfbcf..c25800b1e82fee 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs @@ -244,12 +244,9 @@ public static int PopCount(uint value) return (int)Popcnt.PopCount(value); } - if (AdvSimd.IsSupported && AdvSimd.Arm64.IsSupported) + if (AdvSimd.IsSupported) { - // PopCount works on vector so convert input value to vector first. - Vector64 input = Vector64.CreateScalar(value); - Vector64 aggregated = AdvSimd.Arm64.AddAcross(AdvSimd.PopCount(input.AsByte())); - return (int)AdvSimd.Extract(aggregated, 0); + return PopCount((ulong)value); } return SoftwareFallback(value); @@ -283,12 +280,12 @@ public static int PopCount(ulong value) return (int)Popcnt.X64.PopCount(value); } - if (AdvSimd.IsSupported && AdvSimd.Arm64.IsSupported) + if (AdvSimd.IsSupported) { // PopCount works on vector so convert input value to vector first. - Vector128 input = Vector128.CreateScalar(value); + Vector64 input = Vector64.Create(value); Vector64 aggregated = AdvSimd.Arm64.AddAcross(AdvSimd.PopCount(input.AsByte())); - return (int)AdvSimd.Extract(aggregated, 0); + return AdvSimd.Extract(aggregated, 0); } #if TARGET_32BIT From 2c90fd386236f30b43b208eee1097d3f3a98fc62 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 7 May 2020 14:13:45 -0700 Subject: [PATCH 3/6] Add shims inside System.Utf8String.Experimental project --- .../Runtime/Intrinsics/Intrinsics.Shims.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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 91059ddbeb3a59..036a89aded4ca6 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 @@ -4,6 +4,16 @@ namespace System.Runtime.Intrinsics { + internal static class Vector64 + { + public static Vector64 Create(ulong value) => throw new PlatformNotSupportedException(); + } + internal readonly struct Vector64 + where T : struct + { + public static Vector64 AsByte(this Vector64 vector) => throw new PlatformNotSupportedException(); + } + internal static class Vector128 { public static Vector128 Create(short value) => throw new PlatformNotSupportedException(); @@ -130,4 +140,15 @@ public abstract class Arm64 public static int LeadingZeroCount(uint value) => throw new PlatformNotSupportedException(); public static uint ReverseElementBits(uint value) => throw new PlatformNotSupportedException(); } + + internal abstract class AdvSimd : ArmBase + { + public abstract class Arm64 + { + public static Vector64 AddAcross(Vector64 value) => throw new PlatformNotSupportedException(); + } + public const bool IsSupported = false; + public static byte Extract(Vector64 vector, byte index) => throw new PlatformNotSupportedException(); + public static Vector64 PopCount(Vector64 value) => throw new PlatformNotSupportedException(); + } } From 8d9f456b3f61b660e4cfa561f5cf8c55830954ef Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 7 May 2020 14:49:42 -0700 Subject: [PATCH 4/6] Have own implementation of PopCount(uint) --- .../src/System/Numerics/BitOperations.cs | 14 +++++++++++--- .../System/Runtime/Intrinsics/Intrinsics.Shims.cs | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) 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 c25800b1e82fee..ddb0b19ae38d96 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs @@ -244,9 +244,17 @@ public static int PopCount(uint value) return (int)Popcnt.PopCount(value); } - if (AdvSimd.IsSupported) + if (AdvSimd.Arm64.IsSupported) { - return PopCount((ulong)value); + // PopCount works on vector so convert input value to vector first. + + // Vector64.CreateScalar(uint) generates suboptimal code by storing and + // loading the result to memory. + // See https://github.com/dotnet/runtime/issues/35976 for details. + // Hence use Vector4.Create(ulong) to create Vector64 and operate on that. + Vector64 input = Vector64.Create((ulong)value); + Vector64 aggregated = AdvSimd.Arm64.AddAcross(AdvSimd.PopCount(input.AsByte())); + return AdvSimd.Extract(aggregated, 0); } return SoftwareFallback(value); @@ -280,7 +288,7 @@ public static int PopCount(ulong value) return (int)Popcnt.X64.PopCount(value); } - if (AdvSimd.IsSupported) + if (AdvSimd.Arm64.IsSupported) { // PopCount works on vector so convert input value to vector first. Vector64 input = Vector64.Create(value); 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 036a89aded4ca6..024d7250178333 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 @@ -145,9 +145,9 @@ internal abstract class AdvSimd : ArmBase { public abstract class Arm64 { + public const bool IsSupported = false; public static Vector64 AddAcross(Vector64 value) => throw new PlatformNotSupportedException(); } - public const bool IsSupported = false; public static byte Extract(Vector64 vector, byte index) => throw new PlatformNotSupportedException(); public static Vector64 PopCount(Vector64 value) => throw new PlatformNotSupportedException(); } From b6ee903de7bbd4f7fd5b66156ecf18f9aebc9ebf Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 7 May 2020 16:14:06 -0700 Subject: [PATCH 5/6] fix another build failure --- .../src/System/Runtime/Intrinsics/Intrinsics.Shims.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 024d7250178333..e1654081c77662 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 @@ -7,11 +7,11 @@ namespace System.Runtime.Intrinsics internal static class Vector64 { public static Vector64 Create(ulong value) => throw new PlatformNotSupportedException(); + public static Vector64 AsByte(this Vector64 vector) where T : struct => throw new PlatformNotSupportedException(); } internal readonly struct Vector64 where T : struct { - public static Vector64 AsByte(this Vector64 vector) => throw new PlatformNotSupportedException(); } internal static class Vector128 @@ -143,9 +143,8 @@ public abstract class Arm64 internal abstract class AdvSimd : ArmBase { - public abstract class Arm64 + public new abstract class Arm64 : ArmBase.Arm64 { - public const bool IsSupported = false; public static Vector64 AddAcross(Vector64 value) => throw new PlatformNotSupportedException(); } public static byte Extract(Vector64 vector, byte index) => throw new PlatformNotSupportedException(); From 9c89853f46f6b475f48f9ac3727462817ec498a5 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 7 May 2020 22:31:15 -0700 Subject: [PATCH 6/6] Fix the comment. Co-authored-by: Tanner Gooding --- .../System.Private.CoreLib/src/System/Numerics/BitOperations.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ddb0b19ae38d96..fe457200e960d3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs @@ -251,7 +251,7 @@ public static int PopCount(uint value) // Vector64.CreateScalar(uint) generates suboptimal code by storing and // loading the result to memory. // See https://github.com/dotnet/runtime/issues/35976 for details. - // Hence use Vector4.Create(ulong) to create Vector64 and operate on that. + // Hence use Vector64.Create(ulong) to create Vector64 and operate on that. Vector64 input = Vector64.Create((ulong)value); Vector64 aggregated = AdvSimd.Arm64.AddAcross(AdvSimd.PopCount(input.AsByte())); return AdvSimd.Extract(aggregated, 0);