【问题标题】:Is Visual Studio 2013 optimizing correctly in the presence of /OPT:ICF?Visual Studio 2013 在 /OPT:ICF 存在的情况下是否正确优化?
【发布时间】:2015-05-17 09:22:27
【问题描述】:

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

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

【问题讨论】:

  • 我认为优化器不正确。
  • 可能与 MSVC 中的 COMDAT 折叠有关。
  • 是的,/opt:noicf 修复了它。
  • @ShafikYaghmour MSDN documentation 似乎暗示这是故意的:“因为 /OPT:ICF 可能导致将相同的地址分配给不同的函数或只读数据成员(由使用 /Gy),它可以破坏依赖于函数或只读数据成员的唯一地址的程序。有关详细信息,请参阅 /Gy(启用函数级链接)。"
  • @usr 等一下,我刚刚完整阅读了这篇文章,上面写着Please note, the ICF optimization will only be applied for identical COMDATs where their address is not taken,这表明它不适用于这种情况。

标签: c++ c++11 visual-studio-2013 optimization


【解决方案1】:

根据草案 C++11 标准部分 14.8[temp.fct.spec] 说,这似乎不是一个有效的优化(强调我的未来):

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

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。 ——结束示例]

由于您使用变量的地址折叠它们会影响可观察到的行为,这将违反as-if rule

T.C.指出/opt:noicf 防止了不合格行为。

Matt McNabb 指出/OPT (Optimizations) documentation 包含以下注释:

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

这表明这可能是故意的不合格行为。 Ben Voigt says in a comment now moved to chat 这确实意味着优化可能不一致,但这一点值得商榷。

用户 usr linkedMS blog post: Introducing ‘/Gw’ Compiler Switch,它说:

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

后来的评论说:

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

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

至少我们可以看到/Gw 不应引入不合格行为,但/Gy/Gw 结合可能。

【讨论】:

【解决方案2】:

不,此优化不符合 C++ 标准。 uniqueMemLoc 的声明为模板的每个实例定义了一个唯一的对象,每个对象都有自己的地址。

(如果您使用了字符串文字,情况就不同了。在这种情况下优化将是有效的。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-28
    • 2014-01-26
    • 1970-01-01
    • 2019-12-23
    • 1970-01-01
    • 1970-01-01
    • 2016-04-01
    相关资源
    最近更新 更多