Data-parallel types (SIMD) (since C++26)
La biblioteca proporciona tipos de datos paralelos y operaciones sobre estos tipos: tipos portátiles para declarar explícitamente el paralelismo de datos y estructurar datos mediante recursos de ejecución de datos paralelos donde estén disponibles, como SIMD registros e instrucciones o unidades de ejecución que son controladas por un decodificador de instrucciones común.
El conjunto de tipos vectorizables comprende:
- todos los tipos estándar de enteros y caracteres;
- la mayoría de los tipos de punto flotante incluyendo float , double , y los tipos de punto flotante extendidos seleccionados: std:: float16_t , std:: float32_t , y std:: float64_t si están definidos; y
-
std::
complex
<
T
>
donde
Tes un tipo de punto flotante vectorizable.
Un tipo de datos paralelos consiste en uno o más elementos de un tipo subyacente vectorizable, llamado tipo de elemento . El número de elementos, llamado ancho , es constante para cada tipo de datos paralelos.
El tipo de datos paralelo se refiere a todas las especializaciones habilitadas de las plantillas de clase
basic_simd
y
basic_simd_mask
.
Un
objeto de datos paralelos
de tipo de datos paralelos se comporta de manera análoga a objetos de tipo
T
. Pero mientras
T
almacena y manipula un solo valor, el tipo de datos paralelos con el tipo de elemento
T
almacena y manipula múltiples valores.
Cada operación sobre un objeto de datos paralelos actúa elemento por elemento (excepto para operaciones horizontales, como las reducciones, que están claramente marcadas como tales) aplicándose a cada elemento del objeto o a elementos correspondientes de dos objetos. Cada una de estas aplicaciones no está secuenciada respecto a las demás. Esta regla simple expresa el paralelismo de datos y será utilizada por el compilador para generar instrucciones SIMD y/o flujos de ejecución independientes.
Todas las operaciones (excepto las sobrecargas de funciones matemáticas no constexpr ) en objetos de datos paralelos son constexpr : es posible crear y utilizar objetos de datos paralelos en la evaluación de una expresión constante.
Las plantillas de alias
simd
y
simd_mask
se definen para permitir a los usuarios especificar el ancho a un tamaño determinado. El ancho predeterminado es determinado por la implementación en tiempo de compilación.
|
Definido en el encabezado
<simd>
|
|
|
Definido en el espacio de nombres
std::datapar
|
Contenido
Clases principales
Banderas de carga y almacenamiento
Operaciones de carga y almacenamiento
Conversiones
Algoritmos
Reducciones
Permutaciones
Rasgos
Funciones matemáticas
Todas las funciones en
<cmath>
y
<complex>
están sobrecargadas para
Funciones de manipulación de bitsTodas las funciones de manipulación de bits en <bit> excepto std::bit_cast están sobrecargadas para
Detalles de implementaciónEtiquetas ABI
Los tipos de datos paralelos
La etiqueta ABI permanece independiente de la selección del conjunto de instrucciones de máquina. El conjunto de instrucciones de máquina elegido limita los tipos de etiquetas ABI utilizables. Las etiquetas ABI permiten a los usuarios pasar de forma segura objetos de tipo data-parallel a través de los límites de las unidades de traducción.
Entidades solo para exposición
1)
/*simd-size-type*/
es un alias para un tipo entero con signo. La implementación es libre de elegir cualquier tipo entero con signo.
2)
/*integer-from*/
<
Bytes
>
es un alias para un tipo entero con signo
T
tal que
sizeof
(
T
)
es igual a
Bytes
.
3)
/*simd-size-v*/
<
T, Abi
>
denota el ancho de la especialización habilitada
basic_simd<T, Abi>
, o
0
en caso contrario.
4)
Si
T
denota
std
::
datapar
::
basic_simd_mask
<
Bytes, Abi
>
,
/*mask-element-size*/
<
T
>
es igual a
Bytes
.
5)
El concepto
/*constexpr-wrapper-like*/
se define como:
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)
Sea
x
un lvalue de tipo
const
T
.
/*deduced-simd-t*/
<
T
>
es un alias equivalente a:
7)
Sea
x
un lvalue de tipo
const
T
.
/*make-compatible-simd-t*/
<
V, T
>
es un alias equivalente a:
8)
El concepto
/*simd-floating-point*/
se define como:
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)
El concepto
/*math-floating-point*/
se define como:
template< class... Ts > concept /*math-floating-point*/ = (/*simd-floating-point*/</*deduced-simd-t*/<Ts>> || ...);
10)
Sea
T0
que denota
Ts...
[
0
]
,
T1
que denota
Ts...
[
1
]
, y
TRest
que denota un paquete tal que
T0, T1, TRest...
es equivalente a
Ts...
. Entonces,
/*math-common-simd-t*/
<
Ts...
>
es un alias equivalente a:
11)
El concepto
/*reduction-binary-operation*/
se define como:
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 > se modela solo si:
12)
/*native-abi*/
<
T
>
es un alias definido por la implementación para una etiqueta ABI. Esta es la etiqueta ABI principal para usar en vectorización explícita eficiente. Como resultado,
basic_simd
<
T,
/*native-abi*/
<
T
>>
es una especialización habilitada.
13)
/*deduce-abi-t*/
<
T, N
>
es un alias que nombra un tipo de etiqueta ABI tal que:
T
es un tipo vectorizable, y
N
>
0
&&
N
<=
M
es
true
, donde
M
es un máximo definido por la implementación que es al menos
64
y puede diferir dependiendo de
T
.
14-16)
Estos tipos de etiqueta se utilizan como argumento de plantilla de
std::datapar::flags
. Consulte
banderas de carga y almacenamiento
para sus usos correspondientes.
Notas
Ejemplo
Ejecutar este código
#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)); } Salida: 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 Véase también
|