Likely because your codebase had UB in it that didn't show itself until a certain optimization level. The solution is to fix all instances of UB. See my comment above.
There are other reasons for not using -O3 which people already mentioned.
As a matter of fact, Gentoo specifically says in their docs that -O3 breaks some packages[2].
[1] https://stackoverflow.com/questions/57889116/different-evalu...
O3 does more aggressive inlining and generally expensive optimizations and optimizations that are not necessarily profitable.
Forces me to use a better algorithm when it matters. Which more often than not, does not.
;-)
imo, if you have to go to O3 or enable a pragma to get an "obvious" optimization then this is undesirable and probably something the programmer still needs to be conscious of, especially since we spend so much time doing development builds that are not at the maximum release optimization level.
GCC is actually good at that, -O3 has no issue recognizing it. In fact there even is a very explicit option (-funswitch-loops) responsible for extracting loop invariants. It is not enabled on -O2 because it has a space-speed tradeoff. If this optimization is truly desirable even on -O2, `#pragma GCC optimize("-funswitch-loops")` can be used to force it.