令我惊讶的是,与 Vector256 不同,Vector64 中的 ExtractMostSignificantBits 函数并没有使用内部函数来完成工作。使用内部函数后,以下 36 行代码如下:
mov qword ptr [rsp+0x80], r12
movzx rdx, byte ptr [rsp+0x80]
shr edx, 7
movzx r8, byte ptr [rsp+0x81]
shr r8d, 7
add r8d, r8d
or edx, r8d
movzx r8, byte ptr [rsp+0x82]
shr r8d, 7
shl r8d, 2
or r8d, edx
mov edx, r8d
movzx r8, byte ptr [rsp+0x83]
shr r8d, 7
shl r8d, 3
or r8d, edx
mov edx, r8d
movzx r8, byte ptr [rsp+0x84]
shr r8d, 7
shl r8d, 4
or r8d, edx
mov edx, r8d
movzx r8, byte ptr [rsp+0x85]
shr r8d, 7
shl r8d, 5
or r8d, edx
mov edx, r8d
movzx r8, byte ptr [rsp+0x86]
shr r8d, 7
shl r8d, 6
or r8d, edx
mov edx, r8d
movzx r8, byte ptr [rsp+0x87]
shr r8d, 7
shl r8d, 7
or r8d, edx
分为这4个:
mov qword ptr [rsp+0x70], rcx
mov r10, qword ptr [rsp+0x70]
mov r15, 0x8080808080808080
pext r10, r10, r15
似乎你可以用这样的方法将它卷入Vector64.cs :
public static uint ExtractMostSignificantBits<T>(this Vector64<T> vector)
{
if (Bmi2.X64.IsSupported)
{
ulong mask = 0;
if (typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte))
mask = 0x8080808080808080;
else if (typeof(T) == typeof(short) || typeof(T) == typeof(ushort))
mask = 0x8000800080008000;
else if (typeof(T) == typeof(int) || typeof(T) == typeof(uint) || typeof(T) == typeof(float))
mask = 0x8000000080000000;
else if (typeof(T) == typeof(long) || typeof(T) == typeof(ulong) || typeof(T) == typeof(double))
mask = 0x8000000000000000;
else if (typeof(T) == typeof(nint) || typeof(T) == typeof(nuint))
if (IntPtr.Size == 4)
mask = 0x8000000080000000;
else
mask = 0x8000000000000000;
ulong u = vector._00;
ulong retval = Bmi2.X64.ParallelBitExtract(u, mask);
return (uint)retval;
}
// Fall back to the old code
uint result = 0;
for (int index = 0; index < Vector64<T>.Count; index++)
{
uint value = Scalar<T>.ExtractMostSignificantBit(vector.GetElementUnsafe(index));
result |= (value << index);
}
return result;
}
BMI2 已经不算“新”了,早在 2013 年左右就已推出。而且,考虑到 JIT 编译,这样做成本也不高。
我已经编写了一些测试代码(可根据要求提供),它产生的结果与现有代码相同,只是速度快了两倍多(如果对 Vector64.GetElementUnsafe 进行一些改进,速度可能会更快)。
我是不是忽略了什么细微差别或特殊情况,导致使用内在函数不可接受?还是有人只是忽略了这一点?