[API Proposal]: Mark Vector-related APIs as caller-unsafe
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
### Background and motivation
https://github.com/dotnet/runtime/issues/125145 Annotate All Vector-related APIs as caller-unsafe because all of these either:
- Perform memory accesses without bound checks
- May return uninitialized memory in their components.
I'm using a diff format where `+` indicates that it's now caller-unsafe and `-` indicates the unsafe modifier has been removed (a non-breaking change).
### API Proposal
### namespace `System.Runtime.Intrinsics`
```diff
namespace System.Runtime.Intrinsics
public static partial class Vector64
{
+ /// Initializes only the lowest element and leaves the remaining elements uninitialized; reading them observes undefined data.
+ unsafe
public static Vector64 CreateScalarUnsafe(byte value)
+ unsafe
public static Vector64 CreateScalarUnsafe(double value)
+ unsafe
public static Vector64 CreateScalarUnsafe(short value)
+ unsafe
public static Vector64 CreateScalarUnsafe(int value)
+ unsafe
public static Vector64 CreateScalarUnsafe(long value)
+ unsafe
public static Vector64 CreateScalarUnsafe(nint value)
+ unsafe
public static Vector64 CreateScalarUnsafe(nuint value)
+ unsafe
public static Vector64 CreateScalarUnsafe(sbyte value)
+ unsafe
public static Vector64 CreateScalarUnsafe(float value)
+ unsafe
public static Vector64 CreateScalarUnsafe(ushort value)
+ unsafe
public static Vector64 CreateScalarUnsafe(uint value)
+ unsafe
public static Vector64 CreateScalarUnsafe(ulong value)
+ unsafe
public static Vector64 CreateScalarUnsafe(T value)
+ /// Loads a full vector starting at the given reference with no bounds check; may read past the end of the source.
+ unsafe
public static Vector64 LoadUnsafe(ref readonly T source)
+ unsafe
public static Vector64 LoadUnsafe(ref readonly T source, nuint elementOffset)
+ /// Stores a full vector starting at the given reference with no bounds check; may write past the end of the destination.
+ unsafe
public static void StoreUnsafe(this Vector64 source, ref T destination)
+ unsafe
public static void StoreUnsafe(this Vector64 source, ref T destination, nuint elementOffset)
+ /// Widens to a larger vector, leaving the upper elements uninitialized.
+ unsafe
public static Vector128 ToVector128Unsafe(this Vector64 vector)
}
public static partial class Vector128
{
+ /// Reinterprets the value as a 128-bit vector, leaving the upper elements uninitialized.
+ unsafe
public static Vector128 AsVector128Unsafe(this System.Numerics.Vector2 value)
+ unsafe
public static Vector128 AsVector128Unsafe(this System.Numerics.Vector3 value)
+ /// Initializes only the lowest element and leaves the remaining elements uninitialized; reading them observes undefined data.
+ unsafe
public static Vector128 CreateScalarUnsafe(byte value)
+ unsafe
public static Vector128 CreateScalarUnsafe(double value)
+ unsafe
public static Vector128 CreateScalarUnsafe(short value)
+ unsafe
public static Vector128 CreateScalarUnsafe(int value)
+ unsafe
public static Vector128 CreateScalarUnsafe(long value)
+ unsafe
public static Vector128 CreateScalarUnsafe(nint value)
+ unsafe
public static Vector128 CreateScalarUnsafe(nuint value)
+ unsafe
public static Vector128 CreateScalarUnsafe(sbyte value)
+ unsafe
public static Vector128 CreateScalarUnsafe(float value)
+ unsafe
public static Vector128 CreateScalarUnsafe(ushort value)
+ unsafe
public static Vector128 CreateScalarUnsafe(uint value)
+ unsafe
public static Vector128 CreateScalarUnsafe(ulong value)
+ unsafe
public static Vector128 CreateScalarUnsafe(T value)
+ /// Loads a full vector starting at the given reference with no bounds check; may read past the end of the source.
+ unsafe
public static Vector128 LoadUnsafe(ref readonly T source)
+ unsafe
public static Vector128 LoadUnsafe(ref readonly T source, nuint elementOffset)
+ /// Stores a full vector starting at the given reference with no bounds check; may write past the end of the destination.
+ unsafe
public static void StoreUnsafe(this Vector128 source, ref T destination)
+ unsafe
public static void StoreUnsafe(this Vector128 source, ref T destination, nuint elementOffset)
+ /// Widens to a larger vector, leaving the upper elements uninitialized.
+ unsafe
public static Vector256 ToVector256Unsafe(this Vector128 vector)
}
public static partial class Vector256
{
+ /// Initializes only the lowest element and leaves the remaining elements uninitialized; reading them observes undefined data.
+ unsafe
public static Vector256 CreateScalarUnsafe(byte value)
+ unsafe
public static Vector256 CreateScalarUnsafe(double value)
+ unsafe
public static Vector256 CreateScalarUnsafe(short value)
+ unsafe
public static Vector256 CreateScalarUnsafe(int value)
+ unsafe
public static Vector256 CreateScalarUnsafe(long value)
+ unsafe
public static Vector256 CreateScalarUnsafe(nint value)
+ unsafe
public static Vector256 CreateScalarUnsafe(nuint value)
+ unsafe
public static Vector256 CreateScalarUnsafe(sbyte value)
+ unsafe
public static Vector256 CreateScalarUnsafe(float value)
+ unsafe
public static Vector256 CreateScalarUnsafe(ushort value)
+ unsafe
public static Vector256 CreateScalarUnsafe(uint value)
+ unsafe
public static Vector256 CreateScalarUnsafe(ulong value)
+ unsafe
public static Vector256 CreateScalarUnsafe(T value)
+ /// Loads a full vector starting at the given reference with no bounds check; may read past the end of the source.
+ unsafe
public static Vector256 LoadUnsafe(ref readonly T source)
+ unsafe
public static Vector256 LoadUnsafe(ref readonly T source, nuint elementOffset)
+ /// Stores a full vector starting at the given reference with no bounds check; may write past the end of the destination.
+ unsafe
public static void StoreUnsafe(this Vector256 source, ref T destination)
+ unsafe
public static void StoreUnsafe(this Vector256 source, ref T destination, nuint elementOffset)
+ /// Widens to a larger vector, leaving the upper elements uninitialized.
+ unsafe
public static Vector512 ToVector512Unsafe(this Vector256 vector)
}
public static partial class Vector512
{
+ /// Initializes only the lowest element and leaves the remaining elements uninitialized; reading them observes undefined data.
+ unsafe
public static Vector512 CreateScalarUnsafe(byte value)
+ unsafe
public static Vector512 CreateScalarUnsafe(double value)
+ unsafe
public static Vector512 CreateScalarUnsafe(short value)
+ unsafe
public static Vector512 CreateScalarUnsafe(int value)
+ unsafe
public static Vector512 CreateScalarUnsafe(long value)
+ unsafe
public static Vector512 CreateScalarUnsafe(nint value)
+ unsafe
public static Vector512 CreateScalarUnsafe(nuint value)
+ unsafe
public static Vector512 CreateScalarUnsafe(sbyte value)
+ unsafe
public static Vector512 CreateScalarUnsafe(float value)
+ unsafe
public static Vector512 CreateScalarUnsafe(ushort value)
+ unsafe
public static Vector512 CreateScalarUnsafe(uint value)
+ unsafe
public static Vector512 CreateScalarUnsafe(ulong value)
+ unsafe
public static Vector512 CreateScalarUnsafe(T value)
+ /// Loads a full vector starting at the given reference with no bounds check; may read past the end of the source.
+ unsafe
public static Vector512 LoadUnsafe(ref readonly T source)
+ unsafe
public static Vector512 LoadUnsafe(ref readonly T source, nuint elementOffset)
+ /// Stores a full vector starting at the given reference with no bounds check; may write past the end of the destination.
+ unsafe
public static void StoreUnsafe(this Vector512 source, ref T destination)
+ unsafe
public static void StoreUnsafe(this Vector512 source, ref T destination, nuint elementOffset)
}
```
### namespace `System.Numerics`
```diff
namespace System.Numerics
public static partial class Vector
{
+ /// Widens to a larger vector, leaving the upper elements uninitialized.
+ unsafe
public static Vector3 AsVector3Unsafe(this Vector2 value)
+ unsafe
public static Vector4 AsVector4Unsafe(this Vector2 value)
+ unsafe
public static Vector4 AsVector4Unsafe(this Vector3 value)
+ /// Initializes only the lowest element and leaves the remaining elements uninitialized; reading them observes undefined data.
+ unsafe
public static Vector CreateScalarUnsafe(T value)
+ /// Loads a full vector starting at the given reference with no bounds check; may read past the end of the source.
+ unsafe
public static Vector LoadUnsafe(ref readonly T source)
+ unsafe
public static Vector LoadUnsafe(ref readonly T source, nuint elementOffset)
+ /// Stores a full vector starting at the given reference with no bounds check; may write past the end of the destination.
+ unsafe
public static void StoreUnsafe(this Vector source, ref T destination)
+ unsafe
public static void StoreUnsafe(this Vector2 source, ref float destination)
+ unsafe
public static void StoreUnsafe(this Vector3 source, ref float destination)
+ unsafe
public static void StoreUnsafe(this Vector4 source, ref float destination)
+ unsafe
public static void StoreUnsafe(this Vector source, ref T destination, nuint elementOffset)
+ unsafe
public static void StoreUnsafe(this Vector2 source, ref float destination, nuint elementOffset)
+ unsafe
public static void StoreUnsafe(this Vector3 source, ref float destination, nuint elementOffset)
+ unsafe
public static void StoreUnsafe(this Vector4 source, ref float destination, nuint elementOffset)
}
public partial struct Vector2
{
+ /// Initializes only the lowest element and leaves the remaining elements uninitialized; reading them observes undefined data.
+ unsafe
public static Vector2 CreateScalarUnsafe(float x)
+ /// Loads a full vector starting at the given reference with no bounds check; may read past the end of the source.
+ unsafe
public static Vector2 LoadUnsafe(ref readonly float source)
+ unsafe
public static Vector2 LoadUnsafe(ref readonly float source, nuint elementOffset)
}
public partial struct Vector3
{
+ /// Initializes only the lowest element and leaves the remaining elements uninitialized; reading them observes undefined data.
+ unsafe
public static Vector3 CreateScalarUnsafe(float x)
+ /// Loads a full vector starting at the given reference with no bounds check; may read past the end of the source.
+ unsafe
public static Vector3 LoadUnsafe(ref readonly float source)
+ unsafe
public static Vector3 LoadUnsafe(ref readonly float source, nuint elementOffset)
}
public partial struct Vector4
{
+ /// Initializes only the lowest element and leaves the remaining elements uninitialized; reading them observes undefined data.
+ unsafe
public static Vector4 CreateScalarUnsafe(float x)
+ /// Loads a full vector starting at the given reference with no bounds check; may read past the end of the source.
+ unsafe
public static Vector4 LoadUnsafe(ref readonly float source)
+ unsafe
public static Vector4 LoadUnsafe(ref readonly float source, nuint elementOffset)
}
```
### API Usage
All these apis now require an unsafe context to call them.
### Alternative Designs
_No response_
### Risks
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.