首页 > 解决方案 > 用于替换值的内部 SIMD 指令

问题描述

我想知道如何替换字节值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
        }

标签: c#simdintrinsics

解决方案


指令是pshufb在现代 .NET 中作为Avx2.ShuffleSsse3.Shuffle用于 16 字节版本。在现代 CPU 上,两者都非常快,只有 1 个周期的延迟。

将源数据传递给 shuffle control mask 参数,第一个参数的特殊值是被洗牌的字节,如下所示:

// 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 );
}

有关详细信息,请参阅本文_mm_shuffle_epi8第 18 页的部分。

更新:如果您没有 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 中存在一个性能问题,它阻止编译器在循环之外加载常量。如果您要在循环中调用该方法并希望最大化性能,请考虑将两个常量向量(0 和 2)作为方法参数传递。


推荐阅读