c++ - Visual C++ 2012 (x86) 中可能的编译器错误?

标签 c++ visual-c++ visual-studio-2012 visual-c++-2012 compiler-bug

我目前在使用 VC++ 11 (CTP Update 1) 为 x86 目标编译时遇到随机浮点错误。请参阅下面的简短示例“test.cpp”,并使用以下命令进行编译:

cl /GL /O2 /EHsc test.cpp /link /MACHINE:X86

输出应该是10 == 10,但是当/GL(全程序优化)开启时会产生10 == 0 .问题似乎是 get_scaling_factor() 将结果推送到浮点堆栈上,但调用函数期望它在 SSE 寄存器 XMM0 中。

问题:我是否遗漏了一些明显的东西,或者这真的是一个错误?当然,测试程序没有意义,因为它是一个精简的测试用例。

test.cpp:

#include <iostream>

template <typename T>
inline T get_scaling_factor(int units)
{
    switch (units)
    {
    case 0: return 1;  
    case 1: return 10;  
    case 2: return 100;  
    case 3: return 1000;  
    case 4: return 10000;  
    case 5: return 100000;  
    case 6: return 1000000;  
    case 7: return 10000000;  
    case 8: return 100000000;  
    case 9: return 1000000000; 
    default: return 1;
    }
}

template <int targetUnits, typename T>
inline T scale(T value, int sourceUnits)
{
    return value   * get_scaling_factor<T>(sourceUnits) 
                   / get_scaling_factor<T>(targetUnits);
}

__declspec(noinline)
double scale(double value, int units) 
{
    return scale<9>(value, units);
}

int main()
{
    std::cout << "10 = " << scale(1e9, 1) << std::endl;
}

更新

问题 confirmed by Microsoft .它甚至会影响这样的直接代码:

#include <stdio.h>
double test(int a)
{
    switch (a)
    {
    case 0: return 1.0;
    case 1: return 10.0;
    case 2: return 100.0;
    case 3: return 1000.0;
    case 4: return 10000.0;
    case 5: return 100000.0;
    case 6: return 1000000.0;
    case 7: return 10000000.0;
    case 8: return 100000000.0;
    case 9: return 1000000000.0;
    default: return 1.0;
    }
}

void main()
{
    int nine = 9;
    double x = test(nine);
    x /= test(7);
    int val = (int)x;
    if (val == 100)
        printf("pass");
    else 
        printf("fail, val is %d", val);
}

最佳答案

是的,这绝对是一个代码优化器错误,我可以毫无问题地重现它。优化器错误通常与内联相关,但此处并非如此。这个错误是由 VS2012 中支持新的自动矢量化功能的大量代码生成更改引入的。

简而言之,get_scaling_factor() 函数在 FPU 堆栈上返回结果。代码生成器正确地发出指令以从堆栈中检索它并将其存储在 XMM 寄存器中。但是优化器不恰本地完全删除了该代码,就好像它假定函数结果已经存储在 XMM0 中一样。

解决方法很难找到,将模板函数专门用于 double 无效。使用#pragma optimize 禁用优化:

#pragma optimize("", off)
__declspec(noinline)
double scale(double value, int units) 
{
    return scale<9>(value, units);
}
#pragma optimize("", on)

您的复制代码非常好,Microsoft 可以轻松地修复此错误。您可以在 connect.microsoft.com 提交反馈报告,只需链接到此问题即可。或者,如果您赶时间,那么您可以联系 Microsoft 支持,但我想他们会为您提供相同的解决方法,让您持续使用服务包。


更新:已在 VS2013 中修复。

关于c++ - Visual C++ 2012 (x86) 中可能的编译器错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13051930/

相关文章:

c++ - 请解释这个歧义?

c++ - Visual Studio-在单步执行时查看堆栈大小增长的方法?

c++ - 虚拟继承——gcc 与 vc++

c# - 在 Visual Studio 2010 和 2012 中找到不同的答案

asp.net - Visual Studio - 调试给出错误 0x800700b7

c++ - 如何正确包含 atlbase.h

C++ 比较迭代器和 int

java - 将 C++ 与 Objective-C 和 Java 混合使用

c++ - C++中的寻字游戏算法

C++ 与 MSVC : Variadic ctor in derived class gets argument list wrong when calling base class ctor. 编译器错误或用户错误?