【问题标题】:Function crashes when using _mm_load_pd使用 _mm_load_pd 时函数崩溃
【发布时间】:2018-06-06 22:57:46
【问题描述】:

我有以下功能:

template <typename T>
void SSE_vectormult(T * A, T * B, int size)
{

    __m128d a;
    __m128d b;
    __m128d c;
    double A2[2], B2[2], C[2];
    const double * A2ptr, * B2ptr;
    A2ptr = &A2[0];
    B2ptr = &B2[0];
    a = _mm_load_pd(A);
    for(int i = 0; i < size; i+=2)
    {
        std::cout << "In SSE_vectormult: i is: " << i << '\n';
        A2[0] = A[i];
        B2[0] = B[i];
        A2[1] = A[i+1];
        B2[1] = B[i+1];
        std::cout << "Values from A and B written to A2 and B2\n";
        a = _mm_load_pd(A2ptr);
        b = _mm_load_pd(B2ptr);
        std::cout << "Values converted to a and b\n";
        c = _mm_mul_pd(a,b);
        _mm_store_pd(C, c);
        A[i] = C[0];
        A[i+1] = C[1];
    };
//    const int mask = 0xf1;
//    __m128d res = _mm_dp_pd(a,b,mask);
//    r1 = _mm_mul_pd(a, b);
//    r2 = _mm_hadd_pd(r1, r1);
//    c = _mm_hadd_pd(r2, r2);
//    c = _mm_scale_pd(a, b);
//    _mm_store_pd(A, c);
}

当我在 Linux 上调用它时,一切都很好,但是当我在 Windows 操作系统上调用它时,我的程序崩溃并显示“程序不再工作”。我做错了什么,如何确定我的错误?

【问题讨论】:

  • 假设您正在运行 64 位 Windows,请将您的代码编译为 64 位。 64 位模式下的堆栈是 16 字节对齐的,但在 32 位 Windows 中只有 4 字节对齐。您正在使用的加载和存储需要 16 字节对齐。

标签: c++ segmentation-fault sse intrinsics


【解决方案1】:

不保证您的数据按照 SSE 加载的要求对齐 16 字节。要么使用_mm_loadu_pd:

    a = _mm_loadu_pd(A);
    ...
    a = _mm_loadu_pd(A2ptr);
    b = _mm_loadu_pd(B2ptr);

或确保您的数据在可能的情况下正确对齐,例如对于静态或本地:

alignas(16) double A2[2], B2[2], C[2];    // C++11, or C11 with <stdalign.h>

或不使用 C++11,使用特定于编译器的语言扩展:

 __attribute__ ((aligned(16))) double A2[2], B2[2], C[2];   // gcc/clang/ICC/et al

__declspec (align(16))         double A2[2], B2[2], C[2];   // MSVC

您可以使用#ifdef#define 一个适用于目标编译器的ALIGN(x) 宏。

【讨论】:

    【解决方案2】:

    让我试着回答一下为什么您的代码在 Linux 而不是 Windows 中有效。以 64 位模式编译的代码具有 16 个字节对齐的堆栈。但是,在 32 位模式下编译的代码在 windows 上只有 4 字节对齐,在 Linux 上不保证 16 字节对齐。

    GCC 在 64 位系统上默认为 64 位模式。但是,即使在 64 位系统上,MSVC 也默认为 32 位模式。所以我猜你没有在 Windows 中以 64 位模式编译代码,_mm_load_pd_mm_store_pd 都需要 16 字节对齐的地址,所以代码会崩溃。

    您至少有三种不同的解决方案可以让您的代码在 Windows 中也能正常工作。

    1. 在 64 位模式下编译您的代码。
    2. 使用未对齐的加载和存储(例如_mm_storeu_pd
    3. 按照 Paul R 的建议自行对齐数据。

    最好的解决方案是第三种解决方案,此后您的代码将在 32 位系统和未对齐加载/存储速度慢得多的旧系统上运行。

    【讨论】:

      【解决方案3】:

      如果您查看http://msdn.microsoft.com/en-us/library/cww3b12t(v=vs.90).aspx,您可以看到函数__mm_load_pd 定义为:

      __m128d _mm_load_pd (double *p);
      

      因此,在您的代码中,A 应该是 double 类型,但 A 是类型 T 的模板参数。您应该确保使用权限模板参数调用 SSE_vectormult 函数,或者只是删除模板并改用 double 类型,

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-13
        • 2015-04-22
        • 1970-01-01
        相关资源
        最近更新 更多