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

Plantilla:cpp/numeric/simd/dsc basic vecPlantilla:cpp/numeric/simd/dsc vecPlantilla:cpp/numeric/simd/dsc basic maskPlantilla:cpp/numeric/simd/dsc mask

Indicadores de carga y almacenamiento

Plantilla:cpp/numeric/simd/dsc flagsPlantilla:cpp/numeric/simd/dsc flag defaultPlantilla:cpp/numeric/simd/dsc flag convertPlantilla:cpp/numeric/simd/dsc flag alignedPlantilla:cpp/numeric/simd/dsc flag overaligned

Operaciones de carga y almacenamiento

Plantilla:cpp/numeric/simd/dsc loadPlantilla:cpp/numeric/simd/dsc store

Moldes

Plantilla:cpp/numeric/simd/dsc chunkPlantilla:cpp/numeric/simd/dsc cat

Algoritmos

Plantilla:cpp/numeric/simd/dsc min maxPlantilla:cpp/numeric/simd/dsc clampPlantilla:cpp/numeric/simd/dsc select

Reducciones

Plantilla:cpp/numeric/simd/dsc reducePlantilla:cpp/numeric/simd/dsc all any none ofPlantilla:cpp/numeric/simd/dsc reduce countPlantilla:cpp/numeric/simd/dsc reduce min max index

Permutaciones

Plantilla:cpp/numeric/simd/dsc zero uninit elementPlantilla:cpp/numeric/simd/dsc permutePlantilla:cpp/numeric/simd/dsc mask permutePlantilla:cpp/numeric/simd/dsc memory permute

Rasgos

Plantilla:cpp/numeric/simd/dsc alignmentPlantilla:cpp/numeric/simd/dsc rebindPlantilla:cpp/numeric/simd/dsc resize

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

Plantilla:cpp/experimental/simd/dsc simd
arrays numéricos, máscaras de arrays y secciones de array.
(plantilla de clase) [editar]