Fiquei surpreso ao ver que, ao contrário do Vector256, o ExtractMostSignificantBits do Vector64 não usa um intrínseco para fazer seu trabalho. Usar o intrínseco transforma estas 36 linhas:
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
Nestes 4:
mov qword ptr [rsp+0x70], rcx
mov r10, qword ptr [rsp+0x70]
mov r15, 0x8080808080808080
pext r10, r10, r15
Parece que você poderia implementá-lo no Vector64.cs com algo assim:
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;
}
Não é como se o BMI2 fosse mais "novo", tendo sido introduzido por volta de 2013. Além disso, considerando a compilação JIT, não há muito custo em fazê-lo dessa maneira.
Eu escrevi um código de teste (disponível mediante solicitação) e ele produz os mesmos resultados que o código existente, apenas um pouco mais que o dobro da velocidade (possivelmente ainda mais rápido com algumas melhorias no Vector64.GetElementUnsafe).
Há alguma nuance ou caso especial aqui que eu tenha esquecido e que torna o uso do intrínseco inaceitável? Ou alguém simplesmente esqueceu disso?