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

Dan*_*ger 29 c++ visual-c++ compiler-bug visual-studio-2012 visual-c++-2012

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

cl /GL /O2 /EHsc test.cpp /link /MACHINE:X86
Run Code Online (Sandbox Code Playgroud)

输出应该是10 == 10,但它会10 == 0/GL(整个程序优化)启用时产生.问题似乎是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;
}
Run Code Online (Sandbox Code Playgroud)

更新

问题由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);
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 23

是的,这绝对是一个代码优化器错误,我没有遇到麻烦.优化程序错误通常与内联相关,但事实并非如此.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)
Run Code Online (Sandbox Code Playgroud)

你的repro代码非常好,微软将毫无困难地解决这个问题.您可以在connect.microsoft.com上提交反馈报告,只需链接到此问题即可.或者,如果您赶时间,那么您可以联系Microsoft支持,但我想他们会给您相同的解决方法,以便您使用该服务包.


更新:在VS2013中修复.