Skip to content

Commit 70d7c84

Browse files
[mlir][docs] Add usage/example of OpAsmOpInterface (llvm#123610)
This is part of https://discourse.llvm.org/t/rfc-introduce-opasm-type-attr-interface-for-pretty-print-in-asmprinter/83792. OpAsmOpInterface controls the SSA Name/Block Name and Default Dialect Prefix. This PR adds the usage of them by existing examples in MLIR.
1 parent 091741a commit 70d7c84

File tree

1 file changed

+76
-1
lines changed

1 file changed

+76
-1
lines changed

mlir/docs/DefiningDialects/Assembly.md

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,79 @@ void MyDialect::initialize() {
4848
```
4949
5050
* If `getAlias` provides an alias with a trailing digit, `AsmPrinter` appends an underscore to avoid conflicts with autogenerated IDs.
51-
* If multiple types/attributes have the same alias from `getAlias`, a number is appended to the alias to avoid conflicts.
51+
* If multiple types/attributes have the same alias from `getAlias`, a number is appended to the alias to avoid conflicts.
52+
53+
## Suggesting SSA/Block Names
54+
55+
An `Operation` can suggest the SSA name prefix using `OpAsmOpInterface`.
56+
57+
For example, `arith.constant` will suggest a name like `%c42_i32` for its result:
58+
59+
```tablegen
60+
include "mlir/IR/OpAsmInterface.td"
61+
62+
def Arith_ConstantOp : Op<Arith_Dialect, "constant",
63+
[ConstantLike, Pure,
64+
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>]> {
65+
...
66+
}
67+
```
68+
69+
And the corresponding method:
70+
71+
```cpp
72+
// from https://github.com/llvm/llvm-project/blob/5ce271ef74dd3325993c827f496e460ced41af11/mlir/lib/Dialect/Arith/IR/ArithOps.cpp#L184
73+
void arith::ConstantOp::getAsmResultNames(
74+
function_ref<void(Value, StringRef)> setNameFn) {
75+
auto type = getType();
76+
if (auto intCst = llvm::dyn_cast<IntegerAttr>(getValue())) {
77+
auto intType = llvm::dyn_cast<IntegerType>(type);
78+
79+
// Sugar i1 constants with 'true' and 'false'.
80+
if (intType && intType.getWidth() == 1)
81+
return setNameFn(getResult(), (intCst.getInt() ? "true" : "false"));
82+
83+
// Otherwise, build a complex name with the value and type.
84+
SmallString<32> specialNameBuffer;
85+
llvm::raw_svector_ostream specialName(specialNameBuffer);
86+
specialName << 'c' << intCst.getValue();
87+
if (intType)
88+
specialName << '_' << type;
89+
setNameFn(getResult(), specialName.str());
90+
} else {
91+
setNameFn(getResult(), "cst");
92+
}
93+
}
94+
```
95+
96+
Similarly, an `Operation` can suggest the name for its block arguments using `getAsmBlockArgumentNames` method in `OpAsmOpInterface`.
97+
98+
For custom block names, `OpAsmOpInterface` has a method `getAsmBlockNames` so that
99+
the operation can suggest a custom prefix instead of a generic `^bb0`.
100+
101+
## Defining Default Dialect
102+
103+
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.
104+
105+
For example, in a `func.func` op all `func` prefix could be omitted:
106+
107+
```tablegen
108+
include "mlir/IR/OpAsmInterface.td"
109+
110+
def FuncOp : Func_Op<"func", [
111+
OpAsmOpInterface
112+
...
113+
]> {
114+
let extraClassDeclaration = [{
115+
/// Allow the dialect prefix to be omitted.
116+
static StringRef getDefaultDialect() { return "func"; }
117+
}];
118+
}
119+
```
120+
121+
```mlir
122+
func.func @main() {
123+
// actually func.call
124+
call @another()
125+
}
126+
```

0 commit comments

Comments
 (0)