为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C++
汪汪一只猫 2019-07-11 10:25:35
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做这件事有什么窍门吗?或者什么是最有效的方法?谢谢
查看完整描述

3 回答

?
翻翻过去那场雪

TA贡献2065条经验 获得超14个赞

如果您的目标是AMD Zen,这个方法可能是首选的,因为非常慢的pdepandpext在ryzen(每个周期18个周期)。

我想出了这个方法,它使用一个压缩LUT,它是768(+1填充)字节,而不是8k。它需要一个单一标量值的广播,然后在每个车道上移动一个不同的量,然后隐藏到较低的3位,这提供了一个0-7 LUT。

这里是本质版本,以及构建LUT的代码。

//Generate Move mask via: _mm256_movemask_ps(_mm256_castsi256_ps(mask)); etc__m256i MoveMaskToIndices(u32 moveMask) {
    u8 *adr = g_pack_left_table_u8x3 + moveMask * 3;
    __m256i indices = _mm256_set1_epi32(*reinterpret_cast<u32*>(adr));//lower 24 bits has our LUT

   // __m256i m = _mm256_sllv_epi32(indices, _mm256_setr_epi32(29, 26, 23, 20, 17, 14, 11, 8));

    //now shift it right to get 3 bits at bottom
    //__m256i shufmask = _mm256_srli_epi32(m, 29);

    //Simplified version suggested by wim
    //shift each lane so desired 3 bits are a bottom
    //There is leftover data in the lane, but _mm256_permutevar8x32_ps  only examines the first 3 bits so this is ok
    __m256i shufmask = _mm256_srlv_epi32 (indices, _mm256_setr_epi32(0, 3, 6, 9, 12, 15, 18, 21));
    return shufmask;}u32 get_nth_bits(int a) {
    u32 out = 0;
    int c = 0;
    for (int i = 0; i < 8; ++i) {
        auto set = (a >> i) & 1;
        if (set) {
            out |= (i << (c * 3));
            c++;
        }
    }
    return out;}u8 g_pack_left_table_u8x3[256 * 3 + 1];void BuildPackMask() {
    for (int i = 0; i < 256; ++i) {
        *reinterpret_cast<u32*>(&g_pack_left_table_u8x3[i * 3]) = get_nth_bits(i);
    }}

下面是MSVC生成的程序集:

  lea ecx, DWORD PTR [rcx+rcx*2]
  lea rax, OFFSET FLAT:unsigned char * g_pack_left_table_u8x3 ; g_pack_left_table_u8x3
  vpbroadcastd ymm0, DWORD PTR [rcx+rax]
  vpsrlvd ymm0, ymm0, YMMWORD PTR __ymm@00000015000000120000000f0000000c00000009000000060000000300000000



查看完整回答
反对 回复 2019-07-11
  • 3 回答
  • 0 关注
  • 801 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信