Data-parallel types (SIMD) (since C++26)
Библиотека предоставляет типы с параллельной обработкой данных и операции над этими типами: портативные типы для явного указания параллелизма данных и структурирования данных через ресурсы выполнения с параллельной обработкой данных, где это доступно, такие как 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
|
Содержание
Основные классы
Флаги загрузки и сохранения
Операции загрузки и сохранения
Приведения типов
Алгоритмы
Редукции
Перестановки
Трейты
Математические функции
Все функции в
<cmath>
и
<complex>
перегружены для
Функции для работы с битамиВсе функции для работы с битами из <bit>, кроме std::bit_cast, перегружены для
Детали реализацииABI теги
Типы с параллельной обработкой данных
Тег ABI остается независимым от выбора набора машинных инструкций. Выбранный набор машинных инструкций ограничивает доступные типы тегов ABI. Теги ABI позволяют пользователям безопасно передавать объекты типа data-parallel через границы единиц трансляции.
Сущности только для экспозиции
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
>
является псевдонимом, эквивалентным:
7)
Пусть
x
будет lvalue типа
const
T
.
/*make-compatible-simd-t*/
<
V, T
>
является псевдонимом, эквивалентным:
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...
>
является псевдонимом, эквивалентным:
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 > моделируется только если:
12)
/*native-abi*/
<
T
>
является реализационно-определенным псевдонимом для ABI-тега. Это основной ABI-тег для эффективной явной векторизации. В результате,
basic_simd
<
T,
/*native-abi*/
<
T
>>
является включенной специализацией.
13)
/*deduce-abi-t*/
<
T, N
>
является псевдонимом, который обозначает тип тега ABI таким образом, что:
T
является векторизуемым типом, и
N
>
0
&&
N
<=
M
равно
true
, где
M
— это определённый реализацией максимум, который составляет не менее
64
и может различаться в зависимости от
T
.
14-16)
Эти типы тегов используются в качестве аргумента шаблона для
std::datapar::flags
. Смотрите
флаги загрузки и сохранения
для соответствующих вариантов их использования.
Примечания
Пример
Запустить этот код
#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 Смотрите также
|