使用C#系统..数字.向量<;T>;拆包/打包

使用C#系统..数字.向量<;T>;拆包/打包,c#,vector,bitwise-operators,simd,system.numerics,C#,Vector,Bitwise Operators,Simd,System.numerics,我正在测试.Net C#System.Numerics.Vector类打包和解包位的能力 我希望有向量按位左/右移位功能,但目前还没有,所以我尝试使用如下算术和逻辑方法模拟移位。以下是我看到的: 使用Vector.Multiply()和Vector.BitwiseOr()进行打包(模拟按位左移和或)比数组/指针代码稍微差一点 *>IL /// non-SIMD fallback implementation for 128-bit right-shift (unsigned) /// n: nu

我正在测试.Net C#System.Numerics.Vector类打包和解包位的能力

我希望有向量按位左/右移位功能,但目前还没有,所以我尝试使用如下算术和逻辑方法模拟移位。以下是我看到的:

使用Vector.Multiply()和Vector.BitwiseOr()进行打包(模拟按位左移和或)比数组/指针代码稍微差一点

*>IL

/// non-SIMD fallback implementation for 128-bit right-shift (unsigned)
/// n: number of bit positions to right-shift a 16-byte memory image.
/// Vector(T) argument 'v' is passed by-ref and modified in-situ.
/// Layout order of the two 64-bit quads is little-endian.

.method public static void SHR(Vector_T<uint64>& v, int32 n) aggressiveinlining
{
    ldarg v
    dup
    dup
    ldc.i4.8
    add
    ldind.i8
    ldc.i4.s 64
    ldarg n
    sub
    shl

    ldarg v
    ldind.i8
    ldarg n
    shr.un

    or
    stind.i8

    ldc.i4.8
    add
    dup
    ldind.i8
    ldarg n
    shr.un
    stind.i8

    ret
}

与左移乘法不同,右移除法仅适用于无符号整数。如果您使用的是有符号整数,那么编译器就不能安全地使用移位优化除法。@PaulR:可以,只需要一些额外的指令来处理算术右移与有符号除法之间的舍入差异。有关
v4si-div2(v4si-v){return v/2;}
的gcc/clang输出,请参阅,其中v4si是32位
int
的GNU C本机向量。其他除数的代码生成很有趣;2的幂仍然很便宜,其他除数会给你一个乘法逆。@PeterCordes:是的,我主要考虑的是2的幂,并直接转换为一个移位指令,但是的,当然还有进一步的优化来处理其他除数和带符号值的除法等,虽然这些方法的好处并不是很显著,但我确实使用了Vector。所以:我仔细检查了我的测试,然后想知道AND、XOR、>>和>的位运算符与&的位运算符之间是否存在固有的速度差异。这听起来对吗?据我所知,CLR根本没有对除法进行优化。在经过优化的代码中,这仍然会生成一个对通用“除以某个向量”方法的函数调用—右侧操作数为常量的情况将被忽略。
/// non-SIMD fallback implementation for 128-bit right-shift (unsigned)
/// n: number of bit positions to right-shift a 16-byte memory image.
/// Vector(T) argument 'v' is passed by-ref and modified in-situ.
/// Layout order of the two 64-bit quads is little-endian.

.method public static void SHR(Vector_T<uint64>& v, int32 n) aggressiveinlining
{
    ldarg v
    dup
    dup
    ldc.i4.8
    add
    ldind.i8
    ldc.i4.s 64
    ldarg n
    sub
    shl

    ldarg v
    ldind.i8
    ldarg n
    shr.un

    or
    stind.i8

    ldc.i4.8
    add
    dup
    ldind.i8
    ldarg n
    shr.un
    stind.i8

    ret
}
As<Vector<ulong>,ulong>(ref v) = (As<Vector<ulong>,ulong>(in v) >> n) | 
                                  (ByteOffsAs<Vector<ulong>,ulong>(in v, 8) << (64 - n));
ByteOffsAs<Vector<ulong>,ulong>(ref v, 8) >>= n;
static class vector_ext
{
    [MethodImpl(MethodImplOptions.ForwardRef | MethodImplOptions.AggressiveInlining)]
    extern public static void SHR(ref Vector<ulong> v, int n);
};
0x7FF878F5C7E0    48 89 4C 24 08       mov qword ptr [rsp+8],rcx
0x7FF878F5C7E5    8B C2                mov eax,edx
0x7FF878F5C7E7    F7 D8                neg eax
0x7FF878F5C7E9    8D 48 40             lea ecx,[rax+40h]
0x7FF878F5C7EC    48 8B 44 24 08       mov rax,qword ptr [rsp+8]
0x7FF878F5C7F1    4C 8B 40 08          mov r8,qword ptr [rax+8]
0x7FF878F5C7F5    49 D3 E0             shl r8,cl
0x7FF878F5C7F8    4C 8B 08             mov r9,qword ptr [rax]
0x7FF878F5C7FB    8B CA                mov ecx,edx
0x7FF878F5C7FD    49 D3 E9             shr r9,cl
0x7FF878F5C800    4D 0B C1             or  r8,r9
0x7FF878F5C803    4C 89 00             mov qword ptr [rax],r8
0x7FF878F5C806    48 83 C0 08          add rax,8
0x7FF878F5C80A    8B CA                mov ecx,edx
0x7FF878F5C80C    48 D3 28             shr qword ptr [rax],cl
0x7FF878F5C80F    C3                   ret