API Proposal: Widen, Narrow, and Convert for Vector · Issue #20147 · dotnet/runtime (original) (raw)
This is a concrete proposal of the ideas discussed in issue #14521. Converting data from one form to another is a necessary part of vector algorithms in many areas such as image processing, signal processing, text manipulation, and more. Current SIMD instruction sets expose a lot of functionality for quickly and efficiently converting large chunks of data, but the current interface of Vector<T>
does not have any support for it. Allowing access to these intrinsics could greatly speed up common algorithms involving data conversion.
Proposed additions
All of the additions are on the static Vector
class, and operate on parameters of type Vector<T>
. The additions are systematic and straightforward. Widen
and Narrow
are provided for type pairs that are half- or double-sized, and Convert
is provided for same-sized integral-floating point type pairs.
public static partial class Vector { public static void Widen(Vector source, out Vector dest1, out Vector dest2); public static void Widen(Vector source, out Vector dest1, out Vector dest2); public static void Widen(Vector source, out Vector dest1, out Vector dest2); public static void Widen(Vector source, out Vector dest1, out Vector dest2); public static void Widen(Vector source, out Vector dest1, out Vector dest2); public static void Widen(Vector source, out Vector dest1, out Vector dest2); public static void Widen(Vector source, out Vector dest1, out Vector dest2);
public static Vector<byte> Narrow(Vector<ushort> source1, Vector<ushort> source2);
public static Vector<ushort> Narrow(Vector<uint> source1, Vector<uint> source2);
public static Vector<uint> Narrow(Vector<ulong> source1, Vector<ulong> source2);
public static Vector<sbyte> Narrow(Vector<short> source1, Vector<short> source2);
public static Vector<short> Narrow(Vector<int> source1, Vector<int> source2);
public static Vector<int> Narrow(Vector<long> source1, Vector<long> source2);
public static Vector<float> Narrow(Vector<double> source1, Vector<double> source2);
public static Vector<float> ConvertToSingle(Vector<int> value);
public static Vector<float> ConvertToSingle(Vector<uint> value);
public static Vector<double> ConvertToDouble(Vector<long> value);
public static Vector<double> ConvertToDouble(Vector<ulong> value);
public static Vector<int> ConvertToInt32(Vector<float> value);
public static Vector<uint> ConvertToUInt32(Vector<float> value);
public static Vector<long> ConvertToInt64(Vector<double> value);
public static Vector<ulong> ConvertToUInt64(Vector<double> value);
}
Semantics
The semantics are simple and uniform. I will use a representative set of methods to explain.
Widen(Vector source, out Vector dest1, out Vector dest2)
An input Vector<byte>
called source
is given. When the method completes, dest1
contains the lower half of elements in source
, and dest2
contains the upper half of elements in source
. The elements are converted as if they were individually cast from byte
to ushort
.
Vector Narrow(Vector source1, Vector source2)
Two input Vector<ushort>
's are given. The method returns a single Vector<byte>
. The return value's lower elements are the elements from source1
, and the upper elements are from source2
. The elements are converted as if they were individually cast from ushort
to byte
.
Vector ConvertToSingle(Vector value)
A single Vector<int>
is given. The method returns a single Vector<float>
containing the input's elements. The elements are converted as if they were individually cast from int
to float
.
Rationale
Currently, there is no way to efficiently convert elements residing in Vector<T>
to a different data type. Directly converting the vector's source data (in a serial manner) is the most efficient way, but that requires your algorithm to break out of "vector mode" just to do simple conversion operations. It is also many times slower than we could achieve with proper vector conversion support. Many common algorithms require conversions from one data type to another, so this is currently a large hole in the API.