最も簡単な答え: 投稿したループの代わりに、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 が割り当てられたメモリのブロックの途中 (先頭ではない) のどこかを指している場合、デクリメントは正常に機能しますが、常にそうであることを確認する方法が必要です (たとえば、メモリが割り当てられているこのトリックを使用する同じ関数で)。