From: Levi Broderick Date: Tue, 30 Apr 2019 04:37:58 +0000 (-0700) Subject: Add more span-based Vector ctors and CopyTo methods (#23333) X-Git-Tag: accepted/tizen/unified/20190813.215958~42^2~370 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=003bf857ea8a89e9eedd913f8b095f8fa01fd0b4;p=platform%2Fupstream%2Fcoreclr.git Add more span-based Vector ctors and CopyTo methods (#23333) --- diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs b/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs index 3f7832a..7d8937d 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs +++ b/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs @@ -59,10 +59,10 @@ namespace System.Numerics [Intrinsic] get { - return s_count; + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + return Unsafe.SizeOf>() / Unsafe.SizeOf(); } } - private static readonly int s_count = InitializeCount(); /// /// Returns a vector containing all zeroes. @@ -101,71 +101,6 @@ namespace System.Numerics private static readonly Vector s_allOnes = new Vector(GetAllBitsSetValue()); #endregion Static Members - #region Static Initialization - private struct VectorSizeHelper - { - internal Vector _placeholder; - internal byte _byte; - } - - // Calculates the size of this struct in bytes, by computing the offset of a field in a structure - private static unsafe int InitializeCount() - { - VectorSizeHelper vsh; - byte* vectorBase = &vsh._placeholder.register.byte_0; - byte* byteBase = &vsh._byte; - int vectorSizeInBytes = (int)(byteBase - vectorBase); - - int typeSizeInBytes = -1; - if (typeof(T) == typeof(byte)) - { - typeSizeInBytes = sizeof(byte); - } - else if (typeof(T) == typeof(sbyte)) - { - typeSizeInBytes = sizeof(sbyte); - } - else if (typeof(T) == typeof(ushort)) - { - typeSizeInBytes = sizeof(ushort); - } - else if (typeof(T) == typeof(short)) - { - typeSizeInBytes = sizeof(short); - } - else if (typeof(T) == typeof(uint)) - { - typeSizeInBytes = sizeof(uint); - } - else if (typeof(T) == typeof(int)) - { - typeSizeInBytes = sizeof(int); - } - else if (typeof(T) == typeof(ulong)) - { - typeSizeInBytes = sizeof(ulong); - } - else if (typeof(T) == typeof(long)) - { - typeSizeInBytes = sizeof(long); - } - else if (typeof(T) == typeof(float)) - { - typeSizeInBytes = sizeof(float); - } - else if (typeof(T) == typeof(double)) - { - typeSizeInBytes = sizeof(double); - } - else - { - throw new NotSupportedException(SR.Arg_TypeNotSupported); - } - - return vectorSizeInBytes / typeSizeInBytes; - } - #endregion Static Initialization - #region Constructors /// /// Constructs a vector whose components are all value @@ -779,38 +714,82 @@ namespace System.Numerics #if netcoreapp /// - /// Constructs a vector from the given span. The span must contain at least Vector'T.Count elements. + /// Constructs a vector from the given . The span must contain at least elements. /// - public Vector(Span values) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector(ReadOnlySpan values) : this() { - if ((typeof(T) == typeof(byte)) - || (typeof(T) == typeof(sbyte)) - || (typeof(T) == typeof(ushort)) - || (typeof(T) == typeof(short)) - || (typeof(T) == typeof(uint)) - || (typeof(T) == typeof(int)) - || (typeof(T) == typeof(ulong)) - || (typeof(T) == typeof(long)) - || (typeof(T) == typeof(float)) - || (typeof(T) == typeof(double))) + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + if (values.Length < Vector.Count) { - if (values.Length < Count) - { - throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, Vector.Count, nameof(values))); - } - this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); } - else + this = Unsafe.ReadUnaligned>(ref MemoryMarshal.GetReference(values)); + } + + /// + /// Constructs a vector from the given . The span must contain at least elements. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector(ReadOnlySpan values) + : this() + { + if (values.Length < Count) { - throw new NotSupportedException(SR.Arg_TypeNotSupported); + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); } + this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + } + + /// + /// Constructs a vector from the given . The span must contain at least elements. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector(Span values) + : this() + { + if (values.Length < Count) + { + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); + } + this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); } #endif #endregion Constructors #region Public Instance Methods /// + /// Copies the vector to the given . The destination span must be at least size . + /// + /// The destination span which the values are copied into + /// If number of elements in source vector is greater than those available in destination span + public void CopyTo(Span destination) + { + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + if ((uint)destination.Length < (uint)Vector.Count) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + Unsafe.WriteUnaligned>(ref MemoryMarshal.GetReference(destination), this); + } + + /// + /// Copies the vector to the given . The destination span must be at least size . + /// + /// The destination span which the values are copied into + /// If number of elements in source vector is greater than those available in destination span + public void CopyTo(Span destination) + { + if ((uint)destination.Length < (uint)Count) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + + Unsafe.WriteUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), this); + } + + /// /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count. /// /// The destination array which the values are copied into @@ -1591,6 +1570,41 @@ namespace System.Numerics sb.Append('>'); return sb.ToString(); } + + /// + /// Attempts to copy the vector to the given . The destination span must be at least size . + /// + /// The destination span which the values are copied into + /// True if the source vector was successfully copied to . False if + /// is not large enough to hold the source vector. + public bool TryCopyTo(Span destination) + { + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + if ((uint)destination.Length < (uint)Vector.Count) + { + return false; + } + + Unsafe.WriteUnaligned>(ref MemoryMarshal.GetReference(destination), this); + return true; + } + + /// + /// Attempts to copy the vector to the given . The destination span must be at least size . + /// + /// The destination span which the values are copied into + /// True if the source vector was successfully copied to . False if + /// is not large enough to hold the source vector. + public bool TryCopyTo(Span destination) + { + if ((uint)destination.Length < (uint)Count) + { + return false; + } + + Unsafe.WriteUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), this); + return true; + } #endregion Public Instance Methods #region Arithmetic Operators @@ -5335,5 +5349,12 @@ namespace System.Numerics } #endregion Same-Size Conversion + + #region Throw Helpers + internal static void ThrowInsufficientNumberOfElementsException(int requiredElementCount) + { + throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, requiredElementCount, "values")); + } + #endregion } } diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt b/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt index 5132b09..4eced47 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt +++ b/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt @@ -64,10 +64,10 @@ namespace System.Numerics [Intrinsic] get { - return s_count; + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + return Unsafe.SizeOf>() / Unsafe.SizeOf(); } } - private static readonly int s_count = InitializeCount(); /// /// Returns a vector containing all zeroes. @@ -106,42 +106,6 @@ namespace System.Numerics private static readonly Vector s_allOnes = new Vector(GetAllBitsSetValue()); #endregion Static Members - #region Static Initialization - private struct VectorSizeHelper - { - internal Vector _placeholder; - internal byte _byte; - } - - // Calculates the size of this struct in bytes, by computing the offset of a field in a structure - private static unsafe int InitializeCount() - { - VectorSizeHelper vsh; - byte* vectorBase = &vsh._placeholder.register.byte_0; - byte* byteBase = &vsh._byte; - int vectorSizeInBytes = (int)(byteBase - vectorBase); - - int typeSizeInBytes = -1; -<# - foreach (Type type in supportedTypes) - { -#> - <#=GenerateIfStatementHeader(type)#> - { - typeSizeInBytes = sizeof(<#=typeAliases[type]#>); - } -<# - } -#> - else - { - throw new NotSupportedException(SR.Arg_TypeNotSupported); - } - - return vectorSizeInBytes / typeSizeInBytes; - } - #endregion Static Initialization - #region Constructors /// /// Constructs a vector whose components are all value @@ -305,29 +269,82 @@ namespace System.Numerics #if netcoreapp /// - /// Constructs a vector from the given span. The span must contain at least Vector'T.Count elements. + /// Constructs a vector from the given . The span must contain at least elements. /// - public Vector(Span values) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector(ReadOnlySpan values) : this() { - <#=GenerateIfConditionAllTypes(supportedTypes)#> + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + if (values.Length < Vector.Count) { - if (values.Length < Count) - { - throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, Vector.Count, nameof(values))); - } - this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); } - else + this = Unsafe.ReadUnaligned>(ref MemoryMarshal.GetReference(values)); + } + + /// + /// Constructs a vector from the given . The span must contain at least elements. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector(ReadOnlySpan values) + : this() + { + if (values.Length < Count) { - throw new NotSupportedException(SR.Arg_TypeNotSupported); + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); + } + this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + } + + /// + /// Constructs a vector from the given . The span must contain at least elements. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector(Span values) + : this() + { + if (values.Length < Count) + { + Vector.ThrowInsufficientNumberOfElementsException(Vector.Count); } + this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); } #endif #endregion Constructors #region Public Instance Methods /// + /// Copies the vector to the given . The destination span must be at least size . + /// + /// The destination span which the values are copied into + /// If number of elements in source vector is greater than those available in destination span + public void CopyTo(Span destination) + { + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + if ((uint)destination.Length < (uint)Vector.Count) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + Unsafe.WriteUnaligned>(ref MemoryMarshal.GetReference(destination), this); + } + + /// + /// Copies the vector to the given . The destination span must be at least size . + /// + /// The destination span which the values are copied into + /// If number of elements in source vector is greater than those available in destination span + public void CopyTo(Span destination) + { + if ((uint)destination.Length < (uint)Count) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + + Unsafe.WriteUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), this); + } + + /// /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count. /// /// The destination array which the values are copied into @@ -620,6 +637,41 @@ namespace System.Numerics sb.Append('>'); return sb.ToString(); } + + /// + /// Attempts to copy the vector to the given . The destination span must be at least size . + /// + /// The destination span which the values are copied into + /// True if the source vector was successfully copied to . False if + /// is not large enough to hold the source vector. + public bool TryCopyTo(Span destination) + { + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + if ((uint)destination.Length < (uint)Vector.Count) + { + return false; + } + + Unsafe.WriteUnaligned>(ref MemoryMarshal.GetReference(destination), this); + return true; + } + + /// + /// Attempts to copy the vector to the given . The destination span must be at least size . + /// + /// The destination span which the values are copied into + /// True if the source vector was successfully copied to . False if + /// is not large enough to hold the source vector. + public bool TryCopyTo(Span destination) + { + if ((uint)destination.Length < (uint)Count) + { + return false; + } + + Unsafe.WriteUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), this); + return true; + } #endregion Public Instance Methods #region Arithmetic Operators @@ -1836,5 +1888,12 @@ namespace System.Numerics } #> #endregion Same-Size Conversion + + #region Throw Helpers + internal static void ThrowInsufficientNumberOfElementsException(int requiredElementCount) + { + throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, requiredElementCount, "values")); + } + #endregion } } diff --git a/src/System.Private.CoreLib/shared/System/ThrowHelper.cs b/src/System.Private.CoreLib/shared/System/ThrowHelper.cs index e73e1fa..8b46097 100644 --- a/src/System.Private.CoreLib/shared/System/ThrowHelper.cs +++ b/src/System.Private.CoreLib/shared/System/ThrowHelper.cs @@ -404,6 +404,9 @@ namespace System ThrowHelper.ThrowArgumentNullException(argName); } + // Throws if 'T' is disallowed in Vector / Vector128 / other related types in the + // Numerics or Intrinsics namespaces. If 'T' is allowed, no-ops. JIT will elide the method + // entirely if 'T' is supported and we're on an optimized release build. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void ThrowForUnsupportedVectorBaseType() where T : struct {