Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 寻找非立即移位值的sse 128位移位操作_C++_C_Sse - Fatal编程技术网

C++ 寻找非立即移位值的sse 128位移位操作

C++ 寻找非立即移位值的sse 128位移位操作,c++,c,sse,C++,C,Sse,内部\u mm\u slli\u si128将对128位寄存器进行逻辑左移位,但仅限于立即移位值,并按字节而不是位移位 我可以使用像\u mm\u sll\u epi64或\u mm\u sll\u epi32这样的内在函数将\u m128i寄存器中的一组值向左移位,但这些值不携带“溢出”位 对于N位的移位,想象一下我可以做如下操作: \u mm\u sll\u epi64 \u mm\u srr\u epi64(对于我要携带的位:将它们移到低位) 洗牌srr结果 或者把这些放在一起 (但可

内部
\u mm\u slli\u si128
将对128位寄存器进行逻辑左移位,但仅限于立即移位值,并按字节而不是位移位

我可以使用像
\u mm\u sll\u epi64
\u mm\u sll\u epi32
这样的内在函数将
\u m128i
寄存器中的一组值向左移位,但这些值不携带“溢出”位

对于N位的移位,想象一下我可以做如下操作:

  • \u mm\u sll\u epi64
  • \u mm\u srr\u epi64
    (对于我要携带的位:将它们移到低位)
  • 洗牌srr结果
  • 或者把这些放在一起
(但可能还必须包括N相对于64的检查)


有更好的方法吗?

不是理想的解决方案,但是如果您想将SSE寄存器旋转或移位8的倍数,那么
PSHUFB
指令(以及
\u mm\u shuffle\u epi8()
内在指令)可以提供帮助。它将第二个SSE寄存器作为输入;寄存器中的每个字节都有一个值,用于索引第一个输入寄存器中的字节。

这是我在上一篇博文中提到的一个次要问题。 对于127个不同的移位偏移,有四个不同的SSE2指令的最优序列用于位移位。预处理器可以合理地构造一个相当于129路switch语句的移位函数。请原谅这里的原始代码;我不熟悉直接在这里发布代码。 查看博客文章,了解发生了什么

#include <emmintrin.h>

typedef __m128i XMM;
#define xmbshl(x,n)  _mm_slli_si128(x,n) // xm <<= 8*n  -- BYTE shift left
#define xmbshr(x,n)  _mm_srli_si128(x,n) // xm >>= 8*n  -- BYTE shift right
#define xmshl64(x,n) _mm_slli_epi64(x,n) // xm.hi <<= n, xm.lo <<= n
#define xmshr64(x,n) _mm_srli_epi64(x,n) // xm.hi >>= n, xm.lo >>= n
#define xmand(a,b)   _mm_and_si128(a,b)
#define xmor(a,b)    _mm_or_si128(a,b)
#define xmxor(a,b)   _mm_xor_si128(a,b)
#define xmzero       _mm_setzero_si128()

XMM xm_shl(XMM x, unsigned nbits)
{
    // These macros generate (1,2,5,6) SSE2 instructions, respectively:
    #define F1(n) case 8*(n): x = xmbshl(x, n); break;
    #define F2(n) case n: x = xmshl64(xmbshl(x, (n)>>3), (n)&15); break;
    #define F5(n) case n: x = xmor(xmshl64(x, n), xmshr64(xmbshl(x, 8), 64-(n))); break;
    #define F6(n) case n: x = xmor(xmshl64(xmbshl(x, (n)>>3), (n)&15),\
                                  xmshr64(xmbshl(x, 8+((n)>>3)), 64-((n)&155))); break;
    // These macros expand to 7 or 49 cases each:
    #define DO_7(f,x) f((x)+1) f((x)+2) f((x)+3) f((x)+4) f((x)+5) f((x)+6) f((x)+7)
    #define DO_7x7(f,y) DO_7(f,(y)+1*8) DO_7(f,(y)+2*8) DO_7(f,(y)+3*8) DO_7(f,(y)+4*8) \
                                        DO_7(f,(y)+5*8) DO_7(f,(y)+6*8) DO_7(f,(y)+7*8)
    switch (nbits) {
    case 0: break;
    DO_7(F5, 0) // 1..7
    DO_7(F1, 0) // 8,16,..56
    DO_7(F1, 7) // 64,72,..120
    DO_7x7(F6, 0) // 9..15 17..23 ... 57..63 i.e. [9..63]\[16,24,..,56]
    DO_7x7(F2,56) // 65..71 73..79 ... 121..127 i.e. [65..127]\[64,72,..,120]
    default: x = xmzero;
    }
    return x;
}
#包括
类型定义uu m128i XMM;
#定义xmbshl(x,n)\u mm\u slli\u si128(x,n)//xm=8*n——字节右移
#定义xmshl64(x,n)\u mm\u slli\u epi64(x,n)//xm.hi=n
#定义xmand(a,b)_mm_和_si128(a,b)
#定义xmor(a,b)_mm_或_si128(a,b)
#定义xmxor(a,b)\u mm\u xor\u si128(a,b)
#定义xmzero\u mm\u setzero\u si128()
XMM xm_shl(XMM x,无符号NBIT)
{
//这些宏分别生成(1,2,5,6)SSE2指令:
#定义F1(n)情况8*(n):x=xmbshl(x,n);中断;
#定义F2(n)情况n:x=xmshl64(xmbshl(x,(n)>>3,(n)&15);中断;
#定义F5(n)情况n:x=xmor(xmshl64(x,n),xmshr64(xmbshl(x,8),64-(n));break;
#定义F6(n)情况n:x=xmor(xmshl64(xmbshl(x,(n)>>3)、(n)&15)\
xmshr64(xmbshl(x,8+((n)>>3)),64-((n)和155));断裂;
//这些宏扩展到每个7或49个案例:
#定义DO_7(f,x)f((x)+1)f((x)+2)f((x)+3)f((x)+4)f((x)+5)f((x)+6)f((x)+7)
#定义DO_7x7(f,y)DO_7(f,(y)+1*8 DO_7(f,(y)+2*8 DO_7(f,(y)+3*8 DO_7(f,(y)+4*8)\
DO_7(f,(y)+5*8)DO_7(f,(y)+6*8)DO_7(f,(y)+7*8)
开关(nbits){
案例0:断裂;
DO_7(F5,0)//1..7
DO_7(F1,0)//8,16,…56
DO_7(F1,7)//64,72,…120
DO_7x7(F6,0)//9..15 17..23..57..63即[9..63]\[16,24,…,56]
DO_7x7(F2,56)//65..71 73..79..121..127即[65..127]\[64,72,…,120]
默认值:x=xmzero;
}
返回x;
}

xm_shr相当于上述内容,但在F[1256]宏中到处交换“shl”和“shr”。HTH.

我认为OP明确表示,他需要比特粒度,而不限于即时
\u mm\u shuffle\u epi8()
是字节粒度,需要立即数。我知道他想要位粒度,因此我的答案中的第一个子句。而且,
\u mm\u shuffle\u epi8()
不需要立即执行;第二个参数是一个
\uuu m128i
值。我应该注意,此函数需要SSSE3支持,如果您想在旧机器上运行,这可能不够。@Mysticial:Jason是对的,
pshufb
具有16个预先计算的值,可用于模拟变量的字节移位。在这种情况下,可以使用它进行qword移位(当然是0或1Qword;-),剩余的64位移位可以按照OP的建议进行。实际上,上面的代码对大约一半的移位值不起作用。我对128位整数(gcc支持128位整数)进行了标准移位测试,结果明显不同。例如,120以上的所有移位只需将所有位归零。对于编译时常量移位计数,您永远不需要超过4条指令(或5条没有AVX的指令:额外的
movdqa
)。对于计数<64,字节左移64b,然后位右移64计数
psllq xmm0,64的进位。我用一个
if
编写了它,它很好地编译了一个编译时常量计数:。请参阅以修复代码,只需将每个&15或&155表达式替换为&7即可。这就是说,这段代码非常慢(你知道分支吗?!),而且Peter Cordes的建议看起来更有希望。:-)这段代码源于一个例子,它扩展了c预处理器在模板类代码中的使用,只使用了一个开关。感谢您深入阅读。不久前,我发现使用带有可变移位计数的直接int64更快。但是我会修改示例代码。我认为没有更好的方法。我写了一个关于这个问题的最新副本的答案:。对于编译时常量计数,它将变成4个INSN,或计数>=64的2个INSN。使用变量count,它从整数到向量寄存器进行分支,并必须
movd
计数和64计数<如果数据已经在整数寄存器中,则代码>\uuuu uint128\u t
在这种情况下效果更好。