是否有 C++ 编译器选项允许积极删除所有函数调用并将参数传递给具有空主体的函数?

Are there C++ compiler options that allow aggressive removal of all function calls and passed in arguments to functions with empty bodies?

#include <iostream>

int ExpensiveFunction() {
    // Do expensive calculation
    // ...

    std::cout << "You shouldn't see this!" << std::endl;

    return 42;
}

void print(int num)
{

}

int main()
{
    print(ExpensiveFunction());
    return 0;
}

我希望编译器能够识别 print 是一个空函数,从而完全删除语句的 print 调用和参数评估:

print(ExpensiveFunction());

然而,无论我使用哪种优化设置(使用 MSVC),它总是会执行昂贵函数的计算。

我认识到删除对 ExpensiveFunction 的调用的优化可能是破坏性优化,但我认为这应该是可能的,而无需将 print 转换为将在最优化配置中编译出的宏。

是否可以指示任何 C++ 编译器执行此操作?

编辑: 我添加了一个 std::cout 语句

Is it at all possible to direct any C++ compiler to do this?

可能不是直接的 - 这是一个 quality-of-implementation 问题。

Clang 和 GCC(对于最近测试的版本),使用标准 -O3 标志执行此操作。实际上,他们甚至用 -O1-O2 来做......你必须完全禁用优化才能让他们发出对 ExpensiveFunction.

的调用

对 x64 MSVC 19.24 的快速尝试表明它也会优化调用,至少 /O2

MSVC command-line 选项已列出 here

GCC command-line 选项在手册中,optimization-specific 选项在 here

通常,您可以使用 Matt Godbolt 的编译器资源管理器查看多个不同的编译器同时对同一代码执行的操作,例如 so


请注意,这只是测试您的示例代码 - 如果 ExpensiveFunction 具有可观察的 side-effects,优化器将无法删除它。


编辑 所以结果是 ExpensiveFunction 有可观察的 side-effects.

I recognize that an optimization that removes the call to ExpensiveFunction may be a destructive optimization,

没有"destructive optimization"这样的东西。优化是在不改变功能特性的情况下改进程序的non-functional特性(通常是性能或大小),具体定义为可见的side-effects。

让我们考虑一下您的标题,已更正以匹配问题的 body:

Are there C++ compiler options that allow aggressive removal of all function calls and passed in arguments to functions with non-empty bodies?

如果编译器可以通过丢弃需要时间的东西来加速您的代码 即使它们具有 externally-observable 效果,生活也会变得非常简单:它可以用

替换每个程序
int main() {}

并称之为 "destructive optimization"。这是您更正标题的正确解决方案,对吗?

... but I feel that this should be possible without converting print into a macro that will be compiled out in the most optimized configuration.

您也可以使 ExpensiveFunction 的 body 成为条件,例如,如果它确实是调试输出,您希望在某些构建中禁用其可观察 side-effect

int ExpensiveFunction() {
    #ifndef DEBUG
    // Do expensive calculation
    // ...

    std::cout << "You shouldn't see this!" << std::endl;
    #endif
    return 42;
}

但是禁用具有可观察性的代码 side-effects 必须 始终在您的手动控制之下,除非您对我的 extra-reductive whole-program 上面的优化。

对于 GCC 和 Clang,您可以使用 __attribute__((pure)) 让编译器放心,ExpensiveFunction() 没有任何副作用,如果不使用其结果可以省略。在一些简单的情况下,这些编译器无论如何都可以找出函数的纯粹性,但是使用属性可以让您在更复杂的情况下以及在其他翻译单元中定义的函数中获得这种效果。

不幸的是,MSVC 没有我所知道的任何等效工具。有关更多信息,请参阅 pure/const function attributes in different compilers

对于 MSVC,您需要 /O2(优化)、/GL+/LTCG(link-时间代码生成)和 /OPT:REF(消除从未引用的函数和数据)。