在子字节上使用SSE进行位操作?

时间:2011-07-12 20:04:00

标签: assembly bit-manipulation sse

是否可以使用SSE对非字节对齐的数据进行位操作?例如,我想使用SSE实现这一点:

const char buf[8];
assert(n <= 8);
long rv = 0;
for (int i = 0; i < n; i++)
    rv = (rv << 6) | (buf[i] & 0x3f);

相反,我想将buf加载到xmm寄存器中并使用SSE指令来避免循环。不幸的是,移位操作(例如PSLLW)将每个打包整数移位相同的量,所以我不能在这里使用它。使用乘法(PMULLW)模拟移位似乎也不正确......

查看SSE文档,似乎通常不支持位操作。这是真的?或者使用SSE有很好的位操作示例吗?

2 个答案:

答案 0 :(得分:4)

我不确定SSE指令是否有助于减少实现代码执行所需的操作数量;如果有人知道,我也很好奇。让我们稍微分解一下代码。

代码是递归移位/或序列,意味着你取最低6位,将它们向左移6位,或接下来6位,再移位,依此类推。

因此,您将8位值的数组转换为6位值的打包数组,将数据从64位缩小到48位。像:

|76543210|76543210|76543210|76543210|76543210|76543210|76543210|76543210|
|-----------------|54321054|32105432|10543210|54321054|32105432|10543210|

因此,你可以解开循环并按如下方式编写它:

/*
 * (buf[x] << 58)
 *   moves lowest six bits of a 64bit long into the highest bits, clears others
 *
 * >> (6 * x + 16)
 *   shifts the bits into the expected final position
 */
#define L(x) (((long)buf[x] << 58) >> (6 * x + 16))

long rv = L(0) | L(1) | L(2) | L(3) | L(4) | L(5) | L(6) | L(7);

如上所述,我不知道SSE指令有助于这种打包(SSE包做四对一,字到短,短到字节)。

您可以在SSE寄存器中执行操作,但是根据我的意见,不能减少获得最终结果所需的指令数。

答案 1 :(得分:0)

您可以在SSE中执行相当多的按位操作。你可以使用_mm_and_si128,_mm_or_si128并且有一大堆移位操作。 Google _mm_slli_si128查找完整列表。这些说明已添加到SSE2中,因此它们可以广泛使用。