Espacios de nombres
Variantes

Tipos de paralelismo de datos (SIMD) (desde C++26)

De cppreference.com
 
 
 
 

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 los datos a través de recursos de ejecución paralela de datos cuando estén disponibles, como registros e instrucciones SIMD o unidades de ejecución que son controladas por un decodificador de instrucciones común.

El conjunto de tipos vectorizables comprende:

  • todos los enteros y tipos carácter estándar;
  • la mayoría de los tipos de punto flotante, incluidos 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 T es un tipo de punto flotante vectorizable.

Un tipo de datos paralelos consiste en uno o más elementos de un tipo vectorizable subyacente, llamado tipo de elemento . El número de elementos, llamado ancho , es constante para cada tipo de datos paralelos.

El tipo de datos paralelos se refiere a todas las especializaciones habilitadas de las plantillas de clase basic_vec y basic_mask.

Un objeto de datos paralelos de tipo de datos paralelos se comporta de manera análoga a los 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 a elemento (excepto para operaciones horizontales, como reducciones, que están claramente marcadas como tales) aplicándose a cada elemento del objeto o a elementos correspondientes de dos objetos. Cada aplicación de este tipo no está secuenciada con 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 función matemáticas no constexpr) sobre objetos de datos paralelos son constexpr: es posible crear y usar objetos de datos paralelos en la evaluación de una expresión constante.

Las plantillas de alias vec y mask se definen para permitir a los usuarios especificar el ancho a un tamaño determinado. El ancho predeterminado lo determina la implementación en tiempo de compilación.

Definido en el encabezado <simd>
Definido en el espacio de nombres std::simd

Clases principales

Tipo de vector de paralelismo de datos.
(plantilla de clase) [editar]
(C++26)
Plantilla de alias de conveniencia para basic_vec que permite especificar su anchura.
(plantilla de alias) [editar]
Tipo de paralelismo de datos con el tipo de elemento bool.
(plantilla de clase) [editar]
Plantilla de alias de conveniencia para basic_mask que permite especificar su anchura.
(plantilla de alias) [editar]

Indicadores de carga y almacenamiento

Indicadores de carga y almacenamiento para tipos de paralelismo de datos.
(plantilla de clase) [editar]
Indicador predeterminado utilizado en operaciones de carga y almacenamiento.
(constante) [editar]
Indicador que habilita conversiones que no preservan el valor en operaciones de carga y almacenamiento.
(constante) [editar]
Indicador de que la dirección de carga o almacenamiento está alineada según simd::alignment.
(constante) [editar]
Indicador de que la dirección de carga o almacenamiento está alineada según una alineación específica.
(plantilla de variables) [editar]

Operaciones de carga y almacenamiento

Carga elementos desde un rango contiguo a basic_vec.
(plantilla de función) [editar]
Almacena elementos de basic_vec en un rango contiguo.
(plantilla de función) [editar]

Moldes

Divide un único objeto de paralelismo de datos en varios.
(plantilla de función) [editar]
(C++26)
Concatena múltiples objetos de paralelismo de datos en uno solo.
(plantilla de función) [editar]

Algoritmos

Operaciones de mínimo/máximo elemento a elemento para basic_vec.
(plantilla de función) [editar]
Operación de acotado elemento a elemento para basic_vec.
(plantilla de función) [editar]
Selección elemento a elemento mediante el operador condicional.
(plantilla de función) [editar]

Reducciones

Reduce todos los valores de basic_vec a un único valor mediante una operación binaria especificada.
(plantilla de función) [editar]
Reducciones de basic_mask a bool.
(plantilla de función) [editar]
Reducción de basic_mask al número de valores true.
(plantilla de función) [editar]
Reducciones de basic_mask al índice del primer o último valor true.
(plantilla de función) [editar]

Permutaciones

Valores especiales para permute estático.
(constante) [editar]
Permutaciones estáticas y dinámicas de basic_vec y basic_mask.
(plantilla de función) [editar]
Compresión / expansión de permutaciones de basic_vec y basic_mask según una basic_mask dada.
(plantilla de función) [editar]
Permutaciones de basic_vec desde/hacia la memoria con máscara de escritura opcional.
(plantilla de función) [editar]

Rasgos

Obtiene una alineación adecuada para simd::flag_aligned.
(plantilla de clase) [editar]
Cambia el tipo de elemento del tipo de paralelismo de datos.
(plantilla de clase) [editar]
Cambia la anchura del tipo de paralelismo de datos.
(plantilla de clase) [editar]

Funciones matemáticas

Todas las funciones en <cmath> y <complex> están sobrecargadas para basic_vec.

Funciones de manipulación de bits

Todas las funciones de manipulación de bits en <bit> están sobrecargadas para basic_vec.

Detalles de implementación

Etiquetas ABI

Los tipos de datos paralelos basic_vec y basic_mask están asociados con etiquetas ABI . Estas etiquetas son tipos que especifican el tamaño y la representación binaria de los objetos de datos paralelos. El diseño pretende que el tamaño y la representación binaria varíen según la arquitectura de destino y las banderas del compilador. La etiqueta ABI, junto con el tipo de elemento, determina el ancho.

La etiqueta ABI permanece independiente de la selección del conjunto de instrucciones de la máquina. El conjunto de instrucciones de la máquina elegido limita los tipos de etiquetas ABI utilizables. Las etiquetas ABI permiten a los usuarios pasar de manera segura objetos de tipo de datos paralelos a través de los límites de las unidades de traducción.

Entidades solo de exposición

using /*simd-size-type*/ = /* véase descripción */;
(1) (solo de exposición*)
template< std::size_t Bytes > using /*integer-from*/ = /* véase descripción */;
(2) (solo de exposición*)
template< class T, class Abi > constexpr /*simd-size-type*/ /*simd-size-v*/ = /* véase descripción */;
(3) (solo de exposición*)
template< class T > constexpr std::size_t /*mask-element-size*/ = /* véase descripción */;
(4) (solo de exposición*)
template< class T > concept /*constexpr-wrapper-like*/ = /* véase descripción */;
(5) (solo de exposición*)
template< class T > using /*deduced-simd-t*/ = /* véase descripción */;
(6) (solo de exposición*)
template< class V, class T > using /*make-compatible-simd-t*/ = /* véase descripción */;
(7) (solo de 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_vec<T, Abi>, o 0 en caso contrario.
4) Si T denota std::simd::basic_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 l-valor de tipo const T. /*deduced-simd-t*/<T> es un alias equivalente a:
  • decltype(x + x), si el tipo de x + x es una especialización habilitada de basic_vec; de lo contrario
  • void.
7) Sea x un l-valor de tipo const T. /*make-compatible-simd-t*/<V, T> es un alias equivalente a:
  • /*deduced-simd-t*/<T>, si ese tipo no es void, de lo contrario
  • std::simd::vec<decltype(x + x), V::size()>.
Requisitos de funciones matemáticas
template< class V > concept /*simd-floating-point*/ = /* véase descripción */;
(8) (solo de exposición*)
template< class... Ts > concept /*math-floating-point*/ = /* véase descripción */;
(9) (solo de exposición*)
template< class... Ts > requires /*math-floating-point*/<Ts...> using /*math-common-simd-t*/ = /* véase descripción */;
(10) (solo de exposición*)
template< class BinaryOp, class T > concept /*reduction-binary-operation*/ = /* véase descripción */;
(11) (solo de exposición*)
8) El concepto /*simd-floating-point*/ se define como:
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>;
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:
  • /*deduced-simd-t*/<T0>, si sizeof...(Ts) == 1 es true
  • de lo contrario, std::common_type_t</*deduced-simd-t*/<T0>, /*deduced-simd-t*/<T1>>, si sizeof...(Ts) == 2 es true y /*math-floating-point*/<T0> && /*math-floating-point*/<T1> es true,
  • de lo contrario, std::common_type_t</*deduced-simd-t*/<T0>, T1> si sizeof...(Ts) == 2 es true y /*math-floating-point*/<T0> es true,
  • de lo contrario, std::common_type_t<T0, /*deduced-simd-t*/<T1>> si sizeof...(Ts) == 2 es true,
  • de lo contrario, std::common_type_t</*math-common-simd-t*/<T0, T1>, TRest...>, si /*math-common-simd-t*/<T0, T1> es un tipo válido,
  • de lo contrario, std::common_type_t</*math-common-simd-t*/<TRest...>, T0, T1>.
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::simd::vec<T, 1> v) {
        { binary_op(v, v) } -> std::same_as<std::simd::vec<T, 1>>;
    };

/*reduction-binary-operation*/<BinaryOp, T> se modela solo si:

  • BinaryOp es una operación binaria elemento a elemento que es conmutativa, y
  • Un objeto de tipo BinaryOp es invocable con dos argumentos de tipo std::simd::basic_vec<T, Abi> para una etiqueta ABI no especificada Abi que devuelve un std::simd::basic_vec<T, Abi>.
Etiquetas ABI SIMD
template< class T > using /*native-abi*/ = /* véase descripción */;
(12) (solo de exposición*)
template< class T, /*simd-size-type*/ N > using /*deduce-abi-t*/ = /* véase descripción */;
(13) (solo de exposición*)
12) /*native-abi*/<T> es un alias definido por la implementación para una etiqueta ABI. Esta es la etiqueta ABI principal que debe utilizarse para una vectorización explícita eficiente. Como resultado, basic_vec<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:
  • /*simd-size-v*/<T, /*deduce-abi-t*/<T, N>> es igual a N,
  • std::simd::basic_vec<T, /*deduce-abi-t*/<T, N>> es una especialización habilitada, y
  • std::simd::basic_mask<sizeof(T), /*deduce-abi-t*/</*integer-from*/<sizeof(T)>, N>> es una especialización habilitada.
Se define solo si 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.
Indicadores de carga y almacenamiento
struct /*convert-flag*/;
(14) (solo de exposición*)
struct /*aligned-flag*/;
(15) (solo de exposición*)
template< std::size_t N > struct /*overaligned-flag*/;
(16) (solo de exposición*)
14-16) Estos tipos de etiquetas se utilizan como un argumento de plantilla de std::simd::flags. Consulte indicadores de carga y almacenamiento para sus usos correspondientes.

Notas

Macro de prueba de característica
__cpp_lib_simd 202411L (C++26) Tipos y operaciones de paralelismo de datos
202603L (C++26) Difusión consteval que preserva el valor a simd::vec
__cpp_lib_simd_complex 202502L (C++26) Valores complejos entrelazados
__cpp_lib_simd_permutations 202506L (C++26) Permutaciones SIMD

Ejemplo

#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 << "producto interno: " << inner_product << '\n';

    constexpr simd::vec<double, 16> x([](int i) { return i; });
    println("x", x);
    // Las funciones matemáticas sobrecargadas se definen en <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 
producto interno: 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

Tipo vectorial de paralelismo de datos.
(plantilla de clase) [editar]
arrays numéricos, máscaras de arrays y secciones de array.
(plantilla de clase) [editar]