Namespaces
Variants

Data-parallel types (SIMD) (since C++26)

From cppreference.net

Библиотека предоставляет типы с параллельной обработкой данных и операции над этими типами: портативные типы для явного указания параллелизма данных и структурирования данных через ресурсы выполнения с параллельной обработкой данных, где это доступно, такие как SIMD регистры и инструкции или исполнительные блоки, управляемые общим декодером инструкций.

Набор vectorizable types включает:

  • все стандартные целочисленные и символьные типы;
  • большинство типов с плавающей запятой, включая float , double , и выбранные расширенные типы с плавающей запятой: std:: float16_t , std:: float32_t , и std:: float64_t , если они определены; и
  • std:: complex < T > где T - векторный тип с плавающей запятой.

Тип с параллельной обработкой данных состоит из одного или нескольких элементов базового векторизуемого типа, называемого элементным типом  . Количество элементов, называемое шириной  , является постоянным для каждого типа с параллельной обработкой данных.

Тип с параллельной обработкой данных относится ко всем включенным специализациям шаблонов классов basic_simd и basic_simd_mask .

Data-parallel объект типа data-parallel ведет себя аналогично объектам типа T . Но в то время как T хранит и обрабатывает единственное значение, тип data-parallel с типом элементов T хранит и обрабатывает множество значений.

Каждая операция над объектом с параллельной обработкой данных действует поэлементно (за исключением горизонтальных операций, таких как редукции, которые явно обозначены как таковые), применяясь к каждому элементу объекта или к соответствующим элементам двух объектов. Каждое такое применение неупорядочено относительно других. Это простое правило выражает параллелизм данных и будет использоваться компилятором для генерации SIMD инструкций и/или независимых потоков выполнения.

Все операции (за исключением не- constexpr перегрузок математических функций) над объектами data-parallel являются constexpr : возможно создавать и использовать объекты data-parallel при вычислении константных выражений.

Шаблоны псевдонимов simd и simd_mask определены для того, чтобы позволить пользователям указывать ширину определенного размера. Ширина по умолчанию определяется реализацией во время компиляции.

Определено в заголовке <simd>
Определено в пространстве имён std::datapar

Содержание

Основные классы

тип вектора для параллельной обработки данных
(шаблон класса)
удобный псевдоним-шаблон для basic_simd с возможностью указания ширины
(псевдоним-шаблон)
тип для параллельной обработки данных с типом элементов bool
(шаблон класса)
удобный псевдоним-шаблон для basic_simd_mask с возможностью указания ширины
(псевдоним-шаблон)

Флаги загрузки и сохранения

флаги загрузки и сохранения для типов параллельной обработки данных
(шаблон класса)
флаг по умолчанию, используемый в операциях загрузки и сохранения
(константа)
флаг, разрешающий преобразования, не сохраняющие значения, в операциях загрузки и сохранения
(константа)
флаг, указывающий выравнивание адреса загрузки-сохранения для некоторого заданного хранилища до значения datapar::alignment
(константа)
флаг, указывающий выравнивание адреса загрузки-сохранения для некоторого заданного хранилища до указанного выравнивания
(переменный шаблон)

Операции загрузки и сохранения

загружает элементы из непрерывного диапазона в basic_simd
(шаблон функции)
сохраняет элементы из basic_simd в непрерывный диапазон
(шаблон функции)

Приведения типов

разделяет один объект параллельной обработки данных на несколько
(шаблон функции)
объединяет несколько объектов параллельной обработки данных в один
(шаблон функции)

Алгоритмы

поэлементные операции min/max для basic_simd
(шаблон функции)
поэлементная операция clamp для basic_simd
(шаблон функции)
поэлементный выбор с использованием условного оператора
(шаблон функции)

Редукции

сводит все значения в basic_simd к одному значению с помощью указанной бинарной операции
(шаблон функции)
редукции basic_simd_mask в bool
(шаблон функции)
редукция basic_simd_mask в количество true значений
(шаблон функции)
редукции basic_simd_mask в индекс первого или последнего true значения
(шаблон функции)

Трейты

получает соответствующее выравнивание для datapar::flag_aligned
(шаблон класса)
изменяет тип элементов типа данных с параллельной обработкой
(шаблон класса)
изменяет ширину типа данных с параллельной обработкой
(шаблон класса)

Математические функции

Все функции в <cmath> и <complex> перегружены для basic_simd .

Функции для работы с битами

Все функции для манипуляции битами в <bit> перегружены для basic_simd .

Детали реализации

ABI теги

Типы с параллельной обработкой данных basic_simd и basic_simd_mask ассоциированы с тегами ABI  . Эти теги представляют собой типы, которые определяют размер и двоичное представление объектов с параллельной обработкой данных. Конструкция предполагает, что размер и двоичное представление будут варьироваться в зависимости от целевой архитектуры и флагов компилятора. Тег ABI вместе с типом элемента определяет ширину.

Тег ABI остается независимым от выбора набора машинных инструкций. Выбранный набор машинных инструкций ограничивает доступные типы тегов ABI. Теги ABI позволяют пользователям безопасно передавать объекты типа data-parallel через границы единиц трансляции.

Сущности только для экспозиции

using /*simd-size-type*/ = /* см. описание */ ;
(1) ( только для демонстрации* )
template < std:: size_t Bytes >
using /*integer-from*/ = /* см. описание */ ;
(2) ( только для демонстрации* )
template < class T, class Abi >
constexpr /*simd-size-type*/ /*simd-size-v*/ = /* см. описание */ ;
(3) ( только для демонстрации* )
template < class T >
constexpr std:: size_t /*mask-element-size*/ = /* см. описание */ ;
(4) ( только для демонстрации* )
template < class T >
concept /*constexpr-wrapper-like*/ = /* см. описание */ ;
(5) ( только для демонстрации* )
template < class T >
using /*deduced-simd-t*/ = /* см. описание */ ;
(6) ( только для демонстрации* )
template < class V, class T >
using /*make-compatible-simd-t*/ = /* см. описание */ ;
(7) ( только для демонстрации* )
1) /*simd-size-type*/ является псевдонимом для знакового целочисленного типа. Реализация может выбрать любой знаковый целочисленный тип.
2) /*integer-from*/ < Bytes > является псевдонимом для знакового целочисленного типа T такого, что sizeof ( T ) равно Bytes .
3) /*simd-size-v*/ < T, Abi > обозначает ширину включенной специализации basic_simd<T, Abi> , или 0 в противном случае.
4) Если T обозначает std :: datapar :: basic_simd_mask < Bytes, Abi > , /*mask-element-size*/ < T > равен Bytes .
5) Концепт /*constexpr-wrapper-like*/ определяется следующим образом:
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;
6) Пусть x будет lvalue типа const T . /*deduced-simd-t*/ < T > является псевдонимом, эквивалентным:
  • decltype ( x + x ) , если тип x + x является активной специализацией basic_simd ; иначе
  • void .
7) Пусть x будет lvalue типа const T . /*make-compatible-simd-t*/ < V, T > является псевдонимом, эквивалентным:
  • /*deduced-simd-t*/ < T > , если этот тип не является void , в противном случае
  • std :: datapar :: simd < 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) ( только для демонстрации* )
8) Концепт /*simd-floating-point*/ определяется как:
template< class V >
concept /*simd-floating-point*/ =
    std::same_as<V,
                 std::datapar::basic_simd<typename V::value_type,
                 typename V::abi_type>> &&
    std::is_default_constructible_v<V> && 
    std::floating_point<typename V::value_type>;
9) Концепт /*math-floating-point*/ определяется как:
template< class... Ts >
concept /*math-floating-point*/ =
    (/*simd-floating-point*/</*deduced-simd-t*/<Ts>> || ...);
10) Пусть 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 > .
11) Концепт /*reduction-binary-operation*/ определяется как:
template< class BinaryOp, class T >
concept /*reduction-binary-operation*/ =
    requires (const BinaryOp binary_op, const std::datapar::simd<T, 1> v) {
        { binary_op(v, v) } -> std::same_as<std::datapar::simd<T, 1>>;
    };

/*reduction-binary-operation*/ < BinaryOp, T > моделируется только если:

  • BinaryOp является бинарной поэлементной операцией, которая коммутативна, и
  • Объект типа BinaryOp может быть вызван с двумя аргументами типа std :: datapar :: basic_simd < T, Abi > для неопределенного ABI-тега Abi и возвращает std :: datapar :: basic_simd < T, Abi > .
Теги SIMD ABI
template < class T >
using /*native-abi*/ = /* см. описание */ ;
(12) ( только для демонстрации* )
template < class T, /*simd-size-type*/ N >
using /*deduce-abi-t*/ = /* см. описание */ ;
(13) ( только для демонстрации* )
12) /*native-abi*/ < T > является реализационно-определенным псевдонимом для ABI-тега. Это основной ABI-тег для эффективной явной векторизации. В результате, basic_simd < T, /*native-abi*/ < T >> является включенной специализацией.
13) /*deduce-abi-t*/ < T, N > является псевдонимом, который обозначает тип тега ABI таким образом, что:
  • /*simd-size-v*/ < T, /*deduce-abi-t*/ < T, N >> равно N ,
  • std :: datapar :: basic_simd < T, /*deduce-abi-t*/ < T, N >> является включённой специализацией, и
  • std :: datapar :: basic_simd_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) ( только для демонстрации* )
14-16) Эти типы тегов используются в качестве аргумента шаблона для std::datapar::flags . Смотрите флаги загрузки и сохранения для соответствующих вариантов их использования.

Примечания

Feature-test макрос Значение Стандарт Функциональность
__cpp_lib_simd 202411L (C++26) Типы и операции для параллельной обработки данных
__cpp_lib_simd_complex 202502L (C++26) Поддержка чередующихся комплексных значений в std::datapar::simd

Пример

#include <iostream>
#include <simd>
#include <string_view>
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 std::datapar::basic_simd<int, A> my_abs(std::datapar::basic_simd<int, A> x)
{
    return std::datapar::select(x < 0, -x, x);
}
int main()
{
    constexpr std::datapar::simd<int> a = 1;
    println("a", a);
    constexpr std::datapar::simd<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 = std::datapar::reduce(e);
    std::cout << "inner product: " << inner_product << '\n';
    constexpr std::datapar::simd<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

Смотрите также

числовые массивы, маски массивов и срезы массивов
(шаблон класса)

Внешние ссылки

1. Реализация раздела 9 "Типы с параллелизмом данных" ISO/IEC TS 19570:2018 — github.com
2. Реализация TS доступна для GCC/libstdc++ ( std::experimental::simd поставляется с GCC-11) — gcc.gnu.org