Data-parallel types (SIMD) (since C++26)
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:
- alle Standard-Ganzzahl- und Zeichentypen;
- die meisten Gleitkommatypen einschließlich float , double , und die ausgewählten erweiterten Gleitkommatypen: std:: float16_t , std:: float32_t , und std:: float64_t falls definiert; und
-
std::
complex
<
T
>
wobei
Tein vektorisierbarer Gleitkommatyp ist.
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
Lade- und Speicherflags
Lade- und Speicheroperationen
Casts
Algorithmen
Reduktionen
Permutationen
Traits
Mathematische Funktionen
Alle Funktionen in
<cmath>
und
<complex>
sind überladen für
BitmanipulationsfunktionenAlle Bitmanipulationsfunktionen in <bit> außer std::bit_cast sind für
ImplementierungsdetailsABI-Tags
Die datenparallelen Typen
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
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:
7)
Sei
x
ein Lvalue vom Typ
const
T
.
/*make-compatible-simd-t*/
<
V, T
>
ist ein Alias, der äquivalent ist zu:
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:
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:
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:
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.
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
Beispiel
Diesen Code ausführen
#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
|