最简单的答案:不要使用您发布的循环,而是使用 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 指向分配内存块中间(不是开头)的某个位置,那么递减将正常工作,但您必须有一种方法确保始终如此(例如,分配内存在将使用此技巧的同一函数中)。