硬體 SIMD 向量指標和對應類型之間的重新解釋轉換是否是未定義的行為?
在C 中,是否允許重新解釋_轉換浮點數 到__m256 並透過不同的指標存取浮點物件type?
以下程式碼範例說明了這一點:
#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 的內在函數將像 __m256 這樣的向量指標定義為允許為其他任何東西起別名,就像 ISO C 將 char 定義為允許起別名一樣。 (但反之亦然:在實踐中將int* 指向__m256i 並取消引用它是UB 和中斷。)
所以,是的,取消引用__m256 是安全的,而不是使用_mm256_load_ps( ) 內在的對齊負載。但特別是對於 float/double,使用內在函數通常更容易,因為它們也負責從 float 進行轉換。對於整數,AVX512 載入/儲存內在函數被定義為採用void,但AVX2 及更早版本需要像(__m256i)&arr[i] 這樣的強制轉換,這是相當笨重的API 設計,並且使用它的程式碼會變得混亂。
也使用 void 增加了一些非 AVX512 內在函數,例如movd/movq 載入/儲存對齊和別名安全內在函數,例如 _mm_loadu_si32(void)。以前我認為英特爾假設你會使用_mm_cvtsi32_si128 ,它需要自己安全地加載一個int ,這意味著使用memcpy 來避免UB (至少在經典ICC 和MSVC 之外的編譯器上,如果它們允許未對齊的int*並且不強制執行嚴格的
這可能是在英特爾開始考慮遷移到LLVM的時候ICX/ICPX / OneAPI,並意識到處理強制嚴格別名的編譯器上的狹窄負載是多麼混亂。
以上是重新解釋硬體 SIMD 向量指標和對應類型之間的轉換是否是 C 中未定義的行為?的詳細內容。更多資訊請關注PHP中文網其他相關文章!