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.

@sivarv @CarolEidt