C++ Optimierungsfrage: Koennen Compiler das?
-
Koennen Compiler derartiges wegoptimieren:
struct StructMitZweiAttributen { public: int a,b; } class Foo { private: StructMitZweiAttributen bar; public: StructMitZweiAttributen baar() { return bar; } } //irgendwo anders im code Foo foo; int ergebnis = foo.baar().a + foo.baar().b / (foo.baar().a + foo.baar().b);
Machen aktuelle Compiler (gcc, msvc, etc.) mit Optimierung daraus sowas aehnliches:
Foo foo; StructMitZweiAttributen tmp = foo.baar(); int ergebnis = tmp.a + tmp.b / (tmp.a + tmp.b);
-
gcc mingw 4.5.0
#include <iostream> using namespace std; struct StructMitZweiAttributen { public: int a,b; }; class Foo { public: StructMitZweiAttributen bar; public: StructMitZweiAttributen baar() { return bar; } }; int main() { Foo foo; cin>>foo.bar.a; cin>>foo.bar.b; int ergebnis = foo.baar().a + foo.baar().b / (foo.baar().a + foo.baar().b); cout<<ergebnis; }
wird zu
leal 24(%esp), %eax movl $__ZSt3cin, (%esp) movl %eax, 4(%esp) call __ZNSirsERi leal 28(%esp), %eax movl $__ZSt3cin, (%esp) movl %eax, 4(%esp) call __ZNSirsERi movl 28(%esp), %eax movl 24(%esp), %ecx movl $__ZSt4cout, (%esp) leal (%eax,%ecx), %ebx //addition cltd idivl %ebx //division leal (%eax,%ecx), %ecx //addition movl %ecx, 4(%esp) call __ZNSolsEi
Also klares ja.
Der sieht hier den Code von baar(), macht ihn inline und optimiert alles platt.
Anders sieht es aus, wenn er baar() nicht sehen kann.Dazu muß ich baar() in eine andere *.cpp-Datei machen. In der selben wird es optimiert, auch wenn ich sie unter der main() hinschreibe.
movl %ebx, 4(%esp) movl $__ZSt3cin, (%esp) call __ZNSirsERi leal 44(%esp), %eax movl $__ZSt3cin, (%esp) movl %eax, 4(%esp) call __ZNSirsERi movl %ebx, (%esp) call __ZN3Foo4baarEv movl %ebx, (%esp) movl %eax, %edi call __ZN3Foo4baarEv movl %ebx, (%esp) movl %edx, 28(%esp) call __ZN3Foo4baarEv movl %ebx, (%esp) movl %eax, %esi call __ZN3Foo4baarEv movl 28(%esp), %eax addl %edx, %esi movl $__ZSt4cout, (%esp) cltd idivl %esi leal (%eax,%edi), %edi movl %edi, 4(%esp) call __ZNSolsEi
Haha!
Der Compiler weiß nicht, daß die Funktion immer das selbe berechnet. Könnte ja auch immer ein anderes erzeugen.
Schade.
Mit
StructMitZweiAttributen const& baar();
ist es auch unoptimiert.
Mit
StructMitZweiAttributen const& baar() __attribute__ ((const));
ist es dann aber wieder optimiert.
-
Übrigens, mit
c++filt
lassen sich die komischen Symbole durch lesbare ersetzen, z.B. aus diesem Assembler-Ausschnitt:volkard schrieb:
...
leal 24(%esp), %eax movl $__ZSt3cin, (%esp) movl %eax, 4(%esp) call __ZNSirsERi leal 28(%esp), %eax movl $__ZSt3cin, (%esp) movl %eax, 4(%esp) call __ZNSirsERi movl 28(%esp), %eax movl 24(%esp), %ecx movl $__ZSt4cout, (%esp) leal (%eax,%ecx), %ebx cltd idivl %ebx leal (%eax,%ecx), %ecx movl %ecx, 4(%esp) call __ZNSolsEi
...
wird durch Anwendung von
c++filt
> cat tmp.s | c++filt
das hier:
leal 24(%esp), %eax movl std::cin, (%esp) movl %eax, 4(%esp) call std::basic_istream<char, std::char_traits<char> >::operator>>(int&) leal 28(%esp), %eax movl std::cin, (%esp) movl %eax, 4(%esp) call std::basic_istream<char, std::char_traits<char> >::operator>>(int&) movl 28(%esp), %eax movl 24(%esp), %ecx movl std::cout, (%esp) leal (%eax,%ecx), %ebx cltd idivl %ebx leal (%eax,%ecx), %ecx movl %ecx, 4(%esp) call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
-
volkard schrieb:
Der Compiler weiß nicht, daß die Funktion immer das selbe berechnet. Könnte ja auch immer ein anderes erzeugen.
Schade.
Wenn VC verwendet wird und LTCG (Link Time Code Generation) verwendet wird, dann wird auch das wegoptimiert.
LTGC erzuegt und optimiert den Code erst während der Linker-Phase und dadurch kenn der Compiler "alle" Implementierungen als ob diese inline wären.
Leiderist das ziemlich lahm bei großen Projekten. Bei kleinen Projekten leistet LTGC allerdings irrsinniges.