Vector{<T>|64|128|256|512}.Narrow with saturation #75724
Open
Description
opened on Sep 15, 2022
Summary
For SSE2 there's Sse2.PackSignedSaturate
which packs the two vectors with saturation.
Such functionality is missing for the xplat-vectors -- i.e. Vector128.Narrow
packs the two vectors, but cuts / masks off the values outside of the target range, e.g. for short
-> sbyte
bits above 0xFF is cut off resulting in (for me) unexpected values.
Maybe it's a bit astonishing that Narrow
doesn't pack with saturation. This just bit me, and as it seems #73064 (comment) was similar.
There should be something like NarrowWithSaturation
in order to don't need to fallback to Sse2 / AdvSimd.
API Proposal
namespace System.Runtime.Intrinsics;
public static class Vector64
{
// Existing methods left out for brevity
[CLSCompliant(false)]
public static Vector64<sbyte> NarrowWithSaturation(Vector64<short> lower, Vector64<short> upper);
public static Vector64<short> NarrowWithSaturation(Vector64<int> lower, Vector64<int> upper);
public static Vector64<int> NarrowWithSaturation(Vector64<long> lower, Vector64<long> upper);
[CLSCompliant(false)]
public static Vector64<byte> NarrowWithSaturation(Vector64<ushort> lower, Vector64<ushort> upper);
[CLSCompliant(false)]
public static Vector64<ushort> NarrowWithSaturation(Vector64<uint> lower, Vector64<uint> upper);
public static Vector64<uint> NarrowWithSaturation(Vector64<ulong> lower, Vector64<ulong> upper);
public static Vector64<float> NarrowWithSaturation(Vector64<double> lower, Vector64<double> upper);
}
public static class Vector128
{
// Existing methods left out for brevity
[CLSCompliant(false)]
public static Vector128<sbyte> NarrowWithSaturation(Vector128<short> lower, Vector128<short> upper);
public static Vector128<short> NarrowWithSaturation(Vector128<int> lower, Vector128<int> upper);
public static Vector128<int> NarrowWithSaturation(Vector128<long> lower, Vector128<long> upper);
[CLSCompliant(false)]
public static Vector128<byte> NarrowWithSaturation(Vector128<ushort> lower, Vector128<ushort> upper);
[CLSCompliant(false)]
public static Vector128<ushort> NarrowWithSaturation(Vector128<uint> lower, Vector128<uint> upper);
public static Vector128<uint> NarrowWithSaturation(Vector128<ulong> lower, Vector128<ulong> upper);
public static Vector128<float> NarrowWithSaturation(Vector128<double> lower, Vector128<double> upper);
}
public static class Vector256
{
// Existing methods left out for brevity
[CLSCompliant(false)]
public static Vector256<sbyte> NarrowWithSaturation(Vector256<short> lower, Vector256<short> upper);
public static Vector256<short> NarrowWithSaturation(Vector256<int> lower, Vector256<int> upper);
public static Vector256<int> NarrowWithSaturation(Vector256<long> lower, Vector256<long> upper);
[CLSCompliant(false)]
public static Vector256<byte> NarrowWithSaturation(Vector256<ushort> lower, Vector256<ushort> upper);
[CLSCompliant(false)]
public static Vector256<ushort> NarrowWithSaturation(Vector256<uint> lower, Vector256<uint> upper);
public static Vector256<uint> NarrowWithSaturation(Vector256<ulong> lower, Vector256<ulong> upper);
public static Vector256<float> NarrowWithSaturation(Vector256<double> lower, Vector256<double> upper);
}
public static class Vector512
{
// Existing methods left out for brevity
[CLSCompliant(false)]
public static Vector512<sbyte> NarrowWithSaturation(Vector512<short> lower, Vector512<short> upper);
public static Vector512<short> NarrowWithSaturation(Vector512<int> lower, Vector512<int> upper);
public static Vector512<int> NarrowWithSaturation(Vector512<long> lower, Vector512<long> upper);
[CLSCompliant(false)]
public static Vector512<byte> NarrowWithSaturation(Vector512<ushort> lower, Vector512<ushort> upper);
[CLSCompliant(false)]
public static Vector512<ushort> NarrowWithSaturation(Vector512<uint> lower, Vector512<uint> upper);
public static Vector512<uint> NarrowWithSaturation(Vector512<ulong> lower, Vector512<ulong> upper);
public static Vector512<float> NarrowWithSaturation(Vector512<double> lower, Vector512<double> upper);
}
Activity