SSE _mm_load_ps 导致分段错误

Posted

技术标签:

【中文标题】SSE _mm_load_ps 导致分段错误【英文标题】:SSE _mm_load_ps causing segmentation faults 【发布时间】:2014-02-12 08:17:54 【问题描述】:

所以我在学习使用 SSE 内在函数编程的玩具示例时遇到了麻烦。我在这里读到其他线程,有时 _mm_load_ps 函数的分段错误是由于未正确对齐事物引起的,但我认为它应该由 attribute((aligned(16 ))) 我做的事情。此外,当我在代码中注释掉第 23 行或第 24 行(或两者)时,问题就会消失,但显然这会使代码无法正常工作。

#include <iostream>
using namespace std;

int main()

        float temp1[] __attribute__((__aligned__(16))) = 1.1,1.2,1.3,14.5,3.1,5.2,2.3,3.4;
        float temp2[] __attribute__((__aligned__(16))) = 1.2,2.3,3.4,3.5,1.2,2.3,4.2,2.2;
        float temp3[8];
        __m128 m, *m_result;
        __m128 arr1 = _mm_load_ps(temp1);
        __m128 arr2 = _mm_load_ps(temp2);

        m = _mm_mul_ps(arr1, arr2);
        *m_result = _mm_add_ps(m, m); 
        _mm_store_ps(temp3, *m_result); 
        for(int i = 0; i < 4; i++)
           
            cout << temp3[i] << endl;
           

        m_result++;
        arr1 = _mm_load_ps(temp1+4);
        arr2 = _mm_load_ps(temp2+4);
        m = _mm_mul_ps(arr1, arr2);
        *m_result = _mm_add_ps(m,m);
        _mm_store_ps(temp3, *m_result); 


        for(int i = 0; i < 4; i++)
           
            cout << temp3[i] << endl;
           
        return 0;

第 23 行是 arr1 = _mm_load_ps(temp1+4)。对我来说很奇怪,我可以做一个或另一个,但不能同时做。任何帮助将不胜感激,谢谢!

【问题讨论】:

您已将 temp1 与 16 字节对齐,但随后添加了 4 以确保它不是 16 字节对齐... 对不起,我不跟,我不是必须用_mm_load_ps(temp1+4)来加载接下来的4个值吗? @jcoder: +4 (floats) 是 +16 字节,所以负载没问题 - 这里的问题是两个商店。 ...当然还有悬空指针。 @PaulR 绝对。请无视我的评论...在我喝了至少 2 杯咖啡之前,我不应该发表评论!对于错误的评论,我深表歉意。 【参考方案1】:

您的问题是您声明了一个指针__m128 *m_result,但您从未为它分配任何空间。稍后您还会执行m_result++,它指向另一个尚未分配的内存地址。这里没有理由使用指针。

#include <xmmintrin.h>                 // SSE
#include <iostream>
using namespace std;

int main()

        float temp1[] __attribute__((__aligned__(16))) = 1.1,1.2,1.3,14.5,3.1,5.2,2.3,3.4;
        float temp2[] __attribute__((__aligned__(16))) = 1.2,2.3,3.4,3.5,1.2,2.3,4.2,2.2;
        float temp3[8];
        __m128 m, m_result;
        __m128 arr1 = _mm_load_ps(temp1);
        __m128 arr2 = _mm_load_ps(temp2);

        m = _mm_mul_ps(arr1, arr2);
        m_result = _mm_add_ps(m, m); 
        _mm_store_ps(temp3, m_result); 
        for(int i = 0; i < 4; i++)
           
            cout << temp3[i] << endl;
           

        arr1 = _mm_load_ps(temp1+4);
        arr2 = _mm_load_ps(temp2+4);
        m = _mm_mul_ps(arr1, arr2);
        m_result = _mm_add_ps(m,m);
        _mm_store_ps(temp3, m_result); 


        for(int i = 0; i < 4; i++)
           
            cout << temp3[i] << endl;
           
        return 0;

【讨论】:

还要注意temp3 可能未对齐。 好点。我刚刚尝试了代码并且它有效。这可能是因为它是在 64 位模式下编译的,它将堆栈上的变量对齐到 16 个字节。 是的,编译为 64 位既是福也是祸。另请注意,您在这里不需要 SSE4.1 - 上面的代码中除了 SSE2 之外什么都没有。 再次正确。我虽然他说他用过_mm_dp_ps,但我现在看不到。 @PaulR,实际上,这里除了 SSE 之外什么都没有。甚至不需要 SSE2。【参考方案2】:

(1) m_result 只是一个wild pointer:

     __m128 m, *m_result;

将所有出现的*m_result 更改为m_result 并去掉m_result++;。 (m_result 只是一个临时向量变量,您随后将其存储到temp3)。

(2) 您的两个商店可能未对齐,因为 temp3 没有保证对齐 - 要么更改:

    float temp3[8];

到:

    float temp3[8] __attribute__((__aligned__(16)));

或使用_mm_storeu_ps:

    _mm_storeu_ps(temp3, m_result); 
            ^^^

【讨论】:

+1 因为你的答案比我的好一点。虽然我认为这里的正确术语是野指针而不是悬空指针。野指针是尚未初始化到已分配内存的指针,而悬空指针是指向已释放内存的指针。 en.wikipedia.org/wiki/Dangling_pointer 你说得对——严格来说这是一个野指针——我一直称它们为悬空指针,不管它们是野指针还是悬空指针,这是一个很难改掉的习惯。我会解决的。

以上是关于SSE _mm_load_ps 导致分段错误的主要内容,如果未能解决你的问题,请参考以下文章

Intel SSE Intrinsics _mm_load_si128 分段错误,

使用基本 SSE 指令的分段错误

_mm_store_si128 上的 SSE 段错误

使用 SSE 的任意位置 2 输入混洗

使用结果浮点数时的 SSE SIMD 分段错误

无法在 x86 上以 SSE 类型访问内存,但在 x64 上工作正常