簡體   English   中英

使用AVX2將8位從32位值(__m256i)解壓縮到__m256的最快方法

[英]Fastest way to unpack 8bit from 32bit values (__m256i) into __m256 with AVX2

我有一個名為Aarray ,它包含32個unsigned char值。

我想用這個規則在4個__m256變量中解壓縮這些值,假設我們有一個關於A所有值的從0到31的索引,unpacked 4變量將具有以下值:

B_0 = A[0], A[4],  A[8], A[12], A[16], A[20], A[24], A[28]
B_1 = A[1], A[5],  A[9], A[13], A[17], A[21], A[25], A[29]
B_2 = A[2], A[6], A[10], A[14], A[18], A[22], A[26], A[30]
B_3 = A[3], A[7], A[11], A[15], A[19], A[23], A[27], A[31]

為此,我有這個代碼:

const auto mask = _mm256_set1_epi32( 0x000000FF );
...
const auto A_values = _mm256_i32gather_epi32(reinterpret_cast<const int*>(A.data(), A_positions.values_, 4);

// This code bellow is equivalent to B_0 = static_cast<float>((A_value >> 24) & 0x000000FF)
const auto B_0 = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srai_epi32(A_values, 24), mask));
const auto B_1 = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srai_epi32(A_values, 16), mask));
const auto B_2 = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srai_epi32(A_values, 8), mask));
const auto B_3 = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srai_epi32(A_values, 0), mask));

這很好用,但我想知道是否有更快的方法來做到這一點,特別是關於右移和我用來檢索值的運算符。

另外,為了澄清,我說array A的大小為32,但事實並非如此,這個數組包含更多的值,我需要從不同的位置訪問它的元素(但總是來自4 uint8_t塊)這就是為什么我使用_mm256_i32gather_epi23檢索這些值。 為簡單起見,我只是在這個例子中限制了array大小。

shift / mask可以組合在一個vpshufb 當然這意味着需要擔心洗牌,這必須來自某個地方。 如果他們可以留在寄存器中,那就沒什么大不了的,如果他們必須加載可能會殺死這種技術。

這似乎是對英特爾的優化可疑,因為此次轉換的recip.throughput為0.5和AND 0.33,這比你通過shuffle得到的1更好(帶有兩個shuffle單元的Intel處理器不支持AVX2所以他們不相關,所以洗牌轉到P5)。 它的μops仍然較少,因此在其他代碼的上下文中,它可能值得也可能不值得做,這取決於瓶頸是什么。 如果其余代碼只使用P01(典型的FP SIMD),將μops移動到P5可能是一個好主意。

在Ryzen上通常更好,因為矢量移位在那里具有低吞吐量。 256b vpsrad產生2μs,兩者都必須轉到端口2(然后還有兩個μop用於vpand ,但它們可以轉到四個alu端口中的任何一個),256b vpshufb生成2μs可以轉到端口1和2另一方面,在Ryzen上聚集是如此糟糕,以至於這只是噪音,而不是來自那里的大量μops。 你可以手動收集,但它仍然是很多μops,他們可能會去P12,這使得這種技術很糟糕。

總而言之,我無法告訴你這是否真的更快,取決於它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM