diff --git a/mlir/docs/Canonicalization.md b/mlir/docs/Canonicalization.md --- a/mlir/docs/Canonicalization.md +++ b/mlir/docs/Canonicalization.md @@ -19,15 +19,30 @@ ## General Design -MLIR has a single canonicalization pass, which iteratively applies -canonicalization transformations in a greedy way until the IR converges. These -transformations are defined by the operations themselves, which allows each -dialect to define its own set of operations and canonicalizations together. +MLIR has a single canonicalization pass, which iteratively applies the +canonicalization patterns of all loaded dialects in a greedy way. +Canonicalization is best-effort and not guaranteed to bring the entire IR in a +canonical form. It applies patterns until either fixpoint is reached or the +maximum number of iterations/rewrites (as specified via pass options) is +exhausted. This is for efficiency reasons and to ensure that faulty patterns +cannot cause infinite recursion. + +Canonicalization patterns are registered with the operations themselves, which +allows each dialect to define its own set of operations and canonicalizations +together. Some important things to think about w.r.t. canonicalization patterns: +* Pass pipelines should not rely on the canonicalizer pass for correctness. + They should work correctly with all instances of the canonicalization pass + removed. Separate passes should be used for lowering IR from one level of + abstraction to another one. Such passes can reuse existing canonicalization + patterns. (Ideally only the ones that are actually needed.) + * Repeated applications of patterns should converge. Unstable or cyclic - rewrites will cause infinite loops in the canonicalizer. + rewrites can cause inefficiencies in the canonicalizer pass (i.e., fewer + patterns may be applied) and in the worst case infinite loops if no maximum + number of iterations/rewrites is specified via pass options. * It is generally better to canonicalize towards operations that have fewer uses of a value when the operands are duplicated, because some patterns only diff --git a/mlir/include/mlir/Transforms/Passes.td b/mlir/include/mlir/Transforms/Passes.td --- a/mlir/include/mlir/Transforms/Passes.td +++ b/mlir/include/mlir/Transforms/Passes.td @@ -20,7 +20,11 @@ let summary = "Canonicalize operations"; let description = [{ This pass performs various types of canonicalizations over a set of - operations. See [Operation Canonicalization](Canonicalization.md) for more + operations by iteratively applying the canonicalization patterns of all + loaded dialects until either a fixpoint is reached or the maximum number of + iterations/rewrites is exhausted. Canonicalization is best-effort and does + not guarantee that the entire IR is in a canonical form after running this + pass. See [Operation Canonicalization](Canonicalization.md) for more details. }]; let constructor = "mlir::createCanonicalizerPass()"; diff --git a/mlir/lib/Transforms/Canonicalizer.cpp b/mlir/lib/Transforms/Canonicalizer.cpp --- a/mlir/lib/Transforms/Canonicalizer.cpp +++ b/mlir/lib/Transforms/Canonicalizer.cpp @@ -57,6 +57,7 @@ config.enableRegionSimplification = enableRegionSimplification; config.maxIterations = maxIterations; config.maxNumRewrites = maxNumRewrites; + // Canonicalization is best-effort. Non-convergence is not a pass failure. (void)applyPatternsAndFoldGreedily(getOperation(), patterns, config); }