在Visual C ++ 2012(86)可能的编译器错误?(Possible compiler b

2019-07-02 12:37发布

编译使用VC ++ 11(CTP更新1)的x86目标时,我目前遇到的随机浮点错误。 见小例子“TEST.CPP”下方,使用编译:

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

输出应为10 == 10 ,但它产生10 == 0/GL被使能(整个程序优化)。 这个问题似乎是get_scaling_factor()推动浮点堆栈上的结果,而是调用函数注册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;
}

更新

问题得到微软的证实 。 它甚至会影响像这样直截了当的代码:

#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);
}

Answer 1:

是的,这绝对是一个代码优化错误,我没有任何麻烦,复制它。 优化的错误通常与内联有关,但这里并非如此。 这个bug得到了由支持新的自动向量化功能在VS2012沉重的代码生成的变化推出。

概括地说,所述get_scaling_factor()函数返回FPU堆栈上的结果。 代码生成器正确地发出指令,从堆栈检索它并把它存储在XMM寄存器。 但优化不当删除了全部的代码,就好像它假定功能结果已存储在XMM0。

一种解决方法是很难得的,专业的模板函数双没有任何影响。 禁用优化使用#pragma优化工作:

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

你摄制的代码是非常好,微软不会有任何麻烦固定从此这个bug。 您可以在connect.microsoft.com提交反馈报告,只是链接到这个问题。 或者,如果你赶时间的话可以联系微软支持,虽然我想像他们就会给你相同的解决方法最后你的服务包。


更新:固定在VS2013。



Answer 2:

/GL忽略默认调用约定,由设计。 随着LTCG时,编译器/连接知道整个调用图形,因此它可以匹配主叫方和被叫方。 使用SSE寄存器在这种情况下不可思议。

我不完全知道你的意思是“ get_scaling_factor()推动浮点堆栈上的结果”,虽然。 你的意思是,编译器无法内联呢? 我期望编译器这样做,因为调用图只有一个调用者。 (我们知道`get_scaling_factor(targetUnits)被内联,因为这会导至以零一师以其他方式)

如果编译器确实没有内联get_scaling_factor()那么你其实已经发现了两个错误:一是内联失败,和一个自定义调用约定失败。



文章来源: Possible compiler bug in Visual C++ 2012 (x86)?