[Mlir-commits] [mlir] [MLIR][Linalg][Docs] Add forms to Linalg rationale docs (PR #156859)
Renato Golin
llvmlistbot at llvm.org
Wed Oct 1 06:18:16 PDT 2025
================
@@ -506,6 +506,58 @@ potential by introducing lower-level IR ops and *smaller* Linalg ops.
This gradually reduces the potential, all the way to Loops + VectorOps
and LLVMIR.
+### Interchangeability of Forms<a name="forms"></a>
+
+#### The Linalg Forms
+
+The core Linalg operation tree has three forms:
+* **Generic:** Represented by `linalg.generic` and can encode all perfectly-nested
+loop operations.
+* **Category:** Represented by `linalg.contract` and `linalg.elementwise`,
+which are special (einsum) forms of the `generic` operation. In the future, other
+category operations are planned (e.g.: `linalg.convolution` and `linalg.pooling`).
+* **Named:** All _named_ forms that can lower to either _category_ or
+_generic_ forms. For example, `linalg.matmul`, `linalg.add`, etc.
+
+Unlike lowering to loops, the different Linalg forms that are derived from
+`linalg.generic` are *equivalent*. It should always be possible to convert
+a named operation into a generic and back to named, if the semantics are
+preserved. The various forms in the Linalg dialect are meant to facilitate
+pattern matching (single operations or DAGs) and to be able to consider
+different forms as *canonical* for different transforms.
+
+In addition to the three forms above, there's a separate class that does not
+belong to the tree, as it does not generalize. These are **composite:** operations
+that compose multiple Linalg operations, for example `linalg.softmax` and
+`linalg.winograd*`. These can be converted to a DAG of Linalg operations.
+
+Linalg's various forms (named, generic) also carry information, and that
+information should be preserved as much as possible during the progressive
+lowering. A `matmul` operation is a special case of a `contract` operation,
+which in turn is a special case of `generic` operation. Transformations on
+the more special forms should not be converted to the more generic ones
+unnecessarily, in the same way that they should not be broken down into
+loops + arithmetic if they can still be represented as a Linalg op.
+
+#### Canonical Forms<a name="canonical_forms"></a>
+
+With multiple (often exchangeable) forms, and with transformation simplicity
+in mind, compilers should aim for reducing matching and replacing complexity
+as much as possible. When matching a single operation with a complex pattern,
+having all the information in a `generic` is useful to iteratively match
+different patterns in turn. However, when assembling a DAG of operations to
----------------
rengolin wrote:
If you get a named op from the front-end, life is simple. But if you get a `generic`, you have to make choices.
You can:
1. run a pass to convert to a named op (currently `O(num_gen_attr x num_named_ops)`) and then match against that.
2. iteratively match each generic attribute to a precise form (`O(num_gen_attr)` only) and match directly.
The first approach is helpful if you have a lot of different forms and want to _normalize_ to a canonical form that your passes expect. One-off cost at the beginning of the pipeline, no cost later on.
The second approach is much faster if only a single pass needs to look at that operation (or multiple passes, one for each operation in different forms), since you match one attribute at a time with a particular pattern (not a list of all patterns).
Makes sense?
https://github.com/llvm/llvm-project/pull/156859
More information about the Mlir-commits
mailing list