【问题标题】:Visual Studio debugger sets the upper half of AVX registers to zeroVisual Studio 调试器将 AVX 寄存器的上半部分设置为零
【发布时间】:2021-08-09 06:36:39
【问题描述】:

在使用 AVX 调试某些代码时,我得到了毫无意义的结果。我将我的程序简化为以下内容:

#include <iostream>
#include <immintrin.h>

int main()
{
    while (1)
    {
        static float v[] = {1, 2, 3, 4, 5, 6, 7, 8};
        __m256 v8 = _mm256_load_ps(v);
        std::cout << v8.m256_f32[2] << v8.m256_f32[5];
    }
}

当我运行这个程序时,它会无休止地打印36,这是正确的(它会打印3,然后是6)。如果我在循环内的调试器中设置断点并单步执行,它会打印30。如果我删除断点并继续程序,它会再次开始打印36。我在 Release/Debug、Win32/x86(4 种组合)中看到了相同的行为。

为了能够使用 AVX,我在 Configuration Properties - C/C++ - Code Generation 中将“Enable Enhanced Instruction Set”设置为“Advanced Vector Extensions (/arch:AVX)”。我是不是忘记设置其他配置了?

由于这种行为,我无法使用调试器来调试我的真实程序(此处未包含)。这很烦人。

我做错了吗?我可以解决此问题吗?

我的 Visual Studio 是:MS Visual Studio Professional 2017,版本 15.9.3。

【问题讨论】:

  • FWIW,我没有观察到 MSVC2019、x64 调试/发布上的这种行为。我在跑步或跨步时都得到 36。
  • 如果您查看 asm 代码生成,带有这些选项的 MSVC 应该会生成具有正确 vzeroupper 使用的正常 AVX 指令,例如 godbolt.org/z/YMobhKK56。 (使用-O2,我们看到VS19.28 将向量保留在堆栈上,并对每个联合元素访问执行YMM 加载+ 洗牌,而不是利用保留调用的xmm5..15)。您是为 32 位还是 x86-64 构建?当然,这听起来像是一个调试器问题;该代码是合法的,并且应该在 MSVC 上得到很好的定义,并且在单步或不单步时改变行为是一个巨大的危险信号。
  • 我在发布/调试、Win32/x86(4 种组合)中看到了相同的行为。我确实在反汇编中看到了vzeroupper,但它位于循环内一个有趣的位置。我会再调整一下我的代码,看看我是否能理解它。
  • 可能 OT:_mm256_load_ps 不需要 32 字节边界对齐吗?在您的情况下,这似乎无法保证。
  • @DanielLangr:MSVC(和 ICC)总是使用不需要对齐的 AVX 加载/存储,例如 vmovups,即使您使用需要对齐的内在函数也是如此。因此,他们通过在调试版本中故意使用需要对齐的加载/存储来消除查找未对齐数据的可能性(在这种情况下,它们不会被折叠到内存源操作数中以用于其他不需要对齐的指令。)

标签: c++ visual-studio visual-studio-debugging avx


【解决方案1】:

Visual Studio 2017 15.9.7 fixes a bug 在调试时损坏 AVX/MPX/AVX512 寄存器,您应该更新到最新版本,15.9.3 已经快 3 年了。

【讨论】:

  • 没试过(更新 Visual Studio 是一场噩梦),但这一定是答案!
  • @anatolyg 在当前版本中更新从未给我带来任何问题,它主要只是包含错误修复,更重要的是为您的代码安全修复
猜你喜欢
  • 1970-01-01
  • 2018-06-02
  • 1970-01-01
  • 1970-01-01
  • 2016-06-11
  • 2016-11-22
  • 1970-01-01
  • 2016-04-19
  • 1970-01-01
相关资源
最近更新 更多