I have been digging into some of the SCF canonicalization and transformation passes, and I have a question about the general design choice of some of these patterns. Mainly, when do we create a rewrite pattern and apply it as a canonicalization, when do we just use a rewrite pattern as a pass, and when do we use a more generalized function/operation pass that does some rewriting?
For example, the canonicalizations in SCF.cpp (say SimplifyTrivialLoops) use the pattern rewriter, but LoopInvariantCodeMotion does not. It also looks like the former is not inserted into the MLIR lowering pipeline at any point I can see. Is it instead meant to be run by clients of MLIR who decide when to perform the loop invariant code motion operation, whereas the canonicalizations are meant to be used both within/external to various MLIR lowerings?