-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[MLIR][Linalg][Docs] Add forms to Linalg rationale docs #156859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ea79844
7ea9ca0
e57ef2e
6f161cd
e746daa
31f352f
1d4933d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -506,6 +506,72 @@ 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 set has four forms: | ||
* **Generic:** Represented by `linalg.generic` and can encode all perfectly-nested | ||
loop operations. | ||
* **Category:** For example, `linalg.contract` and `linalg.elementwise`, that encode | ||
higher-level semantics of a `linalg.generic` while still representing multiple _named_ | ||
operations via attributes and syntax. In the future, other category operations are | ||
planned (e.g.: `linalg.convolution` and `linalg.pooling`). | ||
* **Named:** For example, `linalg.matmul`, `linalg.add`, etc. All _named_ forms that | ||
can be converted to either a single _category_ or _generic_ forms, ie. are _perfectly nested_. | ||
* **Composite:** For example `linalg.softmax` and the `winograd` variations. These | ||
operations are not perfectly nested, and are converted to a list of other operations | ||
(of various dialects). | ||
|
||
The forms correlate in the following manner: | ||
``` | ||
+ generic | ||
\__ + category | ||
\__ + named | ||
+ composite | ||
``` | ||
|
||
The `category` and `named` forms are derived from `linalg.generic` and are *equivalent*. | ||
It should always be possible to convert a `named` operation into a `category` and that | ||
into a `generic` and back to `named`. However, it may not be possible to convert a | ||
`generic` into a `named` if there is no such `named` form. | ||
|
||
`Composite` operations cannot be converted to the other three classes and forms a | ||
sub-set on its own. But they can use other Linalg forms when expanding. There can be | ||
a pattern-matching transform to detect a graph of operations and convert into a | ||
`composite` operation. | ||
|
||
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. | ||
|
||
Linalg's various forms 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 | ||
Comment on lines
+560
to
+562
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, would I ever want to (or need to) match There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you get a named op from the front-end, life is simple. But if you get a You can:
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? |
||
form a pattern, it's much simpler to match against named operations (like | ||
`max` + `div` + `reduce` + `broadcast`) than their generic counterparts. | ||
|
||
This is where the interchangeability of forms comes in handy. Linalg has the | ||
ability to specialize and generalize in order to convert the IR to a form that | ||
is easier for a particular type of transform. With forms being semantically | ||
equivalent, one can convert back-and-forth throughout the various transforms | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this an actual conversion or matching on interface? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actual conversion. We have discussed interfaces last year (the forum links in this PR), but the agreement was to keep using forms for now and see if we can generalize to interfaces later. Having the forms may be a bit too verbose, but it will give us enough data on how to design the interfaces if we end up doing it. |
||
to match the needs of each transform. For that particular transform, such | ||
form can be considered _canonical_ and therefore "expected" for the pattern | ||
to _match_. This reduces complexity of pattern matchers and simplifies compiler | ||
pipelines. | ||
|
||
rengolin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
### Composable and Declarative Transformations<a name="declarative_transformations"></a> | ||
Complex and impactful transformations need not be hard to manipulate, write or | ||
maintain. Mixing XLA-style high-level op semantics knowledge with generic | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this about the ops being converted or the transformations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both?
The idea is that "ops being converted" help simplify "transformations". So additional conversions between transformations can help if they assume different canonical forms. But IF and only IF the forms are semantically equivalent, thus, linalg forms.