Namespaces
Variants

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

From cppreference.net

Die Bibliothek stellt datenparallele Typen und Operationen auf diesen Typen bereit: portable Typen zur expliziten Angabe von Datenparallelität und Strukturierung von Daten durch datenparallele Ausführungsressourcen, wo verfügbar, wie etwa SIMD Register und Instruktionen oder Ausführungseinheiten, die von einem gemeinsamen Instruktionsdecoder gesteuert werden.

Die Menge der vectorizable types umfasst:

Ein datenparalleler Typ besteht aus einem oder mehreren Elementen eines zugrundeliegenden vektorisierbaren Typs, genannt der Elementtyp . Die Anzahl der Elemente, genannt die Breite , ist für jeden datenparallelen Typ konstant.

Der datenparallele Typ bezieht sich auf alle aktivierten Spezialisierungen der Klassentemplates basic_simd und basic_simd_mask .

Ein Datenparallel-Objekt vom Datenparallel-Typ verhält sich analog zu Objekten des Typs T . Während jedoch T einen einzelnen Wert speichert und manipuliert, speichert und manipuliert der Datenparallel-Typ mit dem Elementtyp T mehrere Werte.

Jede Operation auf einem datenparallelen Objekt wirkt elementweise (mit Ausnahme horizontaler Operationen wie Reduktionen, die eindeutig als solche gekennzeichnet sind) und wendet sich auf jedes Element des Objekts oder auf entsprechende Elemente zweier Objekte an. Jede solche Anwendung ist ungeordnet in Bezug auf die anderen. Diese einfache Regel drückt Datenparallelismus aus und wird vom Compiler genutzt, um SIMD-Befehle und/oder unabhängige Ausführungsströme zu erzeugen.

Alle Operationen (außer nicht- constexpr Mathematik-Funktionsüberladungen) auf datenparallelen Objekten sind constexpr : es ist möglich, datenparallele Objekte in der Auswertung eines konstanten Ausdrucks zu erstellen und zu verwenden.

Alias-Templates simd und simd_mask werden definiert, um Benutzern zu ermöglichen, die Breite auf eine bestimmte Größe festzulegen. Die Standardbreite wird zur Compile-Zeit durch die Implementierung bestimmt.

Definiert in Header <simd>
Definiert in Namespace std::datapar

Inhaltsverzeichnis

Hauptklassen

Datenparalleler Vektortyp
(Klassentemplate)
Bequemlichkeits-Alias-Template für basic_simd , das seine Breite angeben kann
(Alias-Template)
Datenparalleler Typ mit dem Elementtyp bool
(Klassentemplate)
Bequemlichkeits-Alias-Template für basic_simd_mask , das seine Breite angeben kann
(Alias-Template)

Lade- und Speicherflags

Lade- und Speicher-Flags für datenparallele Typen
(Klassentemplate)
Standard-Flag für Lade- und Speicheroperationen
(Konstante)
Flag zur Aktivierung nicht wertbewahrender Konvertierungen bei Lade- und Speicheroperationen
(Konstante)
Flag zur Angabe der Ausrichtung der Lade-Speicher-Adresse an einem bestimmten Speicher auf den Wert von datapar::alignment
(Konstante)
Flag zur Angabe der Ausrichtung der Lade-Speicher-Adresse an einem bestimmten Speicher auf die spezifizierte Ausrichtung
(Variablentemplate)

Lade- und Speicheroperationen

lädt Elemente aus einem zusammenhängenden Bereich in basic_simd
(Funktions-Template)
speichert Elemente aus basic_simd in einen zusammenhängenden Bereich
(Funktions-Template)

Casts

teilt ein einzelnes datenparalleles Objekt in mehrere auf
(Funktions-Template)
verkettet mehrere datenparallele Objekte zu einem einzelnen
(Funktions-Template)

Algorithmen

Elementweise Min/Max-Operationen für basic_simd
(Funktionstemplate)
Elementweise Clamp-Operation für basic_simd
(Funktionstemplate)
Elementweise Selektion mittels Konditionaloperator
(Funktionstemplate)

Reduktionen

reduziert alle Werte in basic_simd über eine spezifizierte binäre Operation auf einen einzelnen Wert
(Funktionstemplate)
Reduktionen von basic_simd_mask zu bool
(Funktionstemplate)
Reduktion von basic_simd_mask zur Anzahl der true Werte
(Funktionstemplate)
Reduktionen von basic_simd_mask zum Index des ersten oder letzten true Wertes
(Funktionstemplate)

Traits

ermittelt eine geeignete Ausrichtung für datapar::flag_aligned
(Klassentemplate)
ändert den Elementtyp des datenparallelen Typs
(Klassentemplate)
ändert die Breite des datenparallelen Typs
(Klassentemplate)

Mathematische Funktionen

Alle Funktionen in <cmath> und <complex> sind überladen für basic_simd .

Bitmanipulationsfunktionen

Alle Bitmanipulationsfunktionen in <bit> sind überladen für basic_simd .

Implementierungsdetails

ABI-Tags

Die datenparallelen Typen basic_simd und basic_simd_mask sind mit ABI-Tags  assoziiert. Diese Tags sind Typen, die die Größe und binäre Darstellung datenparalleler Objekte spezifizieren. Das Design sieht vor, dass Größe und binäre Darstellung je nach Zielarchitektur und Compiler-Flags variieren. Der ABI-Tag bestimmt zusammen mit dem Elementtyp die Breite.

Der ABI-Tag bleibt unabhängig von der Auswahl des Maschinenbefehlssatzes. Der gewählte Maschinenbefehlssatz begrenzt die verwendbaren ABI-Tag-Typen. Die ABI-Tags ermöglichen es Benutzern, Objekte vom Datentyp data-parallel sicher über Übersetzungseinheitsgrenzen hinweg zu übergeben.

Nur zur Darstellung bestimmte Entitäten

using /*simd-size-type*/ = /* siehe Beschreibung */ ;
(1) ( Nur zur Darstellung* )
template < std:: size_t Bytes >
using /*integer-from*/ = /* siehe Beschreibung */ ;
(2) ( Nur zur Darstellung* )
template < class T, class Abi >
constexpr /*simd-size-type*/ /*simd-size-v*/ = /* siehe Beschreibung */ ;
(3) ( Nur zur Darstellung* )
template < class T >
constexpr std:: size_t /*mask-element-size*/ = /* siehe Beschreibung */ ;
(4) ( Nur zur Darstellung* )
template < class T >
concept /*constexpr-wrapper-like*/ = /* siehe Beschreibung */ ;
(5) ( Nur zur Darstellung* )
template < class T >
using /*deduced-simd-t*/ = /* siehe Beschreibung */ ;
(6) ( Nur zur Darstellung* )
template < class V, class T >
using /*make-compatible-simd-t*/ = /* siehe Beschreibung */ ;
(7) ( Nur zur Darstellung* )
1) /*simd-size-type*/ ist ein Alias für einen vorzeichenbehafteten Ganzzahltyp. Die Implementierung kann jeden vorzeichenbehafteten Ganzzahltyp wählen.
2) /*integer-from*/ < Bytes > ist ein Alias für einen vorzeichenbehafteten Ganzzahltyp T , sodass sizeof ( T ) gleich Bytes ist.
3) /*simd-size-v*/ < T, Abi > bezeichnet die Breite der aktivierten Spezialisierung basic_simd<T, Abi> , oder 0 andernfalls.
4) Wenn T für std :: datapar :: basic_simd_mask < Bytes, Abi > steht, /*mask-element-size*/ < T > entspricht Bytes .
5) Das Konzept /*constexpr-wrapper-like*/ ist definiert als:
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) Sei x ein Lvalue vom Typ const T . /*deduced-simd-t*/ < T > ist ein Aliasname, der äquivalent ist zu:
  • decltype ( x + x ) , falls der Typ von x + x eine aktivierte Spezialisierung von basic_simd ist; andernfalls
  • void .
7) Sei x ein Lvalue vom Typ const T . /*make-compatible-simd-t*/ < V, T > ist ein Alias, der äquivalent ist zu:
  • /*deduced-simd-t*/ < T > , falls dieser Typ nicht void ist, andernfalls
  • std :: datapar :: simd < decltype ( x + x ) , V​ :: ​size ( ) > .
Anforderungen an mathematische Funktionen
template < class V >
concept /*simd-floating-point*/ = /* see description */ ;
(8) ( Nur zur Darstellung* )
template < class ... Ts >
concept /*math-floating-point*/ = /* see description */ ;
(9) ( Nur zur Darstellung* )
template < class ... Ts >

requires /*math-floating-point*/ < Ts... >

using /*math-common-simd-t*/ = /* see description */ ;
(10) ( Nur zur Darstellung* )
template < class BinaryOp, class T >
concept /*reduction-binary-operation*/ = /* see description */ ;
(11) ( Nur zur Darstellung* )
8) Das Konzept /*simd-floating-point*/ ist definiert als:
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) Das Konzept /*math-floating-point*/ ist definiert als:
template< class... Ts >
concept /*math-floating-point*/ =
    (/*simd-floating-point*/</*deduced-simd-t*/<Ts>> || ...);
10) Sei T0 für Ts... [ 0 ] , T1 für Ts... [ 1 ] und TRest für ein Pack, sodass T0, T1, TRest... äquivalent zu Ts... ist. Dann ist /*math-common-simd-t*/ < Ts... > ein Alias, der äquivalent ist zu:
  • /*deduced-simd-t*/ < T0 > , falls sizeof... ( Ts ) == 1 true ist
  • andernfalls std:: common_type_t < /*deduced-simd-t*/ < T0 > , /*deduced-simd-t*/ < T1 >> , falls sizeof... ( Ts ) == 2 true ist und /*math-floating-point*/ < T0 > && /*math-floating-point*/ < T1 > true ist,
  • andernfalls std:: common_type_t < /*deduced-simd-t*/ < T0 > , T1 > , falls sizeof... ( Ts ) == 2 true ist und /*math-floating-point*/ < T0 > true ist,
  • andernfalls std:: common_type_t < T0, /*deduced-simd-t*/ < T1 >> , falls sizeof... ( Ts ) == 2 true ist,
  • andernfalls std:: common_type_t < /*math-common-simd-t*/ < T0, T1 > , TRest... > , falls /*math-common-simd-t*/ < T0, T1 > ein gültiger Typ ist,
  • andernfalls std:: common_type_t < /*math-common-simd-t*/ < TRest... > , T0, T1 > .
11) Das Konzept /*reduction-binary-operation*/ ist definiert als:
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 > wird nur dann modelliert, wenn:

  • BinaryOp eine binäre elementweise Operation ist, die kommutativ ist, und
  • Ein Objekt vom Typ BinaryOp mit zwei Argumenten vom Typ std :: datapar :: basic_simd < T, Abi > für einen nicht spezifizierten ABI-Tag Abi aufrufbar ist und einen std :: datapar :: basic_simd < T, Abi > zurückgibt.
SIMD-ABI-Tags
template < class T >
using /*native-abi*/ = /* siehe Beschreibung */ ;
(12) ( Nur zur Darstellung* )
template < class T, /*simd-size-type*/ N >
using /*deduce-abi-t*/ = /* siehe Beschreibung */ ;
(13) ( Nur zur Darstellung* )
12) /*native-abi*/ < T > ist ein implementierungsdefinierter Alias für ein ABI-Tag. Dies ist das primäre ABI-Tag für effiziente explizite Vektorisierung. Folglich ist basic_simd < T, /*native-abi*/ < T >> eine aktivierte Spezialisierung.
13) /*deduce-abi-t*/ < T, N > ist ein Alias, der einen ABI-Tag-Typ bezeichnet, sodass:
  • /*simd-size-v*/ < T, /*deduce-abi-t*/ < T, N >> gleich N ist,
  • std :: datapar :: basic_simd < T, /*deduce-abi-t*/ < T, N >> eine aktivierte Spezialisierung ist, und
  • std :: datapar :: basic_simd_mask < sizeof ( T ) , /*deduce-abi-t*/ < /*integer-from*/ < sizeof ( T ) > , N >> eine aktivierte Spezialisierung ist.
Es ist nur definiert, wenn T ein vektorisierbarer Typ ist und N > 0 && N <= M true ist, wobei M ein implementierungsdefiniertes Maximum ist, das mindestens 64 beträgt und je nach T variieren kann.
Lade- und Speicherflags
struct /*convert-flag*/ ;
(14) ( Nur zur Darstellung* )
struct /*aligned-flag*/ ;
(15) ( Nur zur Darstellung* )
template < std:: size_t N >
struct /*overaligned-flag*/ ;
(16) ( Nur zur Darstellung* )
14-16) Diese Tag-Typen werden als Template-Argument von std::datapar::flags verwendet. Siehe Lade- und Speicher-Flags für ihre entsprechenden Verwendungen.

Hinweise

Feature-Test Makro Wert Std Feature
__cpp_lib_simd 202411L (C++26) Datenparallele Typen und Operationen
__cpp_lib_simd_complex 202502L (C++26) Unterstützung von verschachtelten komplexen Werten in std::datapar::simd

Beispiel

#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));
}

Ausgabe:

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

Siehe auch

Numerische Arrays, Array-Masken und Array-Slices
(Klassen-Template)

Externe Links

1. Die Implementierung von ISO/IEC TS 19570:2018 Abschnitt 9 "Data-Parallel Types" — github.com
2. TS-Implementierung erreichbar für GCC/libstdc++ ( std::experimental::simd wird mit GCC-11 ausgeliefert) — gcc.gnu.org