Background and motivation
The Arm Advanced SIMD UQRSHRN instruction performs an unsigned saturated narrow operation. As such, its result is always unsigned. However, the .NET intrinsics API for this instruction includes overloads that accept and return signed types.
These overloads will not work as expected if following the API description rather than the instruction description. It would likely be best to obsolete and hide them to avoid potential confusion.
API Proposal
namespace System.Runtime.Intrinsics.Arm;
public abstract class AdvSimd : ArmBase
{
public new abstract class Arm64 : ArmBase.Arm64
{
/// <summary>
/// uint16_t vqrshrns_n_u32 (uint32_t a, const int n)
/// A64: UQRSHRN Hd, Sn, #n
/// </summary>
+ [Obsolete("Use unsigned overload or signed instruction.")]
public static Vector64<short> ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64<int> value, [ConstantExpected(Min = 1, Max = (byte)(16))] byte count) { throw new PlatformNotSupportedException(); }
/// <summary>
/// uint32_t vqrshrnd_n_u64 (uint64_t a, const int n)
/// A64: UQRSHRN Sd, Dn, #n
/// </summary>
+ [Obsolete("Use unsigned overload or signed instruction.")]
public static Vector64<int> ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64<long> value, [ConstantExpected(Min = 1, Max = (byte)(8))] byte count) { throw new PlatformNotSupportedException(); }
/// <summary>
/// uint8_t vqrshrnh_n_u16 (uint16_t a, const int n)
/// A64: UQRSHRN Bd, Hn, #n
/// </summary>
+ [Obsolete("Use unsigned overload or signed instruction.")]
public static Vector64<sbyte> ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64<short> value, [ConstantExpected(Min = 1, Max = (byte)(32))] byte count) { throw new PlatformNotSupportedException(); }
}
/// <summary>
/// uint16x4_t vqrshrn_n_u32 (uint32x4_t a, const int n)
/// A32: VQRSHRN.U32 Dd, Qm, #n
/// A64: UQRSHRN Vd.4H, Vn.4S, #n
/// </summary>
+ [Obsolete("Use unsigned overload or signed instruction.")]
public static Vector64<short> ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128<int> value, [ConstantExpected(Min = 1, Max = (byte)(32))] byte count) { throw new PlatformNotSupportedException(); }
/// <summary>
/// uint32x2_t vqrshrn_n_u64 (uint64x2_t a, const int n)
/// A32: VQRSHRN.U64 Dd, Qm, #n
/// A64: UQRSHRN Vd.2S, Vn.2D, #n
/// </summary>
+ [Obsolete("Use unsigned overload or signed instruction.")]
public static Vector64<int> ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128<long> value, [ConstantExpected(Min = 1, Max = (byte)(16))] byte count) { throw new PlatformNotSupportedException(); }
/// <summary>
/// uint8x8_t vqrshrn_n_u16 (uint16x8_t a, const int n)
/// A32: VQRSHRN.U16 Dd, Qm, #n
/// A64: UQRSHRN Vd.8B, Vn.8H, #n
/// </summary>
+ [Obsolete("Use unsigned overload or signed instruction.")]
public static Vector64<sbyte> ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128<short> value, [ConstantExpected(Min = 1, Max = (byte)(64))] byte count) { throw new PlatformNotSupportedException(); }
/// <summary>
/// uint16x8_t vqrshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n)
/// A32: VQRSHRN.U32 Dd+1, Dn, #n
/// A64: UQRSHRN2 Vd.8H, Vn.4S, #n
/// </summary>
+ [Obsolete("Use unsigned overload or signed instruction.")]
public static Vector128<short> ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64<short> lower, Vector128<int> value, [ConstantExpected(Min = 1, Max = (byte)(32))] byte count) { throw new PlatformNotSupportedException(); }
/// <summary>
/// uint32x4_t vqrshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n)
/// A32: VQRSHRN.U64 Dd+1, Dn, #n
/// A64: UQRSHRN2 Vd.4S, Vn.2D, #n
/// </summary>
+ [Obsolete("Use unsigned overload or signed instruction.")]
public static Vector128<int> ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64<int> lower, Vector128<long> value, [ConstantExpected(Min = 1, Max = (byte)(16))] byte count) { throw new PlatformNotSupportedException(); }
/// <summary>
/// uint8x16_t vqrshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n)
/// A32: VQRSHRN.U16 Dd+1, Dn, #n
/// A64: UQRSHRN2 Vd.16B, Vn.8H, #n
/// </summary>
+ [Obsolete("Use unsigned overload or signed instruction.")]
public static Vector128<sbyte> ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64<sbyte> lower, Vector128<short> value, [ConstantExpected(Min = 1, Max = (byte)(64))] byte count) { throw new PlatformNotSupportedException(); }
}
API Usage
N/A
Alternative Designs
Could just leave them there and let people trip on them.
Risks
Source-breaking change.
Background and motivation
The Arm Advanced SIMD
UQRSHRNinstruction performs an unsigned saturated narrow operation. As such, its result is always unsigned. However, the .NET intrinsics API for this instruction includes overloads that accept and return signed types.These overloads will not work as expected if following the API description rather than the instruction description. It would likely be best to obsolete and hide them to avoid potential confusion.
API Proposal
namespace System.Runtime.Intrinsics.Arm; public abstract class AdvSimd : ArmBase { public new abstract class Arm64 : ArmBase.Arm64 { /// <summary> /// uint16_t vqrshrns_n_u32 (uint32_t a, const int n) /// A64: UQRSHRN Hd, Sn, #n /// </summary> + [Obsolete("Use unsigned overload or signed instruction.")] public static Vector64<short> ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64<int> value, [ConstantExpected(Min = 1, Max = (byte)(16))] byte count) { throw new PlatformNotSupportedException(); } /// <summary> /// uint32_t vqrshrnd_n_u64 (uint64_t a, const int n) /// A64: UQRSHRN Sd, Dn, #n /// </summary> + [Obsolete("Use unsigned overload or signed instruction.")] public static Vector64<int> ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64<long> value, [ConstantExpected(Min = 1, Max = (byte)(8))] byte count) { throw new PlatformNotSupportedException(); } /// <summary> /// uint8_t vqrshrnh_n_u16 (uint16_t a, const int n) /// A64: UQRSHRN Bd, Hn, #n /// </summary> + [Obsolete("Use unsigned overload or signed instruction.")] public static Vector64<sbyte> ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64<short> value, [ConstantExpected(Min = 1, Max = (byte)(32))] byte count) { throw new PlatformNotSupportedException(); } } /// <summary> /// uint16x4_t vqrshrn_n_u32 (uint32x4_t a, const int n) /// A32: VQRSHRN.U32 Dd, Qm, #n /// A64: UQRSHRN Vd.4H, Vn.4S, #n /// </summary> + [Obsolete("Use unsigned overload or signed instruction.")] public static Vector64<short> ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128<int> value, [ConstantExpected(Min = 1, Max = (byte)(32))] byte count) { throw new PlatformNotSupportedException(); } /// <summary> /// uint32x2_t vqrshrn_n_u64 (uint64x2_t a, const int n) /// A32: VQRSHRN.U64 Dd, Qm, #n /// A64: UQRSHRN Vd.2S, Vn.2D, #n /// </summary> + [Obsolete("Use unsigned overload or signed instruction.")] public static Vector64<int> ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128<long> value, [ConstantExpected(Min = 1, Max = (byte)(16))] byte count) { throw new PlatformNotSupportedException(); } /// <summary> /// uint8x8_t vqrshrn_n_u16 (uint16x8_t a, const int n) /// A32: VQRSHRN.U16 Dd, Qm, #n /// A64: UQRSHRN Vd.8B, Vn.8H, #n /// </summary> + [Obsolete("Use unsigned overload or signed instruction.")] public static Vector64<sbyte> ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128<short> value, [ConstantExpected(Min = 1, Max = (byte)(64))] byte count) { throw new PlatformNotSupportedException(); } /// <summary> /// uint16x8_t vqrshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) /// A32: VQRSHRN.U32 Dd+1, Dn, #n /// A64: UQRSHRN2 Vd.8H, Vn.4S, #n /// </summary> + [Obsolete("Use unsigned overload or signed instruction.")] public static Vector128<short> ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64<short> lower, Vector128<int> value, [ConstantExpected(Min = 1, Max = (byte)(32))] byte count) { throw new PlatformNotSupportedException(); } /// <summary> /// uint32x4_t vqrshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) /// A32: VQRSHRN.U64 Dd+1, Dn, #n /// A64: UQRSHRN2 Vd.4S, Vn.2D, #n /// </summary> + [Obsolete("Use unsigned overload or signed instruction.")] public static Vector128<int> ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64<int> lower, Vector128<long> value, [ConstantExpected(Min = 1, Max = (byte)(16))] byte count) { throw new PlatformNotSupportedException(); } /// <summary> /// uint8x16_t vqrshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) /// A32: VQRSHRN.U16 Dd+1, Dn, #n /// A64: UQRSHRN2 Vd.16B, Vn.8H, #n /// </summary> + [Obsolete("Use unsigned overload or signed instruction.")] public static Vector128<sbyte> ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64<sbyte> lower, Vector128<short> value, [ConstantExpected(Min = 1, Max = (byte)(64))] byte count) { throw new PlatformNotSupportedException(); } }API Usage
N/A
Alternative Designs
Could just leave them there and let people trip on them.
Risks
Source-breaking change.