用于替换值的内在 SIMD 指令
Intrinsics SIMD instruction to replace values
我想知道如何替换 Vector128<byte>
中的字节值
我认为假设下面的代码我们有一个 resultvector
是可以的
这些值:
<0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0>
这里我想创建一个新向量,其中所有“0”都将替换为“2”
并且所有“1”将被替换为“0”,如下所示:
<2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2>
我不确定这是否有内在函数或如何实现?
谢谢!
//Create array
byte[] array = new byte[16];
for (int i = 0; i < 4; i++) { array[i] = 0; }
for (int i = 4; i < 8; i++) { array[i] = 1; }
for (int i = 8; i < 16; i++) { array[i] = 0; }
fixed (byte* ptr = array)
{
byte* pointarray = &*((byte*)(ptr + 0));
System.Runtime.Intrinsics.Vector128<byte> resultvector = System.Runtime.Intrinsics.X86.Avx.LoadVector128(&pointarray[0]);
//<0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0>
//resultvector
}
该指令是 pshufb
,在现代 .NET 中可作为 16 字节版本的 Avx2.Shuffle, and Ssse3.Shuffle 使用。两者都非常快,在现代 CPU 上有 1 个周期的延迟。
将您的源数据传递到洗牌控制掩码参数中,并将第一个参数的特殊值传递给正在洗牌的字节,如下所示:
// Create AVX vector with all zeros except the first byte in each 16-byte lane which is 2
static Vector256<byte> makeShufflingVector()
{
Vector128<byte> res = Vector128<byte>.Zero;
res = Sse2.Insert( res.AsInt16(), 2, 0 ).AsByte();
return Vector256.Create( res, res );
}
有关详细信息,请参阅 this article 第 18 页的 _mm_shuffle_epi8
部分。
更新:如果你没有SSSE3,你可以在SSE2中做同样的事情,用2条指令代替1条指令:
static Vector128<byte> replaceZeros( Vector128<byte> src )
{
src = Sse2.CompareEqual( src, Vector128<byte>.Zero );
return Sse2.And( src, Vector128.Create( (byte)2 ) );
}
顺便说一下,.NET 中有一个 performance problem 可以防止编译器在循环外加载常量。如果您要在循环中调用该方法并希望最大限度地提高性能,请考虑传递两个常量向量(0 和 2)作为方法参数。
我想知道如何替换 Vector128<byte>
我认为假设下面的代码我们有一个 resultvector
是可以的
这些值:
<0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0>
这里我想创建一个新向量,其中所有“0”都将替换为“2” 并且所有“1”将被替换为“0”,如下所示: <2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2>
我不确定这是否有内在函数或如何实现?
谢谢!
//Create array
byte[] array = new byte[16];
for (int i = 0; i < 4; i++) { array[i] = 0; }
for (int i = 4; i < 8; i++) { array[i] = 1; }
for (int i = 8; i < 16; i++) { array[i] = 0; }
fixed (byte* ptr = array)
{
byte* pointarray = &*((byte*)(ptr + 0));
System.Runtime.Intrinsics.Vector128<byte> resultvector = System.Runtime.Intrinsics.X86.Avx.LoadVector128(&pointarray[0]);
//<0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0>
//resultvector
}
该指令是 pshufb
,在现代 .NET 中可作为 16 字节版本的 Avx2.Shuffle, and Ssse3.Shuffle 使用。两者都非常快,在现代 CPU 上有 1 个周期的延迟。
将您的源数据传递到洗牌控制掩码参数中,并将第一个参数的特殊值传递给正在洗牌的字节,如下所示:
// Create AVX vector with all zeros except the first byte in each 16-byte lane which is 2
static Vector256<byte> makeShufflingVector()
{
Vector128<byte> res = Vector128<byte>.Zero;
res = Sse2.Insert( res.AsInt16(), 2, 0 ).AsByte();
return Vector256.Create( res, res );
}
有关详细信息,请参阅 this article 第 18 页的 _mm_shuffle_epi8
部分。
更新:如果你没有SSSE3,你可以在SSE2中做同样的事情,用2条指令代替1条指令:
static Vector128<byte> replaceZeros( Vector128<byte> src )
{
src = Sse2.CompareEqual( src, Vector128<byte>.Zero );
return Sse2.And( src, Vector128.Create( (byte)2 ) );
}
顺便说一下,.NET 中有一个 performance problem 可以防止编译器在循环外加载常量。如果您要在循环中调用该方法并希望最大限度地提高性能,请考虑传递两个常量向量(0 和 2)作为方法参数。