diff --git a/mlir/docs/DefiningDialects/Assembly.md b/mlir/docs/DefiningDialects/Assembly.md index aa6272e87358..1c00d5ea9ee9 100644 --- a/mlir/docs/DefiningDialects/Assembly.md +++ b/mlir/docs/DefiningDialects/Assembly.md @@ -4,15 +4,35 @@ ## 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` and `#my_dialect.attr` can be aliased to `!my_dialect_type` and `#my_dialect_attr`. -For example, `!my_dialect.type` and `#my_dialect.attr` 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; @@ -20,13 +40,6 @@ struct MyDialectOpAsmDialectInterface : public OpAsmDialectInterface { AliasResult getAlias(Type type, raw_ostream& os) const override { if (mlir::isa(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; @@ -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 @@ -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.