【问题标题】:Extracting SSE shuffled 32 bit value with only SSE2仅使用 SSE2 提取 SSE shuffled 32 位值
【发布时间】:2012-11-08 13:51:15
【问题描述】:

我正在尝试以有效的方式从 128 位寄存器中提取 4 个字节。问题是每个值都在一个单独的 32 位 {120,0,0,0,55,0,0,0,42,0,0,0,120,0,0,0} 中。我想以{120,55,42,120} 的形式将 128 位转换为 32 位。

“原始”代码如下所示:

__m128i byte_result_vec={120,0,0,0,55,0,0,0,42,0,0,0,120,0,0,0};
unsigned char * byte_result_array=(unsigned char*)&byte_result_vec;
result_array[x]=byte_result_array[0];
result_array[x+1]=byte_result_array[4];
result_array[x+2]=byte_result_array[8];
result_array[x+3]=byte_result_array[12];  

我的 SSSE3 代码是:

unsigned int * byte_result_array=...;
__m128i byte_result_vec={120,0,0,0,55,0,0,0,42,0,0,0,120,0,0,0};
const __m128i eight_bit_shuffle_mask=_mm_set_epi8(1,1,1,1,1,1,1,1,1,1,1,1,0,4,8,12);    
byte_result_vec=_mm_shuffle_epi8(byte_result_vec,eight_bit_shuffle_mask);
unsigned int * byte_result_array=(unsigned int*)&byte_result_vec;
result_array[x]=byte_result_array[0];

如何使用 SSE2 有效地做到这一点。 SSSE3 或 SSE4 有更好的版本吗?

【问题讨论】:

    标签: c optimization sse


    【解决方案1】:

    您可以查看a previous answer of mine 以获取对此和反向操作的一些解决方案。

    特别是在 SSE2 中,您可以首先将 32 位整数打包成有符号的 16 位整数并饱和:

    byte_result_vec = _mm_packs_epi32(byte_result_vec, byte_result_vec);
    

    然后我们使用无符号饱和将这些 16 位值打包成无符号 8 位值:

    byte_result_vec = _mm_packus_epi16(byte_result_vec, byte_result_vec);
    

    然后我们终于可以从寄存器的低 32 位获取我们的值了:

    int int_result = _mm_cvtsi128_si32(byte_result_vec);
    unsigned char* byte_result_array = (unsigned char*)&int_result;
    result_array[x]   = byte_result_array[0];
    result_array[x+1] = byte_result_array[1];
    result_array[x+2] = byte_result_array[2];
    result_array[x+3] = byte_result_array[3];
    

    编辑: 以上假设 8 位字最初位于其各自 32 位字的低字节中,其余部分填充 0s,否则它们将得到在饱和包装过程中被夹住。因此操作如下:

                 byte   15                               0
                        0 0 0 D  0 0 0 C  0 0 0 B  0 0 0 A
    
    _mm_packs_epi32 ->  0 D 0 C  0 B 0 A  0 D 0 C  0 B 0 A
    
    _mm_packus_epi16 -> D C B A  D C B A  D C B A  D C B A
                                                   ^^^^^^^
    
    _mm_cvtsi128_si32 -> int DCBA, laid out in x86 memory as bytes A B C D
    
    -> reinterpreted as unsigned char array { A, B, C, D }
    

    如果不感兴趣的字节最初没有用0s 填充,则必须事先将它们屏蔽掉:

    byte_result_vec = _mm_and_si128(byte_result_vec, _mm_set1_epi32(0x000000FF));
    

    或者如果感兴趣的字节最初在高字节中,则必须事先将它们转移到低字节中:

    byte_result_vec = _mm_srli_epi32(byte_result_vec, 24);
    

    或者,如果你真的想要{ D, C, B, A }(我从你的问题中并不完全清楚),那么这相当于只是在分配中切换数组索引(或交替执行 32 位随机播放(@ 987654331@) 事先在初始 SSE 寄存器上)。

    【讨论】:

    • 这是一个完美的答案。我怎样才能两次投票? :) 这对我帮助很大。您是否碰巧知道使用 SSE4 的更好方法?
    • @martins:使用 SSSE3 及更高版本,您只需要一个 PSHUFB(这是您现有代码应该编译成的)。
    • @martins 我对 SSE > 2 不太熟悉,也许我会尝试研究一下。
    猜你喜欢
    • 2012-07-19
    • 2011-08-23
    • 2012-08-25
    • 1970-01-01
    • 2015-05-23
    • 2012-11-25
    • 2010-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多