0

我正在使用 SSE3 优化我的代码。代码中有一点迫使我将向量中的所有元素移动一个元素

v[0] = 0   //v is some char* and N = v.size()
for(int i = 1;i<N;i++){
    v[i] = v[i-1];
}

据我所知,SSE 不支持向量移位,所以我必须从头开始编写这个代码。

但后来我有了想法,如果我只是减少指针怎么办。

v = (v-1); 
v[0] = 0;

这样,操作将是恒定的,根本不需要任何操作。

我已经对此进行了测试,它适用于我的测试程序。
但是,我不确定此操作是否安全。

这是一个非常愚蠢的想法吗?

4

3 回答 3

4

SSE确实支持移位,向量内元素的按位移位和整个寄存器沿字节边界的移位。

假设您的向量是 16 次类型uint8_t,您正在寻找的操作是

psrldq xmm, 1      ;packed shift right logical double quad word

与内在

vec = _mm_srli_si128(vec, 1);   // shift by 1 byte

对于您的第一个问题:只要v是指向 char 的指针,递减或递增它是完全安全的。取消引用可能不会,这取决于您的程序。

对于你的第二个问题:是的,这看起来是个愚蠢的想法。如果您尝试优化SSE并使用指向字节的指针执行一些任务,那么您很可能做错了什么,并且如果您尝试将 16 个字节加载vSSE寄存器中,您就会遇到麻烦 - 由于未对齐或性能损失导致的段错误因为强制编译器使用movdqu.

于 2012-11-16T08:23:20.187 回答
2

最简单的答案:不要使用您发布的循环,而是使用 memmove(v+1, v, N-1)。这很可能在任何体面的系统上运行得与手动编码组装一样快,因为它手动编码组装,使用 movdqu/movdqa/movntdqa 和循环展开的适当组合。

更复杂的答案:我认为,从大局来看,您实际上不太可能需要转移数据。更有可能的是,您可能需要访问相邻元素和当前元素,例如对 v[i] 和 v[i-1] 进行某种计算。

如果您使用 SIMD 代码来执行此操作,则标准技术是(例如)将字节 0..15 加载到 xmm0 中,将 16..31 加载到 xmm1 中,然后将两个寄存器打乱以最终得到元素 1..16 xmm2。然后你可以用xmm0(这里对应向量化的v[i-1])和xmm2(向量化的v[i])进行计算。这不是逻辑/算术移位意义上的“移位”,而是 SIMD 车道移位。

示例:在汇编中使用字节

movdqa mem, xmm0 // load bytes 0..15
loop:
// increment mem by 16
movdqa mem, xmm1 // load bytes 16..31
movdqa xmm0, xmm2 // make a copy
movdqa xmm1, xmm3 // make a copy
psrldq xmm2, 1 // ends up with bytes 1..15 and a zero
pslldq xmm3, 15 // ends up with zeros and byte 16
por xmm2, xmm3 // ends up with bytes 1..16
// do something with xmm3 and xmm0 here, they contain bytes 1..16 and 0..15 respectively
// in other words xmm3 is a lane-shifted
movdqa xmm1, xmm0 // use our copy of bytes 16..31 to continue the loop
// goto loop

为什么不这样做:“如果我只是递减指针... v = (v-1);”

这将崩溃:

char* v = (char*)malloc(...);
v=(v-1);
v[0] = 0; // or any read or write of v[0]

如果 v 指向分配内存块中间(不是开头)的某个位置,那么递减将正常工作,但您必须有一种方法确保始终如此(例如,分配内存在将使用此技巧的同一函数中)。

于 2012-11-16T09:41:50.940 回答
0

递减指针首先会导致对第 0 个元素的越界访问,并且会使您的向量错位。向量操作,除了要正确对齐以提高性能的数据。如果数据未对齐,则指令调度程序必须将从内存中读取分成两次读取,从而失去一些性能。

SSE 提供对整个向量的位移操作,请参阅@hirschhornsalz 的答案。

于 2012-11-16T10:18:00.240 回答