Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 52 additions & 14 deletions mlir/docs/DefiningDialects/Assembly.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,42 @@

## Generating Aliases

To reduce verbosity in the resulting assembly, `AsmPrinter` can generate aliases for frequently used types and attributes.
`AsmPrinter` can generate aliases for frequently used types and attributes when not printing them in generic form. For example, `!my_dialect.type<a=3,b=4,c=5,d=tuple,e=another_type>` and `#my_dialect.attr<a=3>` can be aliased to `!my_dialect_type` and `#my_dialect_attr`.

For example, `!my_dialect.type<a=3,b=4,c=5,d=tuple,e=another_type>` and `#my_dialect.attr<a=3>` can be aliased to `!my_dialect_type` and `#my_dialect_attr`, simplifying further references.
There are mainly two ways to hook into the `AsmPrinter`. One is the attribute/type interface and the other is the dialect interface.

To enable this, the owning dialect of these types/attributes can define an interface to hook into the `AsmPrinter`. This is effective only when the assembly is not printed in generic form.
The attribute/type interface is the first hook to check. If no such hook is found, or the hook returns `OverridableAlias` (see definition below), then dialect interfaces are involved.

The dialect interface for one specific dialect could generate alias for all types/attributes, even when it does not "own" them. The `AsmPrinter` checks all dialect interfaces based on their order of registration. For example, the default alias `map` for `builtin` attribute `AffineMapAttr` could be overriden by the dialect interface for `my_dialect` as custom dialect is often registered after the `builtin` dialect.

```cpp
// OpAsmDialectInterface is defined in
// https://github.com/llvm/llvm-project/blob/91ab10e8d6c256d841da1a1a1b47c334e08d95b9/mlir/include/mlir/IR/OpImplementation.h#L1738
/// Holds the result of `OpAsm{Dialect,Attr,Type}Interface::getAlias` hook call.
enum class OpAsmAliasResult {
/// The object (type or attribute) is not supported by the hook
/// and an alias was not provided.
NoAlias,
/// An alias was provided, but it might be overriden by other hook.
OverridableAlias,
/// An alias was provided and it should be used
/// (no other hooks will be checked).
FinalAlias
};
```

If multiple types/attributes have the same alias from `getAlias` hooks, a number is appended to the alias to avoid conflicts.

### `OpAsmDialectInterface`

```cpp
#include "mlir/IR/OpImplementation.h"

struct MyDialectOpAsmDialectInterface : public OpAsmDialectInterface {
public:
using OpAsmDialectInterface::OpAsmDialectInterface;

AliasResult getAlias(Type type, raw_ostream& os) const override {
if (mlir::isa<MyType>(type)) {
os << "my_dialect_type";
// Could return OverridableAlias when
// allowing other dialect to override the alias.
//
// Other dialects are allowed to provide alias for
// type/attribute not owned by them
// but the final result would depend on the registration order
// of these dialects in the MLIRContext
return AliasResult::FinalAlias;
}
return AliasResult::NoAlias;
Expand All @@ -47,8 +60,31 @@ void MyDialect::initialize() {
}
```

* If `getAlias` provides an alias with a trailing digit, `AsmPrinter` appends an underscore to avoid conflicts with autogenerated IDs.
* If multiple types/attributes have the same alias from `getAlias`, a number is appended to the alias to avoid conflicts.
### `OpAsmAttrInterface` and `OpAsmTypeInterface`

The easiest way to use these interfaces is toggling `genMnemonicAlias` in the tablegen file of the attribute/alias. It directly uses the mnemonic as alias. See [Defining Dialect Attributes and Types](/docs/DefiningDialects/AttributesAndTypes) for details.

If a more custom behavior is wanted, the following modification to the attribute/type should be made

1. Add `OpAsmAttrInterface` or `OpAsmTypeInterface` into its trait list.
2. Implement the `getAlias` method, either in tablegen or its cpp file.

```tablegen
include "mlir/IR/OpAsmInterface.td"

// Add OpAsmAttrInterface trait
def MyAttr : MyDialect_Attr<"MyAttr",
[ OpAsmAttrInterface ] > {

// This method could be put in the cpp file.
let extraClassDeclaration = [{
::mlir::OpAsmAliasResult getAlias(::llvm::raw_ostream &os) const {
os << "alias_name";
return ::mlir::OpAsmAliasResult::OverridableAlias;
}
}];
}
```

## Suggesting SSA/Block Names

Expand Down Expand Up @@ -98,6 +134,8 @@ Similarly, an `Operation` can suggest the name for its block arguments using `ge
For custom block names, `OpAsmOpInterface` has a method `getAsmBlockNames` so that
the operation can suggest a custom prefix instead of a generic `^bb0`.

Alternatively, `OpAsmTypeInterface` provides a `getAsmName` method for scenarios where the name could be inferred from its type.

## Defining Default Dialect

An `Operation` can indicate that the nested region in it has a default dialect prefix, and the operations in the region could elide the dialect prefix.
Expand Down
Loading