C ++编译器能否优化使用用于将函数结果传递给另一个函数的虚拟变量?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C ++编译器能否优化使用用于将函数结果传递给另一个函数的虚拟变量?相关的知识,希望对你有一定的参考价值。
在下面的代码段中:
A a = fxn1(x1, x2, ...);
B b = fxn2(y1, y2, ...);
C c = fxn3(a, b);
用编译器优化fxn1和fxn2结果的伪变量'a'和'b'的创建是否可以将fxn1和fxn2的结果作为参数直接传递给fxn3?
我意识到代码很容易写成
C c = fxn3(fxn1(x1, x2, ...), fxn2(y1, y2, ...));
实现相同的意图。但是,如果涉及更多参数并且函数之间存在更多依赖关系,IMO将变得非常笨重。
我知道懒惰的评估方法,但这将涉及比我想介绍的更多的代码。谢谢
为什么不干脆呢?以下代码:
struct A { int a; };
struct B { int b; };
struct C { int c; };
A fxn1( int x1, int x2 )
{
return A{ x1+x2 };
}
B fxn2( int y1, int y2 )
{
return B{ y1-y2 };
}
C fxn3( const A& a, const B& b )
{
return C{ a.a * b.b };
}
int main()
{
int x1 = 1;
int x2 = 2;
int y1 = 3;
int y2 = 4;
A a = fxn1(x1, x2);
B b = fxn2(y1, y2);
C c = fxn3(a, b);
std::cout << c.c << std::endl;
}
结果:
0000000000400630 <main>:
400630: 48 83 ec 08 sub $0x8,%rsp
400634: be fd ff ff ff mov $0xfffffffd,%esi
400639: bf 60 10 60 00 mov $0x601060,%edi
40063e: e8 cd ff ff ff callq 400610 <std::basic_ostream<char, std::char_traits<char> >::operator<<(int)@plt>
400643: 48 89 c7 mov %rax,%rdi
400646: e8 95 ff ff ff callq 4005e0 <std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)@plt>
40064b: 31 c0 xor %eax,%eax
40064d: 48 83 c4 08 add $0x8,%rsp
400651: c3 retq
400652: 0f 1f 40 00 nopl 0x0(%rax)
400656: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40065d: 00 00 00
你看到的是:
您的所有功能都减少到一个恒定负载:
400634: be fd ff ff ff mov $0xfffffffd,%esi
这简直就是“-3”。
主要的其余部分仅用于使用std::cout
。
所以你的问题:
用编译器优化fxn1和fxn2结果的伪变量'a'和'b'的创建是否可以将fxn1和fxn2的结果作为参数直接传递给fxn3?
简单地说“是”:-)它“可以”但不是必须的。特别是如果您的代码依赖于更多变量并产生副作用,它可能不会被评估为const var。所以你总是要测量并检查出你自己的真实代码!
理论上,是的,这是可能的。如果你编写单行代码,你也可以获得由编译器建模的临时代码。意图的差异在于生命周期和析构函数。当您的编译器可以证明生命周期无关紧要时,它可以这样做。
在实践中,您需要确保编译器可以看到正在发生的事情,要么启用链接时间优化(LTO),要么让代码内联。在A和B类或其中一个成员中使用自定义析构函数没有帮助,尤其是在另一个CPP文件中时(如果您没有LTO)
人们可能想知道担心这些元素是否有意义。通常,对代码进行概要分析并查看放松时间最多的位置更有意义。
当它似乎是热路径的一部分时,检查生成的程序集。编译器资源管理器是一个非常好的在线工具,可以帮助您。
我意识到代码很容易写成
警告,用
A a = fxn1(x1, x2, ...); B b = fxn2(y1, y2, ...); C c = fxn3(a, b);
你确定fxn1(x1,x2,...)在fxn2(y1,y2,...)之前执行,但是对于C c = fxn3(fxn1(x1, x2, ...), fxn2(y1, y2, ...));
,两个参数的执行顺序是不确定的(如果我没错)
所以这两种形式不相同,除非根本没有副作用,包括在返回值的管理中,如果它们是类的实例
用编译器优化fxn1和fxn2结果的伪变量'a'和'b'的创建是否可以将fxn1和fxn2的结果作为参数直接传递给fxn3?
如果局部变量a和b仅用于参数fxn3也许是,但是尊重fxn1和fxn2的调用顺序,除非它可以知道根本没有副作用,也可能是这些调用被替换为他们的代码(作为内联管理)等
以上是关于C ++编译器能否优化使用用于将函数结果传递给另一个函数的虚拟变量?的主要内容,如果未能解决你的问题,请参考以下文章