[HN Gopher] Advent of Compiler Optimisations 2025
       ___________________________________________________________________
        
       Advent of Compiler Optimisations 2025
        
       Author : vismit2000
       Score  : 323 points
       Date   : 2025-12-02 09:51 UTC (13 hours ago)
        
 (HTM) web link (xania.org)
 (TXT) w3m dump (xania.org)
        
       | ktallett wrote:
       | This is really cool. Congrats on the quality of the work!
        
       | filosofo_rancio wrote:
       | Thanks for sharing, I've always found optimizing a really
       | interesting field, I will keep a close eye!
        
       | squater wrote:
       | You can never have too much Godbolt!
        
       | bspammer wrote:
       | I really appreciate that despite being an obvious domain expert,
       | he's starting with the simple stuff and not jumping straight into
       | crazy obscure parts of the x86 instruction set
        
       | adev_ wrote:
       | Matt Godbolt is an absolute gem for the C & C++ community.
       | 
       | Many thanks to him for that.
       | 
       | Between that and compiler explorer, it is fair to say he made the
       | world a better place for many of us, developers.
        
         | cyberax wrote:
         | Wait?!? Godbolt is actually a real person!?!?
        
       | alfanick wrote:
       | Is there a PDF somewhere? I'm not really able to follow YT
       | videos.
        
         | philipportner wrote:
         | There's a link to the AoCO2025 tag for his blog posts in the
         | op.
        
       | alberth wrote:
       | After 25-years of software development, I still wonder whether
       | I'm using the best possible compiler flags.
        
         | cogman10 wrote:
         | What I've learned is that the fewer flags is the best path for
         | any long lived project.
         | 
         | -O2 is basically all you usually need. As you update your
         | compiler, it'll end up tweaking exactly what that general
         | optimization does based on what they know today.
         | 
         | Because that's the thing about these flags, you'll generally
         | set them once at the beginning of a project. Compiler authors
         | will reevaluate them way more than you will.
         | 
         | Also, a trap I've observed is setting flags based on bad
         | benchmarks. This applies more to the JVM than a C++ compiler,
         | but never the less, a system's current state is somewhat
         | random. 1->2% fluctuations in performance for even the same app
         | is normal. A lot of people won't realize that and ultimately
         | add flags based on those fluctuations.
         | 
         | But further, how code is currently layed out can affect
         | performance. You may see a speed boost not because you tweaked
         | the loop unrolling variable, but rather your tweak may have
         | relocated a hot path to be slightly more cache friendly. A
         | change in the code structure can eliminate that benefit.
        
           | 201984 wrote:
           | What's your reason for -O2 over -O3?
        
             | cogman10 wrote:
             | Historically, -O3 has been a bit less stable (producing
             | incorrect code) and more experimental (doesn't always make
             | things faster).
             | 
             | Flags from -O3 often flow down into -O2 as they are proven
             | generally beneficial.
             | 
             | That said, I don't think -O3 has the problems it once did.
        
               | 201984 wrote:
               | Thanks
        
               | sgerenser wrote:
               | -O3 gained a reputation of being more likely to "break"
               | code, but in reality it was almost always "breaking" code
               | that was invalid to start with (invoked undefined
               | behavior). The problem is C and C++ have so many UB edge
               | cases that a large volume of existing code may invoke UB
               | in certain situations. So -O2 thus had a reputation of
               | being more reliable. If you're sure your code doesn't
               | invoke undefined behavior, though, then -O3 should be
               | fine on a modern compiler.
        
               | drob518 wrote:
               | Exactly. A lot of people didn't understand the contract
               | between the programmer and the compiler that is required
               | to use -O3.
        
               | MaxBarraclough wrote:
               | That's a little vague, I'd put that more pointedly: they
               | don't understand how the C and C++ languages are defined,
               | have a poor grasp of undefined behaviour in particular,
               | and mistakenly believe their defective code to be
               | correct.
               | 
               | Of course, even with a solid grasp of the language(s),
               | it's still by no means easy to write correct C or C++
               | code, but if your plan it to go with _this seems to work_
               | , you're setting yourself up for trouble.
        
               | uecker wrote:
               | Oh, there are also plenty of bugs. And Clang still does
               | not implement the aliasing model of C. For C, I would
               | definitely recommend -O2 -fno-strict-aliasing
        
               | afdbcreid wrote:
               | Indeed, e.g. Rust by default (release builds) use -O3.
        
               | superxpro12 wrote:
               | Don't forget about -Oz!
        
             | wavemode wrote:
             | You have to profile for your specific use case. Some
             | programs run slower under O3 because it inlines/unrolls
             | more aggressively, increasing code size (which can be
             | cache-unfriendly).
        
               | grogers wrote:
               | Yeah, -O3 generally performs well in small benchmarks
               | because of aggressive loop unrolling and inlining. But in
               | large programs that face icache pressure, it can end up
               | being slower. Sometimes -Os is even better for the same
               | reason, but -O2 is usually a better default.
        
             | bluGill wrote:
             | Most people use -O2 and so if you use -O3 you risk some bug
             | in the optimizer that nobody else noticed yet. -O2 is less
             | likely to have problems.
             | 
             | In my experience a team of 200 developers will see 1
             | compiler bug affect them every 10 years. This isn't
             | scientific, but it is a good rule of thumb and may put the
             | above in perspective.
        
               | macintux wrote:
               | Would you say that bug estimate is when using -O2 or -O3?
        
               | bluGill wrote:
               | The estimate includes visual studio, and other compilers
               | that are not open source for whatever optimization
               | options we were using at the time. As such your question
               | doesn't make sense (not that it is bad, but it doesn't
               | make sense).
               | 
               | In the case of open source compilers the bug was
               | generally fixed upstream and we just needed to get on a
               | newer release.
        
             | nickelpro wrote:
             | People keep saying "O3 has bugs," but that's not true. At
             | least no more bugs than O2. It did and does more
             | aggressively expose UB code, but that isn't why people
             | avoid O3.
             | 
             | You generally avoid O3 because it's slower. Slower to
             | compile, and slower to run. Aggressively unrolling loops
             | and larger inlining windows bloat code size to the degree
             | it impacts icache.
             | 
             | The optimization levels aren't "how fast do you want to
             | code to go", they're "how aggressive do you want the
             | optimizer to be." The most aggressive optimizations are
             | largely unproven and left in O3 until they are generally
             | useful, at which point they move to O2.
        
               | SubjectToChange wrote:
               | More aggressive optimization is necessarily going to be
               | more error prone. In particular, the fact that -O3 is
               | "the path less traveled" means that a higher number of
               | latent bugs exist. That said, if code breaks under -O3,
               | then either it needs to be fixed or a bug report needs to
               | be filed.
        
               | uecker wrote:
               | I would say there is a fair share of cases where
               | programmers were told it is UB when it actually was a
               | compiler bug - or non-conformance.
        
             | o11c wrote:
             | Compiler speed matters. I will confess to not as much
             | practical knowledge of -O3, but -O2 is _usually_ reasonable
             | fast to compile.
             | 
             | For cases where -O2 is too slow to compile, dropping a
             | single nasty TU down to -O1 is often beneficial. -O0 is
             | usually not useful - while faster for tiny TUs, -O1 is
             | still pretty fast for them, and for anything larger, the
             | increased binary size bloat of -O0 is likely to kill your
             | link time compared to -O1's slimness.
             | 
             | Also debuggability matters. GCC's `-O2` is quite debuggable
             | once you learn how to work past the possibility of hitting
             | an <optimized out> (going up a frame or dereferencing a
             | casted register is often all you need); this is unlike
             | Clang, which every time I check still gives up _entirely_.
             | 
             | The real argument is -O1 vs -O2 (since -O1 is a major
             | improvement over -O0 and -O3 is a negligible improvement
             | over -O2) ... I suppose _originally_ I defaulted to -O2
             | because that 's what's generally used by distributions,
             | which compile rarely but run the code often. This differs
             | from development ... but does mean you're staying on the
             | best-tested path (hitting an ICE is pretty common as it
             | is); also, defaulting to -O2 means you _know_ when one of
             | your TUs hits the nasty slowness.
             | 
             | While mostly obsolete now, I have also heard of cases where
             | 32-bit x86 inline asm has difficulty fulfilling constraints
             | under register pressure at low optimization levels.
        
           | alberth wrote:
           | Doesn't -O2 still exclude any CPU features from the past ~15
           | years (like AVX).
           | 
           | If you know the architecture and oldest CPU model, we're
           | better served with added a bunch more flags, no?
           | 
           | I wish I could compile my server code to target CPU released
           | on/after a particular date like:                 -O2 -cpu-
           | newer-than=2019
        
             | SubjectToChange wrote:
             | A CPU produced after a certain date is not guaranteed to
             | have the every ISA extension, e.g. SVE for Arm chips. Hence
             | things like the microarchitecure levels for x86-64.
        
               | cogman10 wrote:
               | For x86 it's a pretty good guarantee.
        
               | teo_zero wrote:
               | I don't understand if your comment is ironic. Intel is
               | notorious for equipping different processors produced in
               | the same period with different features. Sometimes even
               | among different cores on the same chip. Sometimes later
               | products have less features enabled (see e.g. AVX512 for
               | Alder Lake).
        
             | cogman10 wrote:
             | It's not an -O2 thing. Rather it's a -march thing.
             | 
             | -O2 in gcc has vectorization flags set which will use avx
             | if the target CPU supports it. It is less aggressive on
             | vectorization than -O3.
        
             | singron wrote:
             | You can use x86_64-v2 or x86_64-v3. Dates are tricky since
             | cpu features aren't included on all SKUs from all
             | manufacturers on a certain date.
        
           | tmtvl wrote:
           | I'd say _-O2 -march=native -mtune=native_ is good enough, you
           | get (some) AVX without the O3 weirdness.
        
             | pedrocr wrote:
             | That's great if you're compiling for use on the same
             | machine or those exactly like it. If you're compiling
             | binaries for wider distribution it will generate code that
             | some machines can't run and won't take advantage of
             | features in others.
             | 
             | To be able to support multiple arch levels in the same
             | binary I think you still need to do manual work of
             | annotating specific functions where several versions should
             | be generated and dispatched at runtime.
        
           | vlovich123 wrote:
           | You should at a minimum add flags to enable dead object
           | collection (-fdata-sections and -ffunction-sections for
           | compilation and -Wl,--gc-sections for the linker).
        
       | NooneAtAll3 wrote:
       | I don't understand
       | 
       | where is the problem to be solved?
        
         | eapriv wrote:
         | The problem is "to add two numbers". The meta-problem is "to
         | learn how computers work".
        
           | azundo wrote:
           | I think they're expecting a daily problem set like Advent of
           | Code. This is not a set of problems to solve, it's a series
           | with one release per day in December, similar to an Advent
           | calendar.
        
       | ketanmaheshwari wrote:
       | I am personally interested in the code amalgamation technique
       | that SQLite uses[0]. It seems like a free 5-10% performance
       | improvement as is claimed by SQLite folks. Be nice if he
       | addresses it some in one of the sessions.
       | 
       | [0] https://sqlite.org/amalgamation.html
        
         | theresistor wrote:
         | This is a pretty standard topic, and not really a compiler
         | optimization. It's usually called a unity build.
         | 
         | [0] https://en.wikipedia.org/wiki/Unity_build
        
         | nickelpro wrote:
         | Unity builds have been largely supplanted by LTO. They still
         | have uses for build time improvements in one-off builds, as LTO
         | on a non-incremental build is usually slower than the
         | equivalent unity build.
        
           | Sponge5 wrote:
           | At my company, we have not seen any performance benefits from
           | LTO on a GCC cross-compiled Qt application.
           | 
           | GCC version: 11.3 target: Cortex-A9 Qt version: 5.15
           | 
           | I think we tested single core and quad core, also possibly a
           | newer GCC version, but I'm not sure. Just wanted to add my
           | two cents.
        
             | o11c wrote:
             | I would expect a little benefit from devirt (but maybe in-
             | TU optimizations are getting that already?), but if a
             | program is pessimized enough, LTO's improvements won't be
             | measurable.
             | 
             | And programs full of pointer-chasing are quite pessimized;
             | highly-OO code is a common example, which includes almost
             | all GUIs, even in C++.
        
             | gpderetta wrote:
             | Do you link against a version of the Qt library that
             | provides IR objects?
             | 
             | In any case even with whole program optimization, O would
             | expect that effectively devirtualizing an heavily object
             | oriented application to be very hard.
        
           | euroderf wrote:
           | For those of you playing at home, LTO is link-time
           | optimization.
        
       | calibas wrote:
       | Advent of Computer Science Advent Calendars, Day 2
        
         | drob518 wrote:
         | Seems we've reached that point.
        
       | bkallus wrote:
       | I hope he ends up covering integer division by constants. The
       | chapter on this in Hacker's Delight is really good but a little
       | dense for casual readers.
        
       | atgreen wrote:
       | I'm looking forward to the remaining posts. The first thing I did
       | this AM was teach SBCL how to optimize `(+ base (* index scale))`
       | and `(+ base (ash index n))` patterns into single LEA
       | instructions based on the day 2 learnings.
        
       | adamgordonbell wrote:
       | Matt is amazing. After checking out his compiler optimizations,
       | maybe check out the recent interview I did with him.
       | What I've come to believe is this: you should work at a level of
       | abstraction you're comfortable with, but you should also
       | understand the layer beneath it.              If you're a C
       | programmer, you should have some idea of how the C runtime works,
       | and how it interacts with the operating system. You don't need
       | every detail, but you need enough to know what's going on when
       | something breaks. Because one day printf won't work, and if the
       | layer below is a total mystery, you won't even know where to
       | start looking.              So: know one layer well, have working
       | knowledge of the layer under it, and, most importantly, be aware
       | of the shape of the layer below that.
       | 
       | https://corecursive.com/godbolt-rule-matt-godbolt/
       | 
       | Also this article in acmqueue by Matt is not new at all, but
       | super great introduction to these types of optimizations.
       | 
       | https://queue.acm.org/detail.cfm?id=3372264
        
       | badmonster wrote:
       | Advent of Code for compiler nerds. Love this format - daily bite-
       | sized optimization lessons build intuition far better than dense
       | textbooks. Understanding what compilers do and why they do it
       | makes you a better programmer in any language.
        
       ___________________________________________________________________
       (page generated 2025-12-02 23:00 UTC)