我发现的 SSE 移位指令只能在所有元素上移位相同的量:
_mm_sll_epi32()
_mm_slli_epi32()
有没有办法对不同的元素应用不同的转变?像这样的东西:
__m128i a, __m128i b;
r0:= a0 << b0;
r1:= a1 << b1;
r2:= a2 << b2;
r3:= a3 << b3;
我发现的 SSE 移位指令只能在所有元素上移位相同的量:
_mm_sll_epi32()
_mm_slli_epi32()
有没有办法对不同的元素应用不同的转变?像这样的东西:
__m128i a, __m128i b;
r0:= a0 << b0;
r1:= a1 << b1;
r2:= a2 << b2;
r3:= a3 << b3;
存在_mm_shl_epi32()
确实做到这一点的内在因素。
http://msdn.microsoft.com/en-us/library/gg445138.aspx
但是,它需要XOP 指令集。只有 AMD Bulldozer 和 Interlagos 处理器或更高版本有此指令。它不适用于任何英特尔处理器。
如果您想在没有 XOP 指令的情况下执行此操作,则需要以艰难的方式进行操作:将它们拉出来并一个接一个地执行。
如果没有 XOP 指令,您可以使用以下内在函数对 SSE4.1 执行此操作:
_mm_insert_epi32()
_mm_extract_epi32()
这些将允许您将 128 位寄存器的一部分提取到常规寄存器中以进行移位并将它们放回原处。
如果你采用后一种方法,它的效率会非常低。这就是为什么_mm_shl_epi32()
首先存在的原因。
如果没有 XOP,您的选择就会受到限制。如果您可以控制移位计数参数的格式,则可以使用,_mm_mullo_pi16
因为乘以 2 的幂与乘以该幂的移位相同。
例如,如果您想将 SSE 寄存器中的 8 个 16 位元素移位,<0, 1, 2, 3, 4, 5, 6, 7>
您可以乘以 2 的移位计数幂,即<0, 2, 4, 8, 16, 32, 64, 128>
。
在某些情况下,这可以替代_mm_shl_epi32(a, b)
:
_mm_mullo_ps(a, 1 << b);
一般来说,这需要b
有一个常数值——我不知道(1 << b)
使用旧 SSE 指令计算的有效方法。