I have a case where a friend casts a non-base class object of type "Base" to a class type object "Derived", where "Derived" is a derived class of "Base" and only adds functions, but no data. In the below code, I did add a data member x
to the derived class
struct A { int a; }; struct B : A { // int x; int x; }; A a; int g(B *b) { a.a = 10; b->a++; return a.a; }
With strict alias analysis on, GCC (also Clang) always returns 10
, and not 11
, because b
can never point to a
in a well-defined code. However, if I remove B::x
(as is actually the case in the code of my friend), GCC's output assembler code does not optimize the return access of a.a
and reloads the value from memory. So the code of my friend that calls g
"works" on GCC (as he intended) even though I think it still has undefined behavior
g((B*)&a);
So in essentially the same two cases, GCC optimizes one case and doesn't optimize the other case. Is it because b
can then legally point to a
? Or is it because GCC just wants to not break real-world code?
I tested the answer that states
If you remove B::x, then B meets the requirements in 9p7 for a standard-layout class and the access becomes perfectly well-defined because the two types are layout-compatible, 9.2p17.
With two layout compatible enums
enum A : int { X, Y }; enum B : int { Z }; A a; int g(B *b) { a = Y; *b = Z; return a; }
The assembler output for g
returns 1
, not 0
, even though A
and B
are layout compatible (7.2p8).
So my further question is (quoting an answer): "two classes with exactly the same layout may be considered "almost the same" and they are left out of the optimization.". Can someone provide a proof of this for GCC or Clang?
GCC consistently outperformance Clang on all optimization levels. 32 Bit Performance is on a bit lower side with respect to corresponding 64-bit compilers & optimization levels. This can be attributed to being able to utilize the RAM properly. The contrast between O0 & Other optimization levels is very visible.
Clang is much faster and uses far less memory than GCC. Clang aims to provide extremely clear and concise diagnostics (error and warning messages), and includes support for expressive diagnostics. GCC's warnings are sometimes acceptable, but are often confusing and it does not support expressive diagnostics.
GCC is slower to compile than clang, so I spend a lot of time compiling, but my final system is (usually) faster with GCC, so I have set GCC as my system compiler.
This is done because they referred to the same memory location. Strict Aliasing: GCC compiler makes an assumption that pointers of different types will never point to the same memory location i.e., alias of each other. Strict aliasing rule helps the compiler to optimize the code.
If you remove B::x
, then B
meets the requirements in 9p7 for a standard-layout class and the access becomes perfectly well-defined because the two types are layout-compatible, 9.2p17 and the members both have the same type.
A standard-layout class is a class that:
- has no non-static data members of type non-standard-layout class (or array of such types) or reference,
- has no virtual functions (10.3) and no virtual base classes (10.1),
- has the same access control (Clause 11) for all non-static data members,
- has no non-standard-layout base classes,
- either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
- has no base classes of the same type as the first non-static data member.
Two standard-layout struct types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout-compatible types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With