【问题标题】:What VS2017 C++ compiler option can affect matrices multiplication?什么 VS2017 C++ 编译器选项会影响矩阵乘法?
【发布时间】:2018-05-24 14:12:39
【问题描述】:

以下代码将两个 4 维单位矩阵相乘:

const Matrix4 id = Matrix4(
    1.0f, 0.0f, 0.0f, 0.0f, 
    0.0f, 1.0f, 0.0f, 0.0f, 
    0.0f, 0.0f, 1.0f, 0.0f, 
    0.0f, 0.0f, 0.0f, 1.0f);

auto & a = id;
auto & b = id;

auto m1 = Matrix4(
    a.data[0] * b.data[0] + a.data[4] * b.data[1] + a.data[8] * b.data[2] +
    a.data[12] * b.data[3],

    a.data[0] * b.data[4] + a.data[4] * b.data[5] + a.data[8] * b.data[6] +
    a.data[12] * b.data[7],

    a.data[0] * b.data[8] + a.data[4] * b.data[9] + a.data[8] * b.data[10] +
    a.data[12] * b.data[11],
    a.data[0] * b.data[12] + a.data[4] * b.data[13] + a.data[8] * b.data[14] +
    a.data[12] * b.data[15],
    a.data[1] * b.data[0] + a.data[5] * b.data[1] + a.data[9] * b.data[2] +
    a.data[13] * b.data[3],
    a.data[1] * b.data[4] + a.data[5] * b.data[5] + a.data[9] * b.data[6] +
    a.data[13] * b.data[7],
    a.data[1] * b.data[8] + a.data[5] * b.data[9] + a.data[9] * b.data[10] +
    a.data[13] * b.data[11],
    a.data[1] * b.data[12] + a.data[5] * b.data[13] + a.data[9] * b.data[14] +
    a.data[13] * b.data[15],
    a.data[2] * b.data[0] + a.data[6] * b.data[1] + a.data[10] * b.data[2] +
    a.data[14] * b.data[3],
    a.data[2] * b.data[4] + a.data[6] * b.data[5] + a.data[10] * b.data[6] +
    a.data[14] * b.data[7],
    a.data[2] * b.data[8] + a.data[6] * b.data[9] + a.data[10] * b.data[10] +
    a.data[14] * b.data[11],
    a.data[2] * b.data[12] + a.data[6] * b.data[13] + a.data[10] * b.data[14] +
    a.data[14] * b.data[15],
    a.data[3] * b.data[0] + a.data[7] * b.data[1] + a.data[11] * b.data[2] +
    a.data[15] * b.data[3],
    a.data[3] * b.data[4] + a.data[7] * b.data[5] + a.data[11] * b.data[6] +
    a.data[15] * b.data[7],
    a.data[3] * b.data[8] + a.data[7] * b.data[9] + a.data[11] * b.data[10] +
    a.data[15] * b.data[11],
    a.data[3] * b.data[12] + a.data[7] * b.data[13] + a.data[11] * b.data[14] +
    a.data[15] * b.data[15]);

const int diff_index = 15;

std::cout << "Actual value of element " << diff_index << " is " << m1.data[diff_index] << " expected " << id.data[diff_index] << std::endl;

很明显,生产的第 15 个元素是 1.0f,在发布配置中是 1.0f,但在 我的项目的调试配置中,我得到 0.0f

我试图通过使用我的项目中的编译器选项在命令行编译单个 .cpp 文件来重现这一点:

cl /GS /TP /W3 /Zc:wchar_t /Zi /Gm- /Od /Ob0 /Zc:inline /fp:precise /errorReport:prompt /WX- /Zc:forScope /RTC1 /GR /Gd /MDd /FC /EHsc /nologo /diagnostics:classic MatrixTest.cpp

但这会输出 1.0f。只有当我将 MatrixTest.cpp 编译为我的项目的一部分时,我才能获得 0.0f。

下面我提供了绝对微不足道的Matrix类的定义:

struct Matrix4
{
    float data[16];

    Matrix4(float m00,
        float m01,
        float m02,
        float m03,
        float m10,
        float m11,
        float m12,
        float m13,
        float m20,
        float m21,
        float m22,
        float m23,
        float m30,
        float m31,
        float m32,
        float m33)
    {
        data[0] = m00;
        data[4] = m01;
        data[8] = m02;
        data[12] = m03;
        data[1] = m10;
        data[5] = m11;
        data[9] = m12;
        data[13] = m13;
        data[2] = m20;
        data[6] = m21;
        data[10] = m22;
        data[14] = m23;
        data[3] = m30;
        data[7] = m31;
        data[11] = m32;
        data[15] = m33;
    }
};

我相信,这不是内存损坏的结果,因为我的项目绝对是微不足道的,而且这段代码已经在某些实际应用中运行了很长时间,所以我认为肯定发生了一些奇怪的事情。

更新 1

VS2017 15.7.1,编译器版本为:Microsoft (R) C/C++ Optimizing Compiler Version 19.14.26428.1 for x86

项目的配置是Debug 64bit。

编译器选项(省略 /I 和 /D)为: /GS /TP /W3 /Zc:wchar_t /Zi /Gm- /Od /Ob0 /Fd"ModelTest.dir\Debug\vc141.pdb" / Zc:inline /fp:precise /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "CMAKE_INTDIR=\"Debug\"" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope / RTC1 /GR /Gd /MDd /FC /Fa"Debug/" /EHsc /nologo /Fo"ModelTest.dir\Debug\" /Fp"ModelTest.dir\Debug\ModelTest.pch" /diagnostics:classic

项目(.sln 和 .vcxproj)由 cmake-3.11.2-win64-x64 生成。

【问题讨论】:

  • 如果您提供的代码不能产生问题,那么问题一定出在您没有提供的代码上。似乎您在其他地方有未定义的行为,并且所有这些代码都与识别实际问题无关。
  • 我的 VS2017 编译器版本是 Microsoft (R) C/C++ Optimizing Compiler Version 19.14.26428.1 for x86
  • 仍然......这只是基本的数学。没有什么特别的,甚至资格 矩阵乘法 都很强。优化器可以做一些技巧,但如果你正在调试,那是不可能的。也许你的 cpp 文件中还有其他东西导致了这种行为。顺便说一句,在发布版本中没有它你是如何编译的?
  • 在我的项目中,我只是从 main() 调用 testMatrix() 并返回。

标签: c++ visual-studio


【解决方案1】:

似乎是 VS 15.7.2 (19.14) x64 中的编译器错误。

没有足够的浮点寄存器来执行所有计算。 旧版本 (v140) 将 xmm14 卸载到堆栈上。但是 vc141 溢出到 xmm0 上,它恰好包含第 16 个参数的值。

比较vc140 vs. vc141 程序集。 (对于source.cpp):

vc140:

  movss       xmm1,dword ptr [rdx+rax]  
  mulss       xmm1,dword ptr [r8+rcx]  
  addss       xmm0,xmm1  
. . .
  movss       dword ptr [rsp+1A8h],xmm14  < save xmm14
. . .
  movss       xmm15,dword ptr [rdx+rax]  
  mulss       xmm15,dword ptr [r8+rcx]  
  addss       xmm14,xmm15
  movss       dword ptr [rsp+80h],xmm0  < push xmm0

vc141:

  movss       xmm1,dword ptr [rdx+rax]  
  mulss       xmm1,dword ptr [r8+rcx]  
  addss       xmm0,xmm1  
. . .
. . .
  movss       xmm0,dword ptr [rdx+rax]  < overwrites xmm0  
  mulss       xmm0,dword ptr [r8+rcx]  
  addss       xmm15,xmm0  
  movss       dword ptr [rsp+80h],xmm0  < push xmm0

作为一种解决方法,您可以单独计算最后一个参数并临时存储。

【讨论】:

  • 嗯...如果这是正确的,我的 这只是基本的数学运算不太合适...
  • 如果这是真的,这可能是对 AVX512 的 32 寄存器支持的另一个副作用错误。他们补充说,在 15.7 中,随之而来的是从错误编译到 ICE 的大量问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-30
  • 1970-01-01
  • 2011-11-15
  • 2020-04-09
  • 2023-04-09
  • 2011-02-21
  • 2019-12-13
相关资源
最近更新 更多