fixed (byte* pBytes = &_asciiBytes[0])
fixed (char* pString = _asciiString)
{
- TryGetAsciiStringVectorized(pBytes, pString, _asciiBytes.Length);
+ TryGetAsciiStringVectorWiden(pBytes, pString, _asciiBytes.Length);
}
if (String.Compare(_asciiString, compareString) != 0)
{
return 100;
}
- public static unsafe bool TryGetAsciiStringVectorized(byte* input, char* output, int count)
+ public static unsafe bool TryGetAsciiStringVectorWiden(byte* input, char* output, int count)
+
{
// Calcuate end position
var end = input + count;
+
// Start as valid
var isValid = true;
- if (Vector.IsHardwareAccelerated && count >= Vector<sbyte>.Count)
- {
- // Jump forward to vector code to reduced cost when smaller than vector size
- // - by default, forward jumps are predicted non-taken and near code is hotter in instruction decode
- // When larger than Vector, vectorization will be able to make the cost back
- goto Vectorized;
- }
-
- NonVectorized:
- if (IntPtr.Size == 8) // Use Intrinsic switch for branch elimination
+ do
{
- // 64-bit: Loop longs by default
- while (input <= end - sizeof(long))
+ // If Vector not-accelerated or remaining less than vector size
+ if (!Vector.IsHardwareAccelerated || input > end - Vector<sbyte>.Count)
{
- isValid &= CheckBytesInAsciiRange(((long*)input)[0]);
-
- output[0] = (char)input[0];
- output[1] = (char)input[1];
- output[2] = (char)input[2];
- output[3] = (char)input[3];
- output[4] = (char)input[4];
- output[5] = (char)input[5];
- output[6] = (char)input[6];
- output[7] = (char)input[7];
-
- input += sizeof(long);
- output += sizeof(long);
+ if (IntPtr.Size == 8) // Use Intrinsic switch for branch elimination
+ {
+ // 64-bit: Loop longs by default
+ while (input <= end - sizeof(long))
+ {
+ isValid &= CheckBytesInAsciiRange(((long*)input)[0]);
+
+ output[0] = (char)input[0];
+ output[1] = (char)input[1];
+ output[2] = (char)input[2];
+ output[3] = (char)input[3];
+ output[4] = (char)input[4];
+ output[5] = (char)input[5];
+ output[6] = (char)input[6];
+ output[7] = (char)input[7];
+
+ input += sizeof(long);
+ output += sizeof(long);
+ }
+ if (input <= end - sizeof(int))
+ {
+ isValid &= CheckBytesInAsciiRange(((int*)input)[0]);
+
+ output[0] = (char)input[0];
+ output[1] = (char)input[1];
+ output[2] = (char)input[2];
+ output[3] = (char)input[3];
+
+ input += sizeof(int);
+ output += sizeof(int);
+ }
+ }
+ else
+ {
+ // 32-bit: Loop ints by default
+ while (input <= end - sizeof(int))
+ {
+ isValid &= CheckBytesInAsciiRange(((int*)input)[0]);
+
+ output[0] = (char)input[0];
+ output[1] = (char)input[1];
+ output[2] = (char)input[2];
+ output[3] = (char)input[3];
+
+ input += sizeof(int);
+ output += sizeof(int);
+ }
+ }
+ if (input <= end - sizeof(short))
+ {
+ isValid &= CheckBytesInAsciiRange(((short*)input)[0]);
+
+ output[0] = (char)input[0];
+ output[1] = (char)input[1];
+
+ input += sizeof(short);
+ output += sizeof(short);
+ }
+ if (input < end)
+ {
+ isValid &= CheckBytesInAsciiRange(((sbyte*)input)[0]);
+ output[0] = (char)input[0];
+ }
+
+ return isValid;
}
- if (input <= end - sizeof(int))
- {
- isValid &= CheckBytesInAsciiRange(((int*)input)[0]);
- output[0] = (char)input[0];
- output[1] = (char)input[1];
- output[2] = (char)input[2];
- output[3] = (char)input[3];
-
- input += sizeof(int);
- output += sizeof(int);
- }
- }
- else
- {
- // 32-bit: Loop ints by default
- while (input <= end - sizeof(int))
+ // do/while as entry condition already checked
+ do
{
- isValid &= CheckBytesInAsciiRange(((int*)input)[0]);
-
- output[0] = (char)input[0];
- output[1] = (char)input[1];
- output[2] = (char)input[2];
- output[3] = (char)input[3];
-
- input += sizeof(int);
- output += sizeof(int);
- }
- }
- if (input <= end - sizeof(short))
- {
- isValid &= CheckBytesInAsciiRange(((short*)input)[0]);
-
- output[0] = (char)input[0];
- output[1] = (char)input[1];
-
- input += sizeof(short);
- output += sizeof(short);
- }
- if (input < end)
- {
- isValid &= CheckBytesInAsciiRange(((sbyte*)input)[0]);
- output[0] = (char)input[0];
- }
+ var vector = Unsafe.AsRef<Vector<sbyte>>(input);
+ isValid &= CheckBytesInAsciiRange(vector);
+ // Vectorized widen, byte vector to two short vectors
+ Vector.Widen(vector, out Unsafe.AsRef<Vector<short>>(output),
+ out Unsafe.AsRef<Vector<short>>(output + Vector<short>.Count));
+ input += Vector<sbyte>.Count;
+ output += Vector<sbyte>.Count;
+ } while (input <= end - Vector<sbyte>.Count);
+
+ // Vector path done, loop back to do non-Vector
+ // If is a exact multiple of vector size, bail now
+ } while (input > end - Vector<sbyte>.Count);
return isValid;
-
- Vectorized:
- // do/while as entry condition already checked
- do
- {
- var vector = Unsafe.AsRef<Vector<sbyte>>(input);
- isValid &= CheckBytesInAsciiRange(vector);
- // Vectorized widen, byte vector to two short vectors
- Vector.Widen(vector, out Unsafe.AsRef<Vector<short>>(output),
- out Unsafe.AsRef<Vector<short>>(output + Vector<short>.Count));
- input += Vector<sbyte>.Count;
- output += Vector<sbyte>.Count;
- } while (input < end - Vector<sbyte>.Count);
-
- goto NonVectorized;
}
-
private static bool CheckBytesInAsciiRange(Vector<sbyte> check)
{
// Vectorized byte range check, signed byte > 0 for 1-127