SSE加载邻接值

SSE Load Neighboring Values

本文关键字:加载 SSE      更新时间:2023-10-16

在处理2D数组时,一个常见的事情是加载一组值,然后将它们向左或向右移动,然后再加载一个不再需要的值。最好的方法是什么?

float arr[128][128];
for(int i = 1;i < 127;++i)
for(int j = 1;j < 127;++j)
{
 __m128 top = _mm_load_ps(arr[i - 1][j]);
 __m128 center = _mm_load_ps(arr[i][j]);
 //...stuff
 //rotate the top
 top = _mm_shuffle_ps(top,top,_MM_SHUFFLE(0,3,2,1));
 //how do i load another item in without insert?

如果你正在谈论对2D数据进行邻域操作,那么为了获得向左或向右移动一定数量的向量,你可以使用未对齐的加载,或者如果你可以假设SSSE3或更高版本,则使用_mm_alignr_epi8。通常情况下,您只会在带有SSE3或以下版本的旧cpu上使用unaligned load方法,在没有其他选择的情况下。

对左/右移动1个float元素的向量进行操作的示例:

对齐加载:

for (int j = 0; j < 128; j += 4)
{
    vl = _mm_loadu_ps(&a[i][j-1]);       // left shifted vector
    vm = _mm_load_ps(&a[i][j]);          // middle vector
    vr = _mm_loadu_ps(&a[i][j+1]);       // right shifted vector
}

_mm_alignr_epi8:

va = _mm_setzero_ps();
vb = _mm_load_ps(&a[i][0]); 
for (int j = 0; j < 128; j += 4)
{
    vc = _mm_load_ps(&a[i][j+4]); 
    vl = _mm_alignr_epi8(va, vb, sizeof(float));       // left shifted vector
                                                       // middle vector = vb
    vr = _mm_alignr_epi8(vb, vc, 3 * sizeof(float));   // right shifted vector
    va = vb;                                           // shuffle source vectors left by one
    vb = vc;
}

请注意,当你执行大量的邻域操作,有大量不同的移位时,有时更有效的方法是临时转置整个数据块,这样你就可以使用行索引,而不是像上面那样做水平向量操作。