P3441R1
Rename simd_split to simd_chunk

Published Proposal,

This version:
http://wg21.link/P3441R1
Authors:
(Intel)
(Intel)
Audience:
LEWG
Project:
ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21

Abstract

The behaviour of simd_split is inconsistent with ranges::views::split, but is consistent with the behaviour of ranges::views::chunk. We propose to rename simd_split to simd_chunk to reflect this similarity in behaviour. We also propose that an overload of simd_chunk which takes an integer parameter is provided as a convenience for a common use case.

1. Motivation

The simd_split<T> function takes a basic_simd object and breaks it down into a tuple of as many objects of type T that it can, and maybe one remainder object. An example illustrates this:

simd<float, 19> x;
using IntoType = simd<float, 8>;

auto t = simd_split<IntoType>(x);
// get<0>(t) will be of type simd<float, 8>
// get<1>(t) will be of type simd<float, 8>
// get<2>(t) will be of type simd<float, 3> - the remainder

If the original type is perfectly divisible into type T then an array<T> is returned instead of a tuple of different sized basic_simd objects.

The behaviour simd_split is virtually identical to that of ranges::views::chunk and ranges::chunk_view. They take a view and a number n and produce a range of views (the chunks) of the original view, such that each chunk, except maybe the last one, has the size n.

In contrast, the more closely named ranges::views::split has a different behaviour to simd_split. The ranges version of split takes an input range and a delimiter value, and generates a range of views split on the delimiter. For example, the string "This,is,a,list", when split by the comma value would generate a range containing 4 views: "This", "is", "a", "list".

We propose that the simd_split function is renamed to simd_chunk to make its behaviour consistant with the existing range/view counterparts.

Note that a common use case for simd_split/simd_chunk is to break a larger basic_simd object into smaller native-sized pieces to call target-specific intrinsics. In this case the size of the chunk is known, but the user has to supply a complete type as the first template parameter to simd_chunk:

simd<float, 19> x;

// Break into AVX2-sized pieces:
auto t = simd_chunk<simd<float, 8>>(x);

In addition to this style we also propose that an overload is provided that takes the size of the chunk, rather than a complete simd type, which makes the most common use case more readable:

simd<float, 19> x;

// Break into AVX2-sized pieces:
auto t = simd_chunk<8>(x);

2. Wording

2.1. Rename split to chunk in overview

// [simd.creation], basic_simd and basic_simd_mask creation
template<class V, class Abi>
constexpr auto
simd_split simd_chunk(const basic_simd<typename V::value_type, Abi>& x) noexcept;
template<class M, class Abi>
constexpr auto
simd_split simd_chunk(const basic_simd_mask<mask-element-size<M>, Abi>& x) noexcept;

2.2. Add simd_chunk integer overload to overview

// [simd.creation], basic_simd and basic_simd_mask creation

template<size_t N, class T, class Abi>
constexpr auto simd_chunk(const basic_simd<T, Abi>& x) noexcept;

template<size_t N, size_t Bytes, class Abi>
constexpr auto simd_chunk(const basic_simd_mask<Bytes, Abi>& x) noexcept;

2.3. Add description of basic_simd and basic_simd_mask creation [simd.creation]

basic_simd and basic_simd_mask creation [simd.creation]

template<class T, class Abi>
constexpr auto simd_split simd_chunk(const basic_simd<typename T::value_type, Abi>& x)
noexcept;
template<class T, class Abi>
constexpr auto simd_split simd_chunk(const basic_simd_mask<mask-element-size<T>, Abi>& x)
noexcept;
template<size_t N, class T, class Abi>
constexpr auto simd_chunk(const basic_simd<T, Abi>& x) noexcept;

Effects:

Equivalent to return simd_chunk<resize_simd_t<N, basic_simd<T, Abi>>>(x)

template<size_t N, size_t Bytes, class Abi>
constexpr auto simd_chunk(const basic_simd_mask<Bytes, Abi>& x) noexcept;

Equivalent to return simd_chunk<resize_simd_t<N, basic_simd_mask<Bytes, Abi>>>(x)