하드웨어 SIMD 벡터 포인터와 해당 유형 간의 재해석 캐스팅이 정의되지 않은 동작인가요?
C에서는 float를 재해석_캐스트하는 것이 허용됩니까? __m256으로 이동하여 액세스 다른 포인터 유형을 통해 객체를 띄우나요?
다음 코드 예제는 이를 보여줍니다.
#include <immintrin.h> constexpr size_t _m256_float_step_sz = sizeof(__m256) / sizeof(float); alignas(__m256) float stack_store[100 * _m256_float_step_sz ]{}; __m256& hwvec1 = *reinterpret_cast<__m256*&>(&stack_store[0 * _m256_float_step_sz]); using arr_t = float[_m256_float_step_sz]; arr_t& arr1 = *reinterpret_cast<float(*)[_m256_float_step_sz]&>(&hwvec1);
hwvec1과 arr1에 정의되지 않은 동작이 있습니까? 엄격한 앨리어싱 규칙([basic.lval]/11)을 위반했습니까? 또는 내장 방식이 하나만 정의되어 있습니까?
__m256 hwvec2 = _mm256_load_ps(&stack_store[0 * _m256_float_step_sz]); _mm256_store_ps(&stack_store[1 * _m256_float_step_sz], hwvec2);
답변:
ISO C는 __m256을 정의하지 않으므로 무엇이 정의되는지 살펴봐야 합니다. 이를 지원하는 구현에 대한 그들의 행동. Intel의 내장 기능은 ISO C에서 char을 별칭으로 정의하는 것과 마찬가지로 __m256과 같은 벡터 포인터를 다른 항목의 별칭으로 허용하도록 정의합니다. (그러나 그 반대는 아닙니다. UB이며 실제로 __m256i에서 int*를 가리키고 참조를 해제하는 것이 중단됩니다.)
그렇습니다. _mm256_load_ps(를 사용하는 대신 __m256을 역참조하는 것이 안전합니다. ) 정렬 부하 고유. 그러나 특히 float/double의 경우 float에서의 캐스팅도 처리하므로 내장 함수를 사용하는 것이 더 쉬운 경우가 많습니다. 정수의 경우 AVX512 로드/저장 내장 함수는 void를 취하는 것으로 정의되지만 AVX2 및 이전 버전에는 (__m256i)&arr[i]와 같은 캐스트가 필요합니다. 이는 꽤 투박한 API 설계이며 이를 사용하여 코드를 복잡하게 만듭니다.
movd/movq와 같은 void를 사용하여 AVX512가 아닌 몇 가지 내장 함수도 추가되었습니다. 로드/저장 정렬 및 _mm_loadu_si32(void)와 같은 앨리어싱 안전 내장 함수. 이전에 Intel은 int를 직접 안전하게 로드해야 하는 _mm_cvtsi32_si128을 사용할 것이라고 가정했습니다. 이는 UB를 피하기 위해 memcpy를 사용하는 것을 의미했습니다(적어도 클래식 ICC 및 MSVC 이외의 컴파일러에서 정렬되지 않은 int*를 허용하고 엄격한 기준을 적용하지 않는 경우). 앨리어싱).
이때가 Intel이 LLVM으로의 마이그레이션을 고려하기 시작한 시기였을 것입니다. ICX/ICPX/OneAPI, 그리고 엄격한 앨리어싱을 시행하는 컴파일러에서 좁은 로드를 처리하는 것이 얼마나 혼란스러운지 깨달았습니다.
위 내용은 하드웨어 SIMD 벡터 포인터와 해당 유형 간의 캐스트를 재해석하는 것이 C에서 정의되지 않은 동작입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!