猿问

AVX 2基于面罩的最有效的打包方法是什么?

AVX 2基于面罩的最有效的打包方法是什么?

如果您有一个输入数组和一个输出数组,但是您只想编写那些通过某种条件的元素,那么在AVX 2中最有效的方法是什么?

我在SSE中见过这样的操作:(来自:https:/ulinenoise.files.wordpress.com/2015/03/gdc 2015_afredriksson_simd.pdf)

__m128i LeftPack_SSSE3(__m128 mask, __m128 val){
 // Move 4 sign bits of mask to 4-bit integer value.
 int mask = _mm_movemask_ps(mask);
 // Select shuffle control data
 __m128i shuf_ctrl = _mm_load_si128(&shufmasks[mask]);
 // Permute to move valid values to front of SIMD register
 __m128i packed = _mm_shuffle_epi8(_mm_castps_si128(val), shuf_ctrl);
 return packed;}

对于4宽的SSE来说,这似乎很好,因此只需要16项LUT,但是对于8宽的AVX,LUT变得相当大(256个条目,每个条目32字节,或8k)。

我感到惊讶的是,AVX似乎没有一个简化这一过程的指示,例如一个带包装的蒙面商店。

我认为,如果对左边设置的符号位#进行一些调整,您可以生成必要的置换表,然后调用mm256_permutevar8x32_ps。但我认为这也是相当多的指示。

有人知道用AVX 2做这件事有什么窍门吗?或者什么是最有效的方法?


谢谢


汪汪一只猫
浏览 802回答 3
3回答

翻翻过去那场雪

如果您的目标是AMD Zen,这个方法可能是首选的,因为非常慢的pdepandpext在ryzen(每个周期18个周期)。我想出了这个方法,它使用一个压缩LUT,它是768(+1填充)字节,而不是8k。它需要一个单一标量值的广播,然后在每个车道上移动一个不同的量,然后隐藏到较低的3位,这提供了一个0-7 LUT。这里是本质版本,以及构建LUT的代码。//Generate&nbsp;Move&nbsp;mask&nbsp;via:&nbsp;_mm256_movemask_ps(_mm256_castsi256_ps(mask));&nbsp;etc__m256i&nbsp;MoveMaskToIndices(u32&nbsp;moveMask)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;*adr&nbsp;=&nbsp;g_pack_left_table_u8x3&nbsp;+&nbsp;moveMask&nbsp;*&nbsp;3; &nbsp;&nbsp;&nbsp;&nbsp;__m256i&nbsp;indices&nbsp;=&nbsp;_mm256_set1_epi32(*reinterpret_cast<u32*>(adr));//lower&nbsp;24&nbsp;bits&nbsp;has&nbsp;our&nbsp;LUT &nbsp;&nbsp;&nbsp;//&nbsp;__m256i&nbsp;m&nbsp;=&nbsp;_mm256_sllv_epi32(indices,&nbsp;_mm256_setr_epi32(29,&nbsp;26,&nbsp;23,&nbsp;20,&nbsp;17,&nbsp;14,&nbsp;11,&nbsp;8)); &nbsp;&nbsp;&nbsp;&nbsp;//now&nbsp;shift&nbsp;it&nbsp;right&nbsp;to&nbsp;get&nbsp;3&nbsp;bits&nbsp;at&nbsp;bottom &nbsp;&nbsp;&nbsp;&nbsp;//__m256i&nbsp;shufmask&nbsp;=&nbsp;_mm256_srli_epi32(m,&nbsp;29); &nbsp;&nbsp;&nbsp;&nbsp;//Simplified&nbsp;version&nbsp;suggested&nbsp;by&nbsp;wim &nbsp;&nbsp;&nbsp;&nbsp;//shift&nbsp;each&nbsp;lane&nbsp;so&nbsp;desired&nbsp;3&nbsp;bits&nbsp;are&nbsp;a&nbsp;bottom &nbsp;&nbsp;&nbsp;&nbsp;//There&nbsp;is&nbsp;leftover&nbsp;data&nbsp;in&nbsp;the&nbsp;lane,&nbsp;but&nbsp;_mm256_permutevar8x32_ps&nbsp;&nbsp;only&nbsp;examines&nbsp;the&nbsp;first&nbsp;3&nbsp;bits&nbsp;so&nbsp;this&nbsp;is&nbsp;ok &nbsp;&nbsp;&nbsp;&nbsp;__m256i&nbsp;shufmask&nbsp;=&nbsp;_mm256_srlv_epi32&nbsp;(indices,&nbsp;_mm256_setr_epi32(0,&nbsp;3,&nbsp;6,&nbsp;9,&nbsp;12,&nbsp;15,&nbsp;18,&nbsp;21)); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;shufmask;}u32&nbsp;get_nth_bits(int&nbsp;a)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;u32&nbsp;out&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;c&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;<&nbsp;8;&nbsp;++i)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;auto&nbsp;set&nbsp;=&nbsp;(a&nbsp;>>&nbsp;i)&nbsp;&&nbsp;1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(set)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out&nbsp;|=&nbsp;(i&nbsp;<<&nbsp;(c&nbsp;*&nbsp;3)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c++; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;out;}u8&nbsp;g_pack_left_table_u8x3[256&nbsp;*&nbsp;3&nbsp;+&nbsp;1];void&nbsp;BuildPackMask()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;<&nbsp;256;&nbsp;++i)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*reinterpret_cast<u32*>(&g_pack_left_table_u8x3[i&nbsp;*&nbsp;3])&nbsp;=&nbsp;get_nth_bits(i); &nbsp;&nbsp;&nbsp;&nbsp;}}下面是MSVC生成的程序集:&nbsp;&nbsp;lea&nbsp;ecx,&nbsp;DWORD&nbsp;PTR&nbsp;[rcx+rcx*2] &nbsp;&nbsp;lea&nbsp;rax,&nbsp;OFFSET&nbsp;FLAT:unsigned&nbsp;char&nbsp;*&nbsp;g_pack_left_table_u8x3&nbsp;;&nbsp;g_pack_left_table_u8x3 &nbsp;&nbsp;vpbroadcastd&nbsp;ymm0,&nbsp;DWORD&nbsp;PTR&nbsp;[rcx+rax] &nbsp;&nbsp;vpsrlvd&nbsp;ymm0,&nbsp;ymm0,&nbsp;YMMWORD&nbsp;PTR&nbsp;__ymm@00000015000000120000000f0000000c00000009000000060000000300000000
随时随地看视频慕课网APP
我要回答