LmCast :: Stay tuned in

You can't fool the optimizer

Recorded: Dec. 4, 2025, 3:06 a.m.

Original Summarized

You can't fool the optimiser — Matt Godbolt’s blog

Matt Godbolt's blog

Menu

Tags

AI
Amusing Stuff
AoCO2025
Blog
Coding
Compiler Explorer
Emulation
Games
Microarchitecture
New Zealand Trip
Personal
Python
Rants
Rust
WeeBox Project

Archive

AI
Amusing Stuff
AoCO2025
Blog
Coding
Compiler Explorer
Emulation
Games
Microarchitecture
New Zealand Trip
Personal
Python
Rants
Rust
WeeBox Project

About

About me
Contact me

You can't fool the optimiser
Written by me, proof-read by an LLM.
Details at end.
Sometimes you’ll step through code in a debugger and find a complex-looking loop… that executes as a single instruction. The compiler saw through the obfuscation and generated the obvious code anyway.
Consider this assortment of highly questionable unsigned addition routines1 - for variety, here compiled for ARM (unlike yesterday’s addition example).

Despite these all being very different ways of returning x + y, the compiler sees through it all and recognises that it’s just a single add w0, w1, w02 instruction. Even the recursive add_v4 - which calls itself - gets optimised down to the same single instruction3.
The compiler’s ability to recognise patterns and replace them with efficient alternatives - even when the code is pretty obfuscated - is a superpower. It lets programmers choose how to write their code that’s intention-revealing (not like these contrived examples, obviously!) and leave the code generation up to the compiler, knowing that most of the time it’ll do the right thing.
So how does the compiler spot these patterns? Is it maintaining a database of “silly ways to add numbers”? Not quite. Internally, it translates your code into an intermediate representation - a simplified, abstract form that’s easier to analyse. When the compiler sees the while loop in add_v3, it transforms it into something like “increment y by x, then return y”, which it then recognises as mathematically equivalent to “return x + y”. This process of converting different code patterns into a standard, canonical form is what lets the compiler treat them all identically. By the time code generation happens, all four functions look the same to the optimiser4.
This pattern recognition is remarkably robust - the compiler will happily optimise code you’d never want to write in the first place. Throughout this series we’ll see how far this canonicalisation can take us.
See the video that accompanies this post.

This post is day 3 of Advent of Compiler Optimisations 2025,
a 25-day series exploring how compilers transform our code.
This post was written by a human (Matt Godbolt) and reviewed and proof-read by LLMs and humans.
Support Compiler Explorer on Patreon
or GitHub,
or by buying CE products in the Compiler Explorer Shop.

Thanks to long-term Compiler Explorer Patron Greg Baker for this example. ↩

ARM supports three operands, so you should read this as w0 = w1 + w0. ↩

We’ll cover tail-call optimisation and how it enables this later in the series. ↩

You can “Open in Compiler Explorer” the example above and then experiment with the “Opt Pipeline Viewer” to see some of the ways the compiler is doing this. ↩

Permalink

Filed under:

Coding
AoCO2025

Posted at 06:00:00 CST on 3rd December 2025.

About Matt Godbolt

Matt Godbolt is a C++ developer living in Chicago.
He works for Hudson River Trading on super fun but secret things.
He is one half of the Two's Complement podcast.
Follow him on Mastodon
or Bluesky.

Copyright 2007-2025 Matt Godbolt.
Unless otherwise stated, all content is licensed under the
Creative Commons Attribution-Noncommercial 3.0 Unported License.
This blog is powered by the MalcBlogSystem by Malcolm Rowe.
Note: This is my personal website. The views expressed on
these pages are mine alone and almost certainly not those of my employer.

This blog post by Matt Godbolt, published on December 3rd, 2025, delves into a fundamental aspect of compiler optimization: the ability of modern compilers to recognize and eliminate redundant or obfuscated code patterns. The core argument presented is that despite programmers attempting to write complex, intentionally convoluted code – exemplified by the presented “silly ways to add numbers” – the compiler remains capable of identifying these patterns and transforming them into highly efficient, single-instruction equivalents.

Godbolt illustrates this using an ARM assembly example where four distinct functions, each implementing addition, are ultimately reduced to a single instruction. This reduction isn't a result of any specific knowledge the compiler possesses about the programmer’s intent but rather due to its internal process of translating source code into an intermediate representation. This representation facilitates a standardized analysis, enabling the compiler to treat variations of the same logical operation identically. The post highlights the crucial role of this canonicalization process, which transforms diverse code forms into a unified, easily-optimized representation.

The compiler achieves this through a staged transformation process, initially converting the source code – specifically, the 'while' loop within `add_v3` – into a more abstract equivalent: "increment y by x, then return y,” which is then recognized as functionally equivalent to “return x + y”. This demonstrates the compiler's focus on the underlying mathematical concept rather than the specific implementation details. The post specifies the ARM architecture's support for three operands, which is vital to understanding the initial assembly example.

Furthermore, the post introduces the “Opt Pipeline Viewer,” an element within Compiler Explorer, designed to allow users to observe the stages of this optimization process in real-time. This transparency is a key element of Godbolt's approach to illustrating compiler behavior. The post references a broader series called “AoCO2025,” a 25-day exploration of compiler optimizations, suggesting a deeper dive into related techniques, including tail-call optimization, which is to be covered in subsequent installments. Godbolt emphasizes that the compiler’s interpretation relies on recognizing the logical equivalence of the operations, regardless of the initially prescribed form. Essentially, the compiler prioritizes correctness and efficiency, making it capable of optimizing even the most seemingly wasteful programming choices. The post concludes by linking this instance to a larger initiative designed to educate on the intricacies of compiler optimization techniques.