在/OPT:ICF 存在的情况下,Visual Studio 2013 是否正确优化?

我希望以下程序始终返回 0.但是,对于 Visual Studio 2013(更新 4),程序在发布版本中退出 1.我不确定这是否是一个错误,或者编译器的优化器是否正确并且依赖于某些边缘行为.如果关闭了 CONST 宏,则发布 exe 返回 0.如果优化器确实正确,我能否得到允许它发出代码的原因?

I expect the following program to return 0 all of the time. However with Visual Studio 2013 (Update 4), the program exits 1 in release builds. I'm not sure if this is a bug or if the compiler's optimizer is correct and is relying on some edge behavior. If the CONST macro is turned off, the release exe returns 0. If the optimizer is indeed correct, could I get the reason why it is allowed to emit the code it does?

#if 1
#   define CONST const
#else
#   define CONST
#endif


class TypeId {
public:
    bool operator== (TypeId const & other) const
    {
        return id == other.id;
    }

private:
    TypeId (void const * id)
        : id(id)
    {}

public:
    template <typename T>
    static TypeId Get ()
    {
        static char CONST uniqueMemLoc = 0;
        return TypeId(&uniqueMemLoc);
    }

private:
    void const * id;
};


int main(int, char **)
{
    typedef int A;
    typedef unsigned int B;

    if (TypeId::Get<A>() == TypeId::Get<B>()) {
        return 1;
    }
    return 0;
}

推荐答案

根据 C++11 标准部分草案 14.8 [temp.fct.spec] 说(强调我的未来):

This does not seem like a valid optimization according to the draft C++11 standard section 14.8 [temp.fct.spec] says (emphasis mine going forward):

从模板实例化的每个函数模板特化都有它自己的任何静态变量的副本.[示例:

Each function template specialization instantiated from a template has its own copy of any static variable. [ Example:

template<class T> void f(T* p) {
static T s;
};
void g(int a, char* b) {
    f(&a); // calls f<int>(int*)
    f(&b); // calls f<char*>(char**)
}

这里 f(int*) 有一个 int 类型的静态变量 s 和f(char**) 有一个 char* 类型的静态变量 s.―结束示例]

Here f(int*) has a static variable s of type int and f<char*>(char**) has a static variable s of type char*. ―end example ]

由于您采用折叠变量的地址,它们会影响可观察的行为,这将违反 假设规则.

Since your taking the address of the variable folding them effects observable behavior which would violate the as-if rule.

T.C.指出 /opt:noicf 可以防止不符合规范的行为.

T.C. points out that /opt:noicf prevents the non-conforming behavior.

Matt McNabb 指出 /OPT(优化)文档 包含以下注释:

Matt McNabb points out that the /OPT (Optimizations) documentation contains the following note:

因为/OPT:ICF 会导致相同的地址被分配给不同的函数或只读数据成员(常量变量使用/Gy 编译),它可以破坏依赖于唯一性的程序函数或只读数据成员的地址.更多信息,请参阅/Gy(启用功能级链接).

Because /OPT:ICF can cause the same address to be assigned to different functions or read-only data members (const variables compiled by using /Gy), it can break a program that depends on unique addresses for functions or read-only data members. For more information, see /Gy (Enable Function-Level Linking).

这表明这可能是故意的不合规行为.Ben Voigt 在评论中说现在转移到聊天,这确实意味着优化可能不符合,但这一点值得商榷.

Which suggests this could be intentional non-conforming behavior. Ben Voigt says in a comment now moved to chat that this indeed means the optimizations can be non-conforming but this points is debatable.

用户 usr 已链接 到 MS 博客帖子:介绍'/Gw'编译器开关,它说:

User usr linked to an MS blog post: Introducing ‘/Gw’ Compiler Switch and it says:

请注意,ICF 优化仅适用于相同的其地址未被采用的 COMDAT ,并且它们是只读的.如果一个数据不是地址获取,然后由 ICF 破坏地址唯一性不会导致任何可观察到的差异,因此它是有效的并且符合标准.

Please note, the ICF optimization will only be applied for identical COMDATs where their address is not taken, and they are read only. If a data is not address taken, then breaking address uniqueness by ICF won't lead to any observable difference, thus it is valid and conformant to the standard.

后来的评论说:

即使它完全符合自己的标准,当结合/Gy 可能会导致潜在的破坏行为.

Even though it's on it's own completely standards complaint, when combined with /Gy potentially breaking behavior can result.

据我所知,为了使 /Gy 生效 const 变量 __declspec(selectany) 必须使用,但它可能是文档中更清楚.

From what I can tell in order for /Gy to effect const variables __declspec(selectany) has to be used but it could be clearer in the documentation.

至少我们可以看到 /Gw 不应该引入不符合规范的行为,但 /Gy/Gw 结合可能会.

At minimum we can see that /Gw should not introduce non-conforming behavior but /Gy in combination with /Gw may.

相关文章