Skip to content

Commit 510efdf

Browse files
authored
BitOperations arm64 intrinsic for LeadingZeroCount, TrailingZeroCount and Log2 (#34486)
ARM64 intrinsic for: - LeadingZeroCount - Log2 - TrailingZeroCount
1 parent 2f209e6 commit 510efdf

File tree

2 files changed

+58
-12
lines changed

2 files changed

+58
-12
lines changed

src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System.Runtime.CompilerServices;
66
using System.Runtime.InteropServices;
7+
using System.Runtime.Intrinsics.Arm;
78
using System.Runtime.Intrinsics.X86;
89

910
#if SYSTEM_PRIVATE_CORELIB
@@ -61,6 +62,11 @@ public static int LeadingZeroCount(uint value)
6162
return (int)Lzcnt.LeadingZeroCount(value);
6263
}
6364

65+
if (ArmBase.IsSupported)
66+
{
67+
return ArmBase.LeadingZeroCount(value);
68+
}
69+
6470
// Unguarded fallback contract is 0->31
6571
if (value == 0)
6672
{
@@ -85,6 +91,11 @@ public static int LeadingZeroCount(ulong value)
8591
return (int)Lzcnt.X64.LeadingZeroCount(value);
8692
}
8793

94+
if (ArmBase.Arm64.IsSupported)
95+
{
96+
return ArmBase.Arm64.LeadingZeroCount(value);
97+
}
98+
8899
uint hi = (uint)(value >> 32);
89100

90101
if (hi == 0)
@@ -104,6 +115,12 @@ public static int LeadingZeroCount(ulong value)
104115
[CLSCompliant(false)]
105116
public static int Log2(uint value)
106117
{
118+
// Enforce conventional contract 0->0 (Log(0) is undefined)
119+
if (value == 0)
120+
{
121+
return 0;
122+
}
123+
107124
// value lzcnt actual expected
108125
// ..0000 32 0 0 (by convention, guard clause)
109126
// ..0001 31 31-31 0
@@ -113,16 +130,15 @@ public static int Log2(uint value)
113130
// 1000.. 0 31-0 31
114131
if (Lzcnt.IsSupported)
115132
{
116-
// Enforce conventional contract 0->0 (Log(0) is undefined)
117-
if (value == 0)
118-
{
119-
return 0;
120-
}
121-
122133
// LZCNT contract is 0->32
123134
return 31 - (int)Lzcnt.LeadingZeroCount(value);
124135
}
125136

137+
if (ArmBase.IsSupported)
138+
{
139+
return 31 - ArmBase.LeadingZeroCount(value);
140+
}
141+
126142
// Fallback contract is 0->0
127143
return Log2SoftwareFallback(value);
128144
}
@@ -136,18 +152,23 @@ public static int Log2(uint value)
136152
[CLSCompliant(false)]
137153
public static int Log2(ulong value)
138154
{
139-
if (Lzcnt.X64.IsSupported)
155+
// Enforce conventional contract 0->0 (Log(0) is undefined)
156+
if (value == 0)
140157
{
141-
// Enforce conventional contract 0->0 (Log(0) is undefined)
142-
if (value == 0)
143-
{
144-
return 0;
145-
}
158+
return 0;
159+
}
146160

161+
if (Lzcnt.X64.IsSupported)
162+
{
147163
// LZCNT contract is 0->64
148164
return 63 - (int)Lzcnt.X64.LeadingZeroCount(value);
149165
}
150166

167+
if (ArmBase.Arm64.IsSupported)
168+
{
169+
return 63 - ArmBase.Arm64.LeadingZeroCount(value);
170+
}
171+
151172
uint hi = (uint)(value >> 32);
152173

153174
if (hi == 0)
@@ -275,6 +296,11 @@ public static int TrailingZeroCount(uint value)
275296
return (int)Bmi1.TrailingZeroCount(value);
276297
}
277298

299+
if (ArmBase.IsSupported)
300+
{
301+
return ArmBase.LeadingZeroCount(ArmBase.ReverseElementBits(value));
302+
}
303+
278304
// Unguarded fallback contract is 0->0
279305
if (value == 0)
280306
{
@@ -313,6 +339,10 @@ public static int TrailingZeroCount(ulong value)
313339
return (int)Bmi1.X64.TrailingZeroCount(value);
314340
}
315341

342+
if (ArmBase.Arm64.IsSupported)
343+
{
344+
return ArmBase.Arm64.LeadingZeroCount(ArmBase.Arm64.ReverseElementBits(value));
345+
}
316346
uint lo = (uint)value;
317347

318348
if (lo == 0)

src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,19 @@ public abstract class X64
103103
public static bool TestZ(Vector128<ushort> left, Vector128<ushort> right) => throw new PlatformNotSupportedException();
104104
}
105105
}
106+
107+
namespace System.Runtime.Intrinsics.Arm
108+
{
109+
internal abstract class ArmBase
110+
{
111+
public abstract class Arm64
112+
{
113+
public const bool IsSupported = false;
114+
public static int LeadingZeroCount(ulong value) => throw new PlatformNotSupportedException();
115+
public static uint ReverseElementBits(ulong value) => throw new PlatformNotSupportedException();
116+
}
117+
public const bool IsSupported = false;
118+
public static int LeadingZeroCount(uint value) => throw new PlatformNotSupportedException();
119+
public static uint ReverseElementBits(uint value) => throw new PlatformNotSupportedException();
120+
}
121+
}

0 commit comments

Comments
 (0)