使用C#系统..数字.向量<;T>;拆包/打包
我正在测试.Net C#System.Numerics.Vector类打包和解包位的能力 我希望有向量按位左/右移位功能,但目前还没有,所以我尝试使用如下算术和逻辑方法模拟移位。以下是我看到的: 使用Vector.Multiply()和Vector.BitwiseOr()进行打包(模拟按位左移和或)比数组/指针代码稍微差一点 *>IL使用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
/// 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