I should add that some types of optimizations (cache efficiency being a big one) are outside the scope of the compiler because it is implicitly part of the code specification that the compiler needs to faithfully reproduce e.g. data structure layout is required to be a certain way for interoperability reasons.
There was some work done a while ago on automatic layout optimisation. See chris lattner's dissertation. It seems to be mostly dead now, but the principles justifying its existence are not.
Compilers can and do allow themselves license to ignore ABI in some cases; for c and c++, this includes link-time-optimised programs and -fwhole-program &c, as well as straight-up localised transformations on localised data structures (for whatever value of 'local' you prefer). Many other programming languages, in particular including JIT-compiled ones, also do not specify any ABI at all.
For C++, the principle backing this is the as-if rule [0]. While compilers do optimize internal ABIs to some extend there is definitely still lots of room for improvement. I think eventually internal function boundaries and data structures should/will eventually only be hints to the optimizer just like the register and inline keywords have lost their original strict meaning - but we are not anywhere close to that yet.