Compilers will convert mul/div to shifts, if they notice one of the operands is a power of 2. I would have included a link to an example on compiler explorer (https://godbolt.org/) but the source editor didn't work on my Pinephone for some reason..

Ah, interesting, I’m playing around with it on godbolt and it is doing all the sort of obvious stuff you might expect (division by 2 implemented as a shift, multiplication by 2 or 3 represented as adds, etc). You are right.

For some reason this was in my head as one of those “surprisingly, optimizing compilers might skip it” situations (like loop unrolling). Dunno where I picked that up.

I think the trick is to make sure the compiler knows you are doing the math with a constant and such? They likely won't branch on arbitrary numbers to sometimes do it as a shift and other times do the multiplication. But compilers for a long time would propagate constants through and pick a faster option for basic a*2.