使用 SIMD 查找 Span 中是否存在'ushort'的最快方法<ushort>?



在.NET Core上的C#中,我正在寻找最快的方法来检查给定的ushort值是否存在于Span<ushort>范围内。幼稚的选项包括枚举跨度,但我强烈怀疑通过SIMD(即SSE或AVX(存在速度更快的单核选项。

这里最快的选项是什么?(不安全代码可以(

一个基本实现(在应用诸如Peter在评论中描述的优化之前(可能是这样工作的:

static unsafe bool ContainsUshort(Span<ushort> data, ushort val)
{
int vecSize = Vector<ushort>.Count;
var value = new Vector<ushort>(val);
int i;
fixed (ushort* ptr = &data[0])
{
int limit = data.Length - vecSize;
for (i = 0; i <= limit; i += vecSize)
{
var d = Unsafe.ReadUnaligned<Vector<ushort>>(ptr + i);
if (Vector.EqualsAny(d, value))
return true;
}
}
for (; i < data.Length; i++)
{
if (data[i] == val)
return true;
}
return false;
}

这需要System.Runtime.CompilerServices.Unsafe包来进行不安全的读取,否则从跨度(或数组(创建向量的效率会低得多。通过用(v)ptest而不是(v)pmovmskb实现EqualsAny内在的方式,ptest通常花费更多的µops,因此将其影响减到最小相对更重要-但由于没有对ptestpmovmskb的直接访问(可以通过使用较新的特定于平台的System.Runtime.Intrinsics.X86API来避免这种限制(;向量到条件";AFAIK仍然需要用Vector.EqualsAny(用0xFFFF填充向量(来完成,这有点傻。。尽管如此,它在我的机器上还是快了一点(经过测试,返回值将为false,因此未展开版本的稍早退出没有发挥作用(

var allSet = new Vector<ushort>(0xFFFF);
int limit = data.Length - vecSize * 2;
for (i = 0; i <= limit; i += vecSize * 2)
{
var d0 = Unsafe.ReadUnaligned<Vector<ushort>>(ptr + i);
var d1 = Unsafe.ReadUnaligned<Vector<ushort>>(ptr + i + vecSize);
var eq = Vector.Equals(d0, value) | Vector.Equals(d1, value);
if (Vector.EqualsAny(eq, allSet))
return true;
}

最新更新