Базовая реализация (до применения оптимизаций, таких как описанные Питером в комментариях) может работать следующим образом:
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
для небезопасного чтения, без созданиявектор из диапазона (или массива тоже) гораздо менее эффективен.Кстати, встроенная EqualsAny
реализована с (v)ptest
вместо (v)pmovmskb
, ptest
обычно стоит больше мопов, поэтому сравнительно важнее минимизировать его влияние - но поскольку прямого доступа к ptest
нет илиpmovmskb
окончательный "вектор к условию" 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;
}