由于不正确的内存对齐,在使用SSE内在函数时出现分段错误

前端之家收集整理的这篇文章主要介绍了由于不正确的内存对齐,在使用SSE内在函数时出现分段错误前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我第一次使用SSE内在函数,即使在确保16byte内存对齐后,我也遇到了分段错误.这篇文章是我之前问题的扩展:

How to allocate 16byte memory aligned data

这是我声明我的数组的方式:

float *V = (float*) memalign(16,dx*sizeof(float));

当我尝试这样做时:

__m128 v_i = _mm_load_ps(&V[i]); //It works

但是当我这样做时:

__m128 u1 = _mm_load_ps(&V[(i-1)]); //There is a segmentation fault

但如果我这样做:

__m128 u1 = _mm_loadu_ps(&V[(i-1)]); //It works again

但是我想消除使用_mm_loadu_ps并希望仅使用_mm_load_ps使其工作.

我正在使用Intel icc编译器.

我该如何解决这个问题?

更新:

使用以下代码中的两个操作:

void FDTD_base (float *V,float *U,int dx,float c0,float c1,float c2,float c3,float c4)
    {
       int i,j,k;
                    for (i = 4; i < dx-4; i++)
                    {

                            U[i] = (c0 * (V[i]) //center
                                    + c1 * (V[(i-1)] + V[(i+1)] )
                                    + c2 * (V[(i-2)] + V[(i+2)] )
                                    + c3 * (V[(i-3)] + V[(i+3)] )
                                    + c4 * (V[(i-4)] + V[(i+4)] ));
                    }

       }

SSE版本:

for (i=4; i < dx-4; i+=4)
        {
            v_i = _mm_load_ps(&V[i]);
            __m128 center = _mm_mul_ps(v_i,c0_i);

            __m128 u1 = _mm_loadu_ps(&V[(i-1)]);
            u2 = _mm_loadu_ps(&V[(i+1)]);

            u3 = _mm_loadu_ps(&V[(i-2)]);
            u4 = _mm_loadu_ps(&V[(i+2)]);

            u5 = _mm_loadu_ps(&V[(i-3)]);
            u6 = _mm_loadu_ps(&V[(i+3)]);

            u7 = _mm_load_ps(&V[(i-4)]);
            u8 = _mm_load_ps(&V[(i+4)]);

            __m128 tmp1 = _mm_add_ps(u1,u2);
            __m128 tmp2 = _mm_add_ps(u3,u4);
            __m128 tmp3 = _mm_add_ps(u5,u6);
            __m128 tmp4 = _mm_add_ps(u7,u8);

            __m128 tmp5 = _mm_mul_ps(tmp1,c1_i);
            __m128 tmp6 = _mm_mul_ps(tmp2,c2_i);
            __m128 tmp7 = _mm_mul_ps(tmp3,c3_i);
            __m128 tmp8 = _mm_mul_ps(tmp4,c4_i);

            __m128 tmp9 = _mm_add_ps(tmp5,tmp6);
            __m128 tmp10 = _mm_add_ps(tmp7,tmp8);

            __m128 tmp11 = _mm_add_ps(tmp9,tmp10);
            __m128 tmp12 = _mm_add_ps(center,tmp11);

            _mm_store_ps(&U[i],tmp12);
    }

是否有更有效的方法只使用_mm_load_ps()?

解决方法

由于sizeof(float)为4,因此只有V中的每四个条目才能正确对齐.请记住,_mm_load_ps一次加载四个浮点数.参数,即指向第一个浮点的指针,需要与16个字节对齐.

我假设在你的例子中我是4的倍数,否则_mm_load_ps(& V [i])会失败.

更新

这就是我建议使用对齐的加载和shuffle实现上面的滑动窗口示例:

__m128 v_im1;
__m128 v_i = _mm_load_ps( &V[0] );
__m128 v_ip1 = _mm_load_ps( &V[4] );

for ( i = 4 ; i < dx ; i += 4 ) {

    /* Get the three vectors in this 'frame'. */
    v_im1 = v_i; v_i = v_ip1; v_ip1 = _mm_load_ps( &V[i+4] );

    /* Get the u1..u8 from the example code. */
    __m128 u3 = _mm_shuffle_ps( v_im1,v_i,3 + (4<<2) + (0<<4) + (1<<6) );
    __m128 u4 = _mm_shuffle_ps( v_i,v_ip1,3 + (4<<2) + (0<<4) + (1<<6) );

    __m128 u1 = _mm_shuffle_ps( u3,1 + (2<<2) + (1<<4) + (2<<6) );
    __m128 u2 = _mm_shuffle_ps( v_i,u4,1 + (2<<2) + (1<<4) + (2<<6) );

    __m128 u5 = _mm_shuffle_ps( v_im1,u3,1 + (2<<2) + (1<<4) + (2<<6) );
    __m128 u6 = _mm_shuffle_ps( u4,1 + (2<<2) + (1<<4) + (2<<6) );

    __m128 u7 = v_im1;
    __m128 u8 = v_ip1;

    /* Do your computation and store. */
    ...

    }

请注意,这有点棘手,因为_mm_shuffle_ps只能从每个参数中获取两个值,这就是为什么我们首先需要创建u3和u4才能将它们重新用于具有不同重叠的其他值.

另请注意,值u1,u3和u5也可以在上一次迭代中从u2,u4和u6恢复.

最后请注意,我还没有验证上面的代码!阅读_mm_shuffle_ps的文档,并检查第三个参数(选择器)是否适用于每种情况.

猜你在找的C&C++相关文章