Data-parallel types (SIMD) (since C++26)
이 라이브러리는 데이터 병렬 타입과 이러한 타입에 대한 연산을 제공합니다: 사용 가능한 경우 데이터 병렬성을 명시적으로 표현하고 데이터 병렬 실행 리소스를 통해 데이터를 구조화하기 위한 이식 가능한 타입으로, SIMD 레지스터 및 명령어나 공통 명령어 디코더에 의해 구동되는 실행 유닛과 같은 리소스를 포함합니다.
벡터화 가능 타입 집합은 다음으로 구성됩니다:
- 모든 표준 정수 및 문자 타입;
- 대부분의 부동소수점 타입 포함: float , double , 그리고 선택된 확장 부동소수점 타입: std:: float16_t , std:: float32_t , 그리고 std:: float64_t (정의된 경우); 그리고
-
std::
complex
<
T
>
여기서
T는 벡터화 가능한 부동소수점 타입입니다.
데이터 병렬 타입 은 요소 타입 이라고 하는 기본 벡터화 가능 타입의 하나 이상의 요소로 구성됩니다. 요소의 개수는 너비 라고 하며, 각 데이터 병렬 타입에 대해 상수입니다.
데이터 병렬 타입은 클래스 템플릿
basic_simd
와
basic_simd_mask
의 모든 활성화된 특수화를 의미합니다.
데이터 병렬 타입의
데이터 병렬 객체
는
T
타입의 객체와 유사하게 동작합니다. 하지만
T
가 단일 값을 저장하고 조작하는 반면,
T
를 요소 타입으로 하는 데이터 병렬 타입은 여러 값을 저장하고 조작합니다.
데이터 병렬 객체의 모든 연산은 객체의 각 요소 또는 두 객체의 해당 요소에 적용되는 요소별(element-wise) 방식으로 작동합니다(감소 연산과 같은 수평 연산은 명시적으로 표시된 경우 제외). 각각의 이러한 적용은 다른 적용과 순서가 지정되지 않습니다. 이 간단한 규칙은 데이터 병렬성을 표현하며 컴파일러가 SIMD 명령어 및/또는 독립적인 실행 스트림을 생성하는 데 사용됩니다.
데이터 병렬 객체에 대한 모든 연산(비- constexpr 수학 함수 오버로드 제외)은 constexpr 입니다: 상수 표현식 평가에서 데이터 병렬 객체를 생성하고 사용하는 것이 가능합니다.
별칭 템플릿
simd
과
simd_mask
는 사용자가 특정 크기로 너비를 지정할 수 있도록 정의됩니다. 기본 너비는 컴파일 시점에 구현에 의해 결정됩니다.
|
헤더에 정의됨
<simd>
|
|
|
네임스페이스에 정의됨
std::datapar
|
목차 |
주요 클래스
|
(C++26)
|
데이터 병렬 벡터 타입
(클래스 템플릿) |
|
(C++26)
|
basic_simd
의 너비를 지정할 수 있는 편의 앨리어스 템플릿
(앨리어스 템플릿) |
|
(C++26)
|
요소 타입이
bool
인 데이터 병렬 타입
(클래스 템플릿) |
|
(C++26)
|
basic_simd_mask
의 너비를 지정할 수 있는 편의 앨리어스 템플릿
(앨리어스 템플릿) |
로드 및 저장 플래그
|
(C++26)
|
데이터 병렬 타입을 위한 로드 및 스토어 플래그
(클래스 템플릿) |
|
(C++26)
|
로드 및 스토어 연산에 사용되는 기본 플래그
(상수) |
|
(C++26)
|
로드 및 스토어 연산에서 값 보존이 아닌 변환을 활성화하는 플래그
(상수) |
|
(C++26)
|
로드-스토어 주소가 특정 저장소에 대해
datapar::alignment
값으로 정렬되었음을 나타내는 플래그
(상수) |
|
(C++26)
|
로드-스토어 주소가 특정 저장소에 대해 지정된 정렬로 정렬되었음을 나타내는 플래그
(변수 템플릿) |
로드 및 스토어 연산
연속 범위의 요소들을
basic_simd
로 로드합니다
(함수 템플릿) |
|
basic_simd
의 요소들을 연속 범위에 저장합니다
(함수 템플릿) |
캐스트
|
(C++26)
|
단일 데이터-병렬 객체를 여러 개로 분할
(함수 템플릿) |
|
(C++26)
|
여러 데이터-병렬 객체를 단일 객체로 연결
(함수 템플릿) |
알고리즘
basic_simd
에 대한 요소별 최소/최대 연산
(함수 템플릿) |
|
|
(C++26)
|
basic_simd
에 대한 요소별 clamp 연산
(함수 템플릿) |
|
(C++26)
|
조건부 연산자를 사용한 요소별 선택
(함수 템플릿) |
리덕션
basic_simd
의 모든 값을 지정된 이항 연산을 통해 단일 값으로 축소
(함수 템플릿) |
|
basic_simd_mask
의
bool
로의 축소
(함수 템플릿) |
|
|
(C++26)
|
basic_simd_mask
의
true
값 개수로의 축소
(함수 템플릿) |
basic_simd_mask
의 첫 번째 또는 마지막
true
값의 인덱스로의 축소
(함수 템플릿) |
Traits
|
(C++26)
|
datapar::flag_aligned
에 적합한 정렬을 획득함
(클래스 템플릿) |
|
(C++26)
|
데이터 병렬 타입의 요소 타입을 변경함
(클래스 템플릿) |
|
(C++26)
|
데이터 병렬 타입의 너비를 변경함
(클래스 템플릿) |
수학 함수
<cmath>
및
<complex>
헤더의 모든 함수들은
basic_simd
에 대해 오버로드됩니다.
|
이 섹션은 불완전합니다
이유: 설명 필요 |
비트 조작 함수
<bit>
헤더의 모든 비트 조작 함수들은
basic_simd
에 대해 오버로드되어 있습니다.
|
이 섹션은 불완전합니다
이유: 설명 필요 |
구현 세부 사항
ABI 태그
데이터 병렬 타입
basic_simd
와
basic_simd_mask
는
ABI 태그
와 연관되어 있습니다. 이러한 태그들은 데이터 병렬 객체의 크기와 이진 표현을 지정하는 타입들입니다. 이 설계는 대상 아키텍처와 컴파일러 플래그에 따라 크기와 이진 표현이 달라지도록 의도되었습니다. ABI 태그는 요소 타입과 함께 너비를 결정합니다.
ABI 태그는 머신 명령어 집합 선택과 독립적으로 유지됩니다. 선택된 머신 명령어 집합은 사용 가능한 ABI 태그 유형을 제한합니다. ABI 태그를 통해 사용자는 데이터 병렬 타입 객체를 번역 단위 경계를 넘어 안전하게 전달할 수 있습니다.
| 이 섹션은 불완전합니다 |
설명 전용 엔티티
|
이 섹션은 불완전합니다
이유: 업데이트 필요 |
|
using
/*simd-size-type*/
=
/* 설명 참조 */
;
|
(1) | ( 설명 전용* ) |
|
template
<
std::
size_t
Bytes
>
using /*integer-from*/ = /* 설명 참조 */ ; |
(2) | ( 설명 전용* ) |
|
template
<
class
T,
class
Abi
>
constexpr /*simd-size-type*/ /*simd-size-v*/ = /* 설명 참조 */ ; |
(3) | ( 설명 전용* ) |
|
template
<
class
T
>
constexpr std:: size_t /*mask-element-size*/ = /* 설명 참조 */ ; |
(4) | ( 설명 전용* ) |
|
template
<
class
T
>
concept /*constexpr-wrapper-like*/ = /* 설명 참조 */ ; |
(5) | ( 설명 전용* ) |
|
template
<
class
T
>
using /*deduced-simd-t*/ = /* 설명 참조 */ ; |
(6) | ( 설명 전용* ) |
|
template
<
class
V,
class
T
>
using /*make-compatible-simd-t*/ = /* 설명 참조 */ ; |
(7) | ( 설명 전용* ) |
T
의 별칭으로,
sizeof
(
T
)
가
Bytes
와 동일한 경우를 의미합니다.
basic_simd<T, Abi>
의 너비를 나타내며, 그렇지 않을 경우
0
을 나타냅니다.
T
가
std
::
datapar
::
basic_simd_mask
<
Bytes, Abi
>
를 나타낸다면,
/*mask-element-size*/
<
T
>
는
Bytes
와 같습니다.
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;
-
decltype
(
x
+
x
)
, 만약
x
+
x
의 타입이
basic_simd의 활성화된 특수화인 경우; 그렇지 않으면 - void .
- /*deduced-simd-t*/ < T > , 해당 타입이 void 가 아닌 경우, 그렇지 않으면
- std :: datapar :: simd < decltype ( x + x ) , V :: size ( ) > .
|
수학 함수 요구사항
|
||
|
template
<
class
V
>
concept /*simd-floating-point*/ = /* see description */ ; |
(8) | ( 설명 전용* ) |
|
template
<
class
...
Ts
>
concept /*math-floating-point*/ = /* see description */ ; |
(9) | ( 설명 전용* ) |
|
template
<
class
...
Ts
>
requires
/*math-floating-point*/
<
Ts...
>
|
(10) | ( 설명 전용* ) |
|
template
<
class
BinaryOp,
class
T
>
concept /*reduction-binary-operation*/ = /* see description */ ; |
(11) | ( 설명 전용* ) |
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>;
template< class... Ts > concept /*math-floating-point*/ = (/*simd-floating-point*/</*deduced-simd-t*/<Ts>> || ...);
T0
가
Ts...
[
0
]
를 나타내고,
T1
이
Ts...
[
1
]
를 나타내며,
TRest
가
T0, T1, TRest...
가
Ts...
와 동등하도록 하는 팩을 나타낸다고 하자. 그러면
/*math-common-simd-t*/
<
Ts...
>
는 다음과 동등한 별칭이다:
- /*deduced-simd-t*/ < T0 > , 단 sizeof... ( Ts ) == 1 가 true 인 경우
- 그렇지 않고, std:: common_type_t < /*deduced-simd-t*/ < T0 > , /*deduced-simd-t*/ < T1 >> , 단 sizeof... ( Ts ) == 2 가 true 이고 /*math-floating-point*/ < T0 > && /*math-floating-point*/ < T1 > 가 true 인 경우
- 그렇지 않고, std:: common_type_t < /*deduced-simd-t*/ < T0 > , T1 > , 단 sizeof... ( Ts ) == 2 가 true 이고 /*math-floating-point*/ < T0 > 가 true 인 경우
- 그렇지 않고, std:: common_type_t < T0, /*deduced-simd-t*/ < T1 >> , 단 sizeof... ( Ts ) == 2 가 true 인 경우
- 그렇지 않고, std:: common_type_t < /*math-common-simd-t*/ < T0, T1 > , TRest... > , 단 /*math-common-simd-t*/ < T0, T1 > 가 유효한 타입인 경우
- 그렇지 않으면, std:: common_type_t < /*math-common-simd-t*/ < TRest... > , T0, T1 > .
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 > 는 다음 조건을 만족할 때만 모델링됩니다:
-
-
BinaryOp는 교환 법칙을 만족하는 이진 요소별 연산이며, -
BinaryOp타입의 객체는 지정되지 않은 ABI 태그Abi에 대해 std :: datapar :: basic_simd < T, Abi > 타입의 두 인수로 호출 가능하며, std :: datapar :: basic_simd < T, Abi > 를 반환합니다.
-
|
SIMD ABI 태그
|
||
|
template
<
class
T
>
using /*native-abi*/ = /* see description */ ; |
(12) | ( 설명 전용* ) |
|
template
<
class
T,
/*simd-size-type*/
N
>
using /*deduce-abi-t*/ = /* see description */ ; |
(13) | ( 설명 전용* ) |
- /*simd-size-v*/ < T, /*deduce-abi-t*/ < T, N >> 가 N 과 동일하고,
- std :: datapar :: basic_simd < T, /*deduce-abi-t*/ < T, N >> 가 활성화된 특수화이며,
- std :: datapar :: basic_simd_mask < sizeof ( T ) , /*deduce-abi-t*/ < /*integer-from*/ < sizeof ( T ) > , N >> 가 활성화된 특수화인 경우.
T
가 벡터화 가능한 타입이고
N
>
0
&&
N
<=
M
가
true
인 경우에만 정의됩니다. 여기서
M
은 최소
64
이상이며
T
에 따라 달라질 수 있는 구현 정의 최댓값입니다.
|
로드 및 저장 플래그
|
||
|
struct
/*convert-flag*/
;
|
(14) | ( 설명 전용* ) |
|
struct
/*aligned-flag*/
;
|
(15) | ( 설명 전용* ) |
|
template
<
std::
size_t
N
>
struct /*overaligned-flag*/ ; |
(16) | ( 설명 전용* ) |
참고 사항
| 기능 테스트 매크로 | 값 | 표준 | 기능 |
|---|---|---|---|
__cpp_lib_simd
|
202411L
|
(C++26) | 데이터 병렬 타입 및 연산 |
__cpp_lib_simd_complex
|
202502L
|
(C++26) |
std::datapar::simd
내 인터리브 복소수 값 지원
|
예제
#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)); }
출력:
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
참고 항목
|
수치 배열, 배열 마스크 및 배열 슬라이스
(클래스 템플릿) |
외부 링크
| 1. | ISO/IEC TS 19570:2018 Section 9 "Data-Parallel Types"의 구현 — github.com |
| 2. |
TS 구현 진행 상황:
GCC/libstdc++
(
std::experimental::simd
는 GCC-11과 함께 배포됨) — gcc.gnu.org
|