


  • 41
    It's only dangerous if you're relying on undefined behaviour. And even then I'd be surprised if it was the optimisation level that messed something up. – Seth Carnegie Jul 18 '12 at 16:31
  • 5
    The compiler is still constrained to produce a program that behaves "as if" it compiled your code exactly. I don't know that -O3 is considered particularly buggy? I think perhaps it can make undefined behavior "worse" as it may do weird and wonderful things based on certain assumptions, but that would be your own fault. So generally, I'd say it's fine. – BoBTFish Jul 18 '12 at 16:33
  • 5
    It's true that higher optimizations levels are more prone to compiler bugs. I've hit a few cases myself, but in general they are still pretty rare. – Mysticial Jul 18 '12 at 16:35
  • 26
    -O2 turns on -fstrict-aliasing, and if your code survives that then it'll probably survive other optimizations, since that's one that people get wrong over and over. That said, -fpredictive-commoning is only in -O3, and enabling that might enable bugs in your code caused by incorrect assumptions about concurrency. The less wrong your code is, the less dangerous optimization is ;-) – Steve Jessop Jul 18 '12 at 16:51
  • 6
    @PlasmaHH, I don't think "stricter" is a good description of -Ofast, it turns off IEEE-compliant handling of NaNs for example – Jonathan Wakely Jul 19 '12 at 8:25




By popular demand, here an addition:






  • 4
    I just use something like the opposite. I always use -Os or -O2 (sometimes O2 generates a smaller executable).. after profiling I use O3 on parts of the code that takes more execution time and that alone can give up to 20% more speed. – CoffeDeveloper Apr 5 '15 at 15:45
  • 3
    I do that for speed. O3 most times makes things slower. Don't know exactly why, I suspect it pollutes Instruction cache. – CoffeDeveloper Apr 7 '15 at 8:00
  • 4
    @DarioOO I feel like pleading "code bloat" is a popular thing to do, but I almost never see it backed with benchmarks. It depends a lot on architecture, but every time I see published benchmarks (e.g. phoronix.com/…) it shows O3 being faster in the vast majority of cases. I've seen the profiling and careful analysis required to prove that code bloat was actually an issue, and it usually only happens for people that embrace templates in an extreme way. – Nir Friedman Jul 19 '15 at 20:30
  • 1
    @NirFriedman: It tends to get an issue when the inlining cost model of the compiler has bugs, or when you optimize for a totally different target than you run on. Intrestingly this applies to all optimization levels... – PlasmaHH Jul 20 '15 at 8:26
  • 1
    @PlasmaHH: the using-cmov issue would be hard to fix for the general case. Usually you haven't just sorted your data, so when gcc is trying to decide if a branch is predictable or not, static analysis looking for calls to std::sort functions is unlikely to help. Using something like stackoverflow.com/questions/109710/… would help, or maybe write the source to take advantage of the sorted-ness: scan until you see >=128, then start summing. As for the bloated code, yeah I intend to get around to reporting it. :P – Peter Cordes Dec 13 '15 at 1:49

In my somewhat checkered experience, applying -O3 to an entire program almost always makes it slower (relative to -O2), because it turns on aggressive loop unrolling and inlining that make the program no longer fit in the instruction cache. For larger programs, this can also be true for -O2 relative to -Os!

The intended use pattern for -O3 is, after profiling your program, you manually apply it to a small handful of files containing critical inner loops that actually benefit from these aggressive space-for-speed tradeoffs. Newer versions of GCC have a profile-guided optimization mode that can (IIUC) selectively apply the -O3 optimizations to hot functions -- effectively automating this process.

  • 17
    "almost always"? Make it "50-50", and we'll have a deal ;-). – No-Bugs Hare Feb 9 '17 at 16:39

-O3 option turns on more expensive optimizations, such as function inlining, in addition to all the optimizations of the lower levels ‘-O2’ and ‘-O1’. The ‘-O3’ optimization level may increase the speed of the resulting executable, but can also increase its size. Under some circumstances where these optimizations are not favorable, this option might actually make a program slower.

  • 3
    I understand that some "apparent optimizations" might make a program slower, but do you have a source that claims that GCC -O3 has made a program slower? – Mooing Duck Jul 18 '12 at 18:27
  • 1
    @MooingDuck: While I can not cite a source, I remember running into such a case with some older AMD processors that had quite a small L1I cache (~10k instructions). I am sure google has more for the interested, but especially options like loop unrolling are not part of O3, and those increase sizes a lot. -Os is the one for when you want to make executable smallest. Even -O2 can increase code size. A nice tool to play with the outcome of different optimization levels is the gcc explorer. – PlasmaHH Jul 18 '12 at 19:44
  • @PlasmaHH: Actually, a tiny cache size is something a compiler could screw up, good point. That's a really good example. Please put it in the answer. – Mooing Duck Jul 18 '12 at 21:32
  • 2
    @PlasmaHH Pentium III had 16KB code cache. AMD's K6 and above actually had 32KB instruction cache. P4's started with around 96KB worth. Core I7 actually has a 32KB L1 code cache. Instruction decoders are strong nowadays, so your L3 is good enough to fall back on for almost any loop. – doug65536 Jan 21 '13 at 1:39
  • 1
    You'll see an enormous performance increase any time there is a function called in a loop and it can do significant common subexpression elimination and hoisting of unnecessary recalculation out of the function to before the loop. – doug65536 Jan 21 '13 at 1:51

Yes, O3 is buggier. I'm a compiler developer and I've identified clear and obvious gcc bugs caused by O3 generating buggy SIMD assembly instructions when building my own software. From what I've seen, most production software ships with O2 which means O3 will get less attention wrt testing and bug fixes.

Think of it this way: O3 adds more transformations on top of O2, which adds more transformations on top of O1. Statistically speaking, more transformations means more bugs. That's true for any compiler.


Recently I experienced a problem using optimization with g++. The problem was related to a PCI card, where the registers (for command and data) were repreented by a memory address. My driver mapped the physical address to a pointer within the application and gave it to the called process, which worked with it like this:

unsigned int * pciMemory;
askDriverForMapping( & pciMemory );
pciMemory[ 0 ] = someCommandIdx;
pciMemory[ 0 ] = someCommandLength;
for ( int i = 0; i < sizeof( someCommand ); i++ )
    pciMemory[ 0 ] = someCommand[ i ];

The card didn't act as expected. When I saw the assembly I understood that the compiler only wrote someCommand[ the last ] into pciMemory, omitting all preceding writes.

In conclusion: be accurate and attentive with optimization.

  • 50
    But the point here is that your program simply has undefined behaviour; the optimiser did nothing wrong. In particular you need to declare pciMemory as volatile. – Konrad Rudolph Mar 25 '13 at 15:07
  • 14
    It’s actually not UB but the compiler is within its right to omit all but the last writes to pciMemory because all other writes provably have no effect. For the optimiser that’s awesome because it can remove many useless and time-consuming instructions. – Konrad Rudolph Mar 25 '13 at 15:20
  • 7
    I found this in standard (after 10+ years))) - A volatile declaration may be used to describe an object corresponding to a memory-mapped input/output port or an object accessed by an asynchronously interrupting function. Actions on objects so declared shall not be ‘‘optimized out’’ by an implementation or reordered except as permitted by the rules for evaluating expressions. – borisbn Mar 25 '13 at 15:22
  • 3
    @borisbn Somewhat off-topic but how do you know that your device have taken the command before sending a new command? – user877329 Sep 15 '14 at 8:59
  • 3
    @user877329 I saw it by device's behaviuor, but it was a great quest – borisbn Sep 16 '14 at 17:02

Your Answer

