SSE 内在函数向右移位

Posted

技术标签:

【中文标题】SSE 内在函数向右移位【英文标题】:SSE intrinsics bit shifting to the right 【发布时间】:2014-12-01 01:26:34 【问题描述】:

我正在尝试使用内在函数将整数向右移位。下面的代码试图做到这一点,但输出看起来不像预期的那样,也许我错误地加载了数字或使用了错误的内在函数。这是输出:

 2 4 8 16 32 64 128 1 2 4 8 16 32 64 128 0
 512 1024 2048 4096 8192 16384 32768 0
 0 8192 0 16384
 8 0 16 0

我确实尝试查看此thread,但甚至没有尝试使用bitshift instructions with SSE intrinsics。

这是完整的代码(使用 SSE2 标志编译)。

#include <emmintrin.h>
#include <stdio.h>
#include <stdint.h>

void print_16_num(__m128i var)

    uint8_t *val = (uint8_t*) &var;
    printf(" %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i \n",
           val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7],val[8], val[9], val[10], val[11], val[12], val[13], val[14], val[15]);

void print_8_num( __m128i var)

    uint16_t *val = (uint16_t*) &var;
    printf(" %i %i %i %i %i %i %i %i \n",
           val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);

void print_4_num( __m128i var)

    uint16_t *val = (uint16_t*) &var;
    printf(" %i %i %i %i \n",
           val[0], val[1], val[2], val[3]);

int main()

    __m128i _16 = _mm_set_epi8( 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1);
    print_16_num(_mm_srli_si128(_16,1));

   __m128i _8 = _mm_set_epi16( 128, 64, 32, 16, 8, 4, 2, 1);
    print_8_num( _mm_srli_si128(_8,1));

    __m128i _4 = _mm_set_epi32( 128, 64, 32, 16);
    print_4_num( _mm_srli_si128(_4,1));

    _4 = _mm_set_epi32( 128, 64, 32, 16);
    print_4_num( _mm_srli_epi32(_4,1));

    return 0;

【问题讨论】:

根据您引用的文档,_mm_srli_si128shifts by bytes, not bits。 @RaymondChen 哦,难怪它不起作用。所以我猜链接(到另一个***问题)是按位移动的唯一方法? afaik 仅移动 128 位值按字节移动,使用 64、32、16 位。我猜设计师质疑你会转移如此大的价值的业务 【参考方案1】:

当您使用 _mm_set_epi* 函数时,它们首先接受其参数作为最重要的项目。

例如第一条语句,

__m128i _16 = _mm_set_epi8( 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1);

将使用此值加载变量:

0x80402010080402018040201008040201
 (128,64,32 ...)

然后你用_mm_srli_si128(_16,1)将该128位值右移1个字节,你得到

0x00804020100804020180402010080402

当您读取单个字节值时,byte[0] 是最低有效字节,也就是最右边的字节。 (所以它打印 02 04 08 等...)

其他语句也是如此,尽管我认为您想在 print_4_num 函数中转换为 uint32_t* 而不是 uint16_t*

对于最后一个,_mm_srli_epi32(_4,1) 会移动值

0x00000080000000400000002000000010
       (128)   (64)    (32)    (16)

点一下就变成了

0x00000040000000200000001000000008

但它会打印“8 0 16 0”,因为您在 print_4_num 函数中读取的是 16 位值而不是 32 位值:

0x0000 0040 0000 0020 0000 0010 0000 0008
     (not used)        [3]  [2]  [1]  [0]

要查看哪些函数的作用是什么,请查看英特尔内部指南:

https://software.intel.com/sites/landingpage/IntrinsicsGuide/

【讨论】:

我只需要重铸 print_4_num 并且工作正常,反正我只需要 32 位。谢谢。

以上是关于SSE 内在函数向右移位的主要内容,如果未能解决你的问题,请参考以下文章

SSE 内在函数优化

数组乘法与 sse 内在函数乘法的时序?

用 sse 执行内在函数

SSE 内在函数检查零标志

内在函数和寄存器(SSE)

修改函数以使用 SSE 内在函数