Observation in comments
Interestingly, it feels like there's a trend in compiler research to go in the opposite direction: a very small number of passes, where each pass applies every single item of a class of optimizations until fixpoint.
So instead of "merge_shifts -> replace_muls_with_shifts -> merge_shifts -> constant_fold -> merge_muls -> etc", you'd maybe have "constant_fold_and_merge_shifts_and_replace_mul_with_shifts".
I'm thinking especially of:
- egraphs: https://www.youtube.com/watch?v=m001XqQKyCQ&t=61s
- RVSDGs: https://www.sjalander.com/research/pdf/sjalander-tecs2020.pd...
Part of the trick is having a representation where some optimizations are a trivial property of the representation's structure, so more fixpoint passes can be replaced with forward passes (constructing and destructing the advanced representation).