【问题标题】:Program crashes when using intrinsics使用内部函数时程序崩溃
【发布时间】:2014-06-13 14:46:16
【问题描述】:

我是使用内部函数的新手,所以我不确定我的程序为什么会崩溃。我能够构建程序,但是当我运行它时,我只是得到“programname.exe 已停止工作”窗口。

#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#include <intrin.h>

int _tmain(int argc, _TCHAR* argv[])
{
    const int N = 128;
    float x[N], y[N];
    float sum = 0;

    for (int i = 0; i < N; i++)
    {
        x[i] = rand() >> 1;
        y[i] = rand() >> 1;
    }

    float* ptrx = x;
    float* ptry = y;

    __m128 x1;

    x1 = _mm_load_ps(ptrx);

    return 0;
}

如果我注释掉 'x1 = _mm_load_ps(ptrx);'行,程序能够运行,所以这就是导致崩溃的原因。

这是构建解决方案时的输出...

1>------ Rebuild All started: Project: intrins2, Configuration: Debug Win32 ------
1>  stdafx.cpp
1>  intrins2.cpp
1>c:\...\visual studio 2013\projects\intrins2\intrins2\intrins2.cpp(20): warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
1>c:\...\visual studio 2013\projects\intrins2\intrins2\intrins2.cpp(21): warning C4244: '=' : conversion from 'int' to 'float', possible loss of data
1>  intrins2.vcxproj -> c:\...\visual studio 2013\Projects\intrins2\Debug\intrins2.exe
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

【问题讨论】:

  • 这可能不太可能,但您执行代码的机器是否可能不支持内在函数?请注意,并非所有处理器都支持所有内在函数:msdn.microsoft.com/de-de/library/yc6byew8%28v=vs.90%29.aspx
  • _mm_load_ps(ptrx)改成_mm_loadu_ps(ptrx)或者在64位模式下编译,你的程序就不会崩溃了。
  • 谢谢@Zboson 成功了。两者有什么区别?
  • 如果我没记错的话,loadu 变体会加载未对齐的变量并使它们对齐。各种 SSE 内容都需要这种对齐方式。在 x64 上,默认情况下所有变量都是对齐的,这就是它在那里工作的原因。
  • @JonB.Jones。 _mm_load_ps 要求内存为 16 字节对齐。 _mm_loadu_ps 没有这样的限制。在 64 位模式下,堆栈是 16 字节对齐的。但是,堆中的内存不一定是 16 字节对齐的。在较旧的 CPU 上 _mm_loadu_ps_mm_load_ps 慢得多,即使在对齐的内存上也是如此,但情况不再如此。只需使用_mm_loadu_ps 并继续前进。

标签: c++ visual-studio visual-studio-2013 sse intrinsics


【解决方案1】:

问题在于您的“源”(数组x)未与 SSE 指令所需的大小对齐。

您可以使用“未对齐”加载指令来解决此问题,也可以使用 __declspec(align(n)) 来解决此问题,例如:

    float __declspec(align(16)) x[N];
    float __declspec(align(16)) y[N];

现在您的 xy 数组对齐到 16 个字节,并且可以从 SSE 指令访问[当然是 4 的倍数的索引]。请注意,采用内存参数的一般 SSE 指令不允许非对齐访问,因此例如_mm_max_ps 要求第二个参数(按 Intel 顺序,在 AT&T 顺序中的第一个)是对齐的内存位置。

【讨论】:

  • 谢谢,这很有帮助,但我不太明白对齐或不对齐是什么意思..
  • @JonB.Jones,对齐意味着内存地址是 16 的倍数。你可以测试一下。执行printf("%p %d\n", ptrx, ptrx%16),您将看到地址不是 16 字节的倍数(在 32 位模式下)。如果您在 64 位模式下编译或使用__declspec(align(16)),它将是 16 字节的倍数,即对齐到 16 字节。
  • 哦,哇,好吧。这为我解决了很多问题。我忘记了英特尔处理器中的内存地址长度不一定是固定的,就像在 MIPS 处理器中一样。伙计,现在我后悔没有早点来这里哈哈。非常感谢你们的帮助,伙计们。
  • 动态分配的内存呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多