The boring answer: it really is just hardcoded
The answer to the general question of “how do compilers recognize optimizable patterns?” would be large enough to fill a book. Certainly, there are lots of techniques that could be used to apply this type of optimization. However, in this particular case, the answer is sadly rather boring: the compiler really does look for a more-or-less hardcoded pattern.
In LLVM, this optimization was added in 2019, and the given rationale was that this particular implementation of popcount is a particularly common idiom. I haven’t personally investigated the extent to which this is true, but the author cites Hacker’s Delight as the source of the pattern they’ve chosen to recognize. The optimization is performed as part of LLVM’s aggressive-instcombine pass, which “combines expression patterns to form expressions with fewer, simple instructions.” Essentially, it is a slightly more sophisticated variation on peephole optimization.
In the code, the appropriately-named tryToRecognizePopcount
function implements the detection, and it is not particularly sophisticated. In theory, it could do something much fancier, like abstractly interpreting bitwise operations to somehow determine whether the end result implements popcount. However, the actual implementation does not do that: it looks for a sequence of instructions that perform a very particular set of bitwise operations, including the relevant hardcoded constants, and if it doesn’t find the implementation it expects, nothing interesting happens.
Although the approach is quite naïve, it’s worth keeping in mind that this analysis runs after LLVM has already lowered the code to its internal, SSA representation (which inherently involves some normalization), and the code has already been “cleaned up” by other simplifying optimization passes. This means that, though the pattern being scanned for is fairly simple, there is good reason to believe minor variations in the way it’s written in the source code will all be normalized to the same basic shape, as long as they are fundamentally the same algorithm. This increases the likelihood that the optimization will fire.
I did not take the time to investigate how GCC performs this optimization, but kouta-kun’s answer explains that it takes essentially the same approach.
Why take this approach?
Optimizing compilers must consider many tradeoffs when choosing what optimizations to perform and how to implement them. In theory, a compiler could choose to implement a set of extremely sophisticated algorithms to squeeze every last drop of performance from a program, but this is not done in practice, for several reasons:
Program analysis can be expensive, and lengthy compile times make programmers unhappy. Compiler authors must weigh each optimization pass’s compile-time overhead against its runtime benefits, and plenty of optimizations simply don’t pay their weight.
Compilers are complex, constantly-evolving pieces of software. Each change to the internal representation or static analysis framework requires updating every optimization pass to handle the new API, so complex passes can become a substantial maintenance burden. Compiler authors must always consider whether developer time could be better spent elsewhere.
Most compilers run most of their optimization passes on all programs, but not all optimizations are broadly applicable. Even if an optimization pass has the potential to win big on certain programs, it’s not worth significant costs if most programs will never see the benefits.
An advantage of a hardcoded pass is that it’s fairly cheap, and maintenance burden is very low. Even if it only fires on a small subset of programs, the overhead is likely to be so small that it’s in the noise. What’s more, an operation like popcount is likely to appear within inner loops, so on those programs, the performance gains have the potential to be very large.
That said, this optimization is absolutely not representative of optimizations as a whole. Hardcoded patterns are rarely the compiler author’s tool of choice, and popcount is simply an exception. I wouldn’t read into it too much.