From 70d7c847fd1b73c8bb453eac11a4a1ae03bb0d86 Mon Sep 17 00:00:00 2001 From: Hongren Zheng Date: Thu, 23 Jan 2025 16:37:46 +0800 Subject: [PATCH] [mlir][docs] Add usage/example of OpAsmOpInterface (#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. --- mlir/docs/DefiningDialects/Assembly.md | 77 +++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/mlir/docs/DefiningDialects/Assembly.md b/mlir/docs/DefiningDialects/Assembly.md index d69349390ee3..aa6272e87358 100644 --- a/mlir/docs/DefiningDialects/Assembly.md +++ b/mlir/docs/DefiningDialects/Assembly.md @@ -48,4 +48,79 @@ 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. \ No newline at end of file +* If multiple types/attributes have the same alias from `getAlias`, a number is appended to the alias to avoid conflicts. + +## Suggesting SSA/Block Names + +An `Operation` can suggest the SSA name prefix using `OpAsmOpInterface`. + +For example, `arith.constant` will suggest a name like `%c42_i32` for its result: + +```tablegen +include "mlir/IR/OpAsmInterface.td" + +def Arith_ConstantOp : Op]> { +... +} +``` + +And the corresponding method: + +```cpp +// from https://github.com/llvm/llvm-project/blob/5ce271ef74dd3325993c827f496e460ced41af11/mlir/lib/Dialect/Arith/IR/ArithOps.cpp#L184 +void arith::ConstantOp::getAsmResultNames( + function_ref setNameFn) { + auto type = getType(); + if (auto intCst = llvm::dyn_cast(getValue())) { + auto intType = llvm::dyn_cast(type); + + // Sugar i1 constants with 'true' and 'false'. + if (intType && intType.getWidth() == 1) + return setNameFn(getResult(), (intCst.getInt() ? "true" : "false")); + + // Otherwise, build a complex name with the value and type. + SmallString<32> specialNameBuffer; + llvm::raw_svector_ostream specialName(specialNameBuffer); + specialName << 'c' << intCst.getValue(); + if (intType) + specialName << '_' << type; + setNameFn(getResult(), specialName.str()); + } else { + setNameFn(getResult(), "cst"); + } +} +``` + +Similarly, an `Operation` can suggest the name for its block arguments using `getAsmBlockArgumentNames` method in `OpAsmOpInterface`. + +For custom block names, `OpAsmOpInterface` has a method `getAsmBlockNames` so that +the operation can suggest a custom prefix instead of a generic `^bb0`. + +## 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. + +For example, in a `func.func` op all `func` prefix could be omitted: + +```tablegen +include "mlir/IR/OpAsmInterface.td" + +def FuncOp : Func_Op<"func", [ + OpAsmOpInterface + ... +]> { + let extraClassDeclaration = [{ + /// Allow the dialect prefix to be omitted. + static StringRef getDefaultDialect() { return "func"; } + }]; +} +``` + +```mlir +func.func @main() { + // actually func.call + call @another() +} +```