Типы с параллелизмом по данным (SIMD) (начиная с C++26)
Библиотека предоставляет типы с параллелизмом по данным и операции над этими типами: переносимые типы для явного задания параллелизма по данным и структурирования данных с помощью ресурсов выполнения с параллелизмом по данным, если они доступны, например регистров и инструкций SIMD или исполнительных устройств, управляемых общим декодером инструкций.
Множество векторизуемых типов включает:
- все стандартные целочисленные типы и символьные типы;
- большинство типов с плавающей точкой, включая float, double и выбранные расширенные типы с плавающей точкой: std::float16_t, std::float32_t и std::float64_t, если они определены; и
-
std::complex<T>, где
T— векторизуемый тип с плавающей точкой.
Тип с параллелизмом по данным состоит из одного или нескольких элементов базового векторизуемого типа, называемого типом элемента . Количество элементов, называемое шириной , является постоянным для каждого типа с параллелизмом по данным.
Тип с параллелизмом по данным обозначает все разрешённые специализации шаблонов классов basic_vec и basic_mask.
Объект с параллелизмом по данным типа с параллелизмом по данным ведёт себя аналогично объектам типа T. Однако, если T хранит и обрабатывает одно значение, тип с параллелизмом по данным и типом элемента T хранит и обрабатывает несколько значений.
Каждая операция над объектом с параллелизмом по данным выполняется поэлементно (за исключением горизонтальных операций, например редукций, которые явно обозначены как таковые) и применяется к каждому элементу объекта или к соответствующим элементам двух объектов. Каждое такое применение не упорядочено относительно остальных. Это простое правило выражает параллелизм по данным и используется компилятором для генерации инструкций SIMD и/или независимых потоков выполнения.
Все операции (кроме перегрузок математических функций, не являющихся constexpr) над объектами с параллелизмом по данным являются constexpr: можно создавать и использовать такие объекты при вычислении константного выражения.
Шаблоны псевдонимов vec и mask определены, чтобы позволить пользователям задавать ширину определённого размера. Ширина по умолчанию определяется реализацией во время компиляции.
Определено в заголовке <simd> |
|
|---|---|
Определено в пространстве имён std::simd |
Основные классы
|
(C++26) | векторный тип с параллелизмом по данным (шаблон класса) |
|
(C++26) | удобный шаблон псевдонима для basic_vec, позволяющий задавать его ширину(шаблон псевдонима) |
|
(C++26) | тип с параллелизмом по данным и типом элемента bool (шаблон класса) |
|
(C++26) | удобный шаблон псевдонима для basic_mask, позволяющий задавать его ширину(шаблон псевдонима) |
Флаги загрузки и сохранения
|
(C++26) | флаги загрузки и сохранения для типов с параллелизмом по данным (шаблон класса) |
|
(C++26) | флаг по умолчанию, используемый в операциях загрузки и сохранения (константа) |
|
(C++26) | флаг, разрешающий преобразования, не сохраняющие значение, в операциях загрузки и сохранения (константа) |
|
(C++26) | флаг, указывающий, что адрес загрузки-сохранения выровнен относительно некоторой заданной области хранения до значения simd::alignment (константа) |
|
(C++26) | флаг, указывающий, что адрес загрузки-сохранения выровнен относительно некоторой заданной области хранения до указанного значения выравнивания (шаблон переменной) |
Операции загрузки и сохранения
|
(C++26) | загружает элементы из непрерывного диапазона в basic_vec (шаблон функции) |
|
(C++26) | сохраняет элементы из basic_vec в непрерывный диапазон (шаблон функции) |
Преобразования типов
|
(C++26) | разбивает один объект с параллелизмом по данным на несколько объектов (шаблон функции) |
|
(C++26) | объединяет несколько объектов с параллелизмом по данным в один объект (шаблон функции) |
Алгоритмы
|
(C++26) | поэлементные операции нахождения минимума/максимума для basic_vec (шаблон функции) |
|
(C++26) | поэлементная операция ограничения значения диапазоном для basic_vec (шаблон функции) |
|
(C++26) | поэлементный выбор с использованием условного оператора (шаблон функции) |
Редукции
|
(C++26) | сводит все значения в basic_vec к одному значению с помощью заданной бинарной операции (шаблон функции) |
|
(C++26) | редукции basic_mask к типу bool (шаблон функции) |
|
(C++26) | редукция basic_mask к количеству значений true (шаблон функции) |
|
(C++26) | редукции basic_mask к индексу первого или последнего значения true (шаблон функции) |
Перестановки
|
(C++26) | специальные значения для статического permute (константа) |
|
(C++26) | статические и динамические перестановки basic_vec и basic_mask (шаблон функции) |
|
(C++26) | перестановки со сжатием/расширением basic_vec и basic_mask в соответствии с заданной basic_mask (шаблон функции) |
|
(C++26) | перестановки basic_vec из/в память с необязательной маской записи (шаблон функции) |
Свойства типов
|
(C++26) | получает подходящее выравнивание для simd::flag_aligned (шаблон класса) |
|
(C++26) | изменяет тип элемента типа с параллелизмом по данным (шаблон класса) |
|
(C++26) | изменяет ширину типа с параллелизмом по данным (шаблон класса) |
Математические функции
Все функции из <cmath> и <complex> перегружены для basic_vec.
Функции манипуляции битами
Все функции манипуляции битами из <bit>, кроме std::bit_cast, перегружены для basic_vec.
Подробности реализации
Теги ABI
Типы с параллелизмом по данным basic_vec и basic_mask связаны с тегами ABI . Эти теги — типы, задающие размер и двоичное представление объектов с параллелизмом по данным. Предполагается, что размер и двоичное представление будут изменяться в зависимости от целевой архитектуры и флагов компилятора. Тег ABI вместе с типом элемента определяет ширину.
Тег ABI не зависит от выбора набора машинных инструкций. Выбранный набор машинных инструкций ограничивает используемые типы тегов ABI. Теги ABI позволяют пользователям безопасно передавать объекты типа с параллелизмом по данным через границы единиц трансляции.
Сущности, используемые только для описания
using /*simd-size-type*/ = /* see description */; | (1) | (только для описания*) |
template< std::size_t Bytes > using /*integer-from*/ = /* see description */; | (2) | (только для описания*) |
template< class T, class Abi > constexpr /*simd-size-type*/ /*simd-size-v*/ = /* see description */; | (3) | (только для описания*) |
template< class T > constexpr std::size_t /*mask-element-size*/ = /* see description */; | (4) | (только для описания*) |
template< class T > concept /*constexpr-wrapper-like*/ = /* see description */; | (5) | (только для описания*) |
template< class T > using /*deduced-simd-t*/ = /* see description */; | (6) | (только для описания*) |
template< class V, class T > using /*make-compatible-simd-t*/ = /* see description */; | (7) | (только для описания*) |
T, такого что sizeof(T) равно Bytes.basic_vec<T, Abi> или 0 в противном случае.T обозначает std::simd::basic_mask<Bytes,Abi>, то /*mask-element-size*/<T> равно Bytes.template< class T >
concept /*constexpr-wrapper-like*/ =
std::convertible_to<T, decltype(T::value)> &&
std::equality_comparable_with<T, decltype(T::value)> &&
std::bool_constant<T() == T::value>::value &&
std::bool_constant<static_cast<decltype(T::value)>(T()) == T::value>::value;
x — lvalue типа constT. /*deduced-simd-t*/<T> — псевдоним, эквивалентный: -
decltype(x+x), если тип
x + xявляется разрешённой специализациейbasic_vec; в противном случае - void.
x — lvalue типа constT. /*make-compatible-simd-t*/<V,T> — псевдоним, эквивалентный: - /*deduced-simd-t*/<T>, если этот тип не равен void; в противном случае
- std::simd::vec<decltype(x+x),V::size()>.
| Требования к математическим функциям | ||
template< class V > concept /*simd-floating-point*/ = /* see description */; | (8) | (только для описания*) |
template< class... Ts > concept /*math-floating-point*/ = /* see description */; | (9) | (только для описания*) |
template< class... Ts > requires /*math-floating-point*/<Ts...> using /*math-common-simd-t*/ = /* see description */; | (10) | (только для описания*) |
template< class BinaryOp, class T > concept /*reduction-binary-operation*/ = /* see description */; | (11) | (только для описания*) |
template< class V >
concept /*simd-floating-point*/ =
std::same_as<V,
std::simd::basic_vec<typename V::value_type,
typename V::abi_type>> &&
std::is_default_constructible_v<V> &&
std::floating_point<typename V::value_type>;
template< class... Ts >
concept /*math-floating-point*/ =
(/*simd-floating-point*/</*deduced-simd-t*/<Ts>> || ...);
T0 обозначает Ts...[0], T1 обозначает Ts...[1], а TRest обозначает набор параметров, такой что T0,T1,TRest... эквивалентно Ts.... Тогда /*math-common-simd-t*/<Ts...> — псевдоним, эквивалентный: -
/*deduced-simd-t*/<T0>, если
sizeof...(Ts) == 1являетсяtrue - в противном случае std::common_type_t</*deduced-simd-t*/<T0>,/*deduced-simd-t*/<T1>>, если
sizeof...(Ts) == 2являетсяtrueи/*math-floating-point*/<T0> && /*math-floating-point*/<T1>являетсяtrue, - в противном случае std::common_type_t</*deduced-simd-t*/<T0>,T1>, если
sizeof...(Ts) == 2являетсяtrueи/*math-floating-point*/<T0>являетсяtrue, - в противном случае std::common_type_t<T0,/*deduced-simd-t*/<T1>>, если
sizeof...(Ts) == 2являетсяtrue, - в противном случае std::common_type_t</*math-common-simd-t*/<T0,T1>,TRest...>, если /*math-common-simd-t*/<T0,T1> является допустимым типом,
- в противном случае std::common_type_t</*math-common-simd-t*/<TRest...>,T0,T1>.
template< class BinaryOp, class T >
concept /*reduction-binary-operation*/ =
requires (const BinaryOp binary_op, const std::simd::vec<T, 1> v) {
{ binary_op(v, v) } -> std::same_as<std::simd::vec<T, 1>>;
};
/*reduction-binary-operation*/<BinaryOp,T> моделируется только если:
-
BinaryOpявляется коммутативной поэлементной бинарной операцией, и - объект типа
BinaryOpможно вызвать с двумя аргументами типа std::simd::basic_vec<T,Abi> для неуказанного тега ABIAbi; вызов возвращает std::simd::basic_vec<T,Abi>.
| Теги ABI SIMD | ||
template< class T > using /*native-abi*/ = /* see description */; | (12) | (только для экспозиции*) |
template< class T, /*simd-size-type*/ N > using /*deduce-abi-t*/ = /* see description */; | (13) | (только для экспозиции*) |
-
/*simd-size-v*/<T,/*deduce-abi-t*/<T,N>> равен
N, - std::simd::basic_vec<T,/*deduce-abi-t*/<T,N>> является разрешённой специализацией, и
- std::simd::basic_mask<sizeof(T),/*deduce-abi-t*/</*integer-from*/<sizeof(T)>,N>> является разрешённой специализацией.
T является векторизуемым типом, а N > 0 && N <= M — true, где M — определяемое реализацией максимальное значение, не меньшее 64, которое может различаться в зависимости от T. | Флаги загрузки и сохранения | ||
struct /*convert-flag*/; | (14) | (только для экспозиции*) |
struct /*aligned-flag*/; | (15) | (только для экспозиции*) |
template< std::size_t N > struct /*overaligned-flag*/; | (16) | (только для экспозиции*) |
std::simd::flags. Соответствующие варианты использования описаны в разделе флаги загрузки и сохранения.Примечания
| Макрос проверки поддержки | Значение | Стандарт | Возможность |
|---|---|---|---|
__cpp_lib_simd | 202411L | (C++26) | Типы и операции для обработки данных в параллельном режиме |
202603L | (C++26) | Преобразование consteval с сохранением значения в simd::vec |
|
__cpp_lib_simd_complex | 202502L | (C++26) | Чередующиеся комплексные значения |
__cpp_lib_simd_permutations | 202506L | (C++26) | Перестановки SIMD |
Пример
#include <iostream>
#include <simd>
#include <string_view>
namespace simd = std::simd;
void println(std::string_view name, auto const& a)
{
std::cout << name << ": ";
for (std::size_t i{}; i != a.size(); ++i)
std::cout << a[i] << ' ';
std::cout << '\n';
}
template<class A>
constexpr simd::basic_vec<int, A> my_abs(simd::basic_vec<int, A> x)
{
return simd::select(x < 0, -x, x);
}
int main()
{
constexpr simd::vec<int> a = 1;
println("a", a);
constexpr simd::vec<int> b([](int i) { return i - 2; });
println("b", b);
constexpr auto c = a + b;
println("c", c);
constexpr auto d = my_abs(c);
println("d", d);
constexpr auto e = d * d;
println("e", e);
constexpr auto inner_product = simd::reduce(e);
std::cout << "inner product: " << inner_product << '\n';
constexpr simd::vec<double, 16> x([](int i) { return i; });
println("x", x);
// overloaded math functions are defined in <simd>
println("cos²(x) + sin²(x)", std::pow(std::cos(x), 2) + std::pow(std::sin(x), 2));
}
Вывод:
a: 1 1 1 1 b: -2 -1 0 1 c: -1 0 1 2 d: 1 0 1 2 e: 1 0 1 4 inner product: 6 x: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cos²(x) + sin²(x): 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
См. также
|
(parallelism TS v2) | тип вектора для обработки данных в параллельном режиме (шаблон класса) |
| числовые массивы, маски массивов и срезы массивов (шаблон класса) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/numeric/simd