[Mlir-commits] [mlir] b5614ce - Enable printing newlines and indents in attribute and type printers (#87948)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Jan 5 05:05:17 PST 2026
Author: Jacenty Andruszkiewicz
Date: 2026-01-05T15:05:12+02:00
New Revision: b5614ce13ff26f9f8ad90f3dfbce123f21265e03
URL: https://github.com/llvm/llvm-project/commit/b5614ce13ff26f9f8ad90f3dfbce123f21265e03
DIFF: https://github.com/llvm/llvm-project/commit/b5614ce13ff26f9f8ad90f3dfbce123f21265e03.diff
LOG: Enable printing newlines and indents in attribute and type printers (#87948)
This commit moves the code responsible for adding newlines and tracking
indent, so that it can be used not only for operation printers, but also
for attribute and type printers.
It could be useful for nested attributes, where proper formatting with
newlines and indents would benefit the readability of the IR. Currently,
everything is printed on one line, which makes it difficult to read if
the attribute is more verbose and there are multiple levels of nesting.
Co-authored-by: Andruszkiewicz, Jacenty <andruszkiewicz.jacenty at intel.com>
Added:
Modified:
mlir/docs/DefiningDialects/AttributesAndTypes.md
mlir/include/mlir/IR/OpImplementation.h
mlir/lib/IR/AsmPrinter.cpp
mlir/test/lib/Dialect/Test/TestAttrDefs.td
mlir/test/lib/Dialect/Test/TestAttributes.cpp
mlir/test/lib/Dialect/Test/TestTypeDefs.td
mlir/test/lib/Dialect/Test/TestTypes.cpp
mlir/test/mlir-tblgen/testdialect-attrdefs.mlir
mlir/test/mlir-tblgen/testdialect-typedefs.mlir
mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.cpp
Removed:
################################################################################
diff --git a/mlir/docs/DefiningDialects/AttributesAndTypes.md b/mlir/docs/DefiningDialects/AttributesAndTypes.md
index b99186391d710..5d9744462a4b1 100644
--- a/mlir/docs/DefiningDialects/AttributesAndTypes.md
+++ b/mlir/docs/DefiningDialects/AttributesAndTypes.md
@@ -565,6 +565,11 @@ For Attributes, these methods will have the form:
- `void MyAttr::print(AsmPrinter &p) const`
+It is possible to use newlines and indents in custom `print` methods.
+However, multiline Types or Attributes are not recommended nor allowed in the upstream MLIR dialects.
+They can be used in custom dialects to improve flexibility and readability, e.g. in cases of
+multiple nested Types and Attributes.
+
#### Using `assemblyFormat`
Attributes and types defined in ODS with a mnemonic can define an
diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h
index d70aa346eaa1f..f16247657809a 100644
--- a/mlir/include/mlir/IR/OpImplementation.h
+++ b/mlir/include/mlir/IR/OpImplementation.h
@@ -130,6 +130,18 @@ class AsmPrinter {
/// Return the raw output stream used by this printer.
virtual raw_ostream &getStream() const;
+ /// Print a newline and indent the printer to the start of the current
+ /// operation/attribute/type.
+ /// Note: For attributes and types this method should only be used in
+ /// custom dialects. Usage in upstream MLIR dialects is currently disallowed.
+ virtual void printNewline();
+
+ /// Increase indentation.
+ virtual void increaseIndent();
+
+ /// Decrease indentation.
+ virtual void decreaseIndent();
+
/// Print the given floating point value in a stabilized form that can be
/// roundtripped through the IR. This is the companion to the 'parseFloat'
/// hook on the AsmParser.
@@ -448,16 +460,6 @@ class OpAsmPrinter : public AsmPrinter {
/// Print a loc(...) specifier if printing debug info is enabled.
virtual void printOptionalLocationSpecifier(Location loc) = 0;
- /// Print a newline and indent the printer to the start of the current
- /// operation.
- virtual void printNewline() = 0;
-
- /// Increase indentation.
- virtual void increaseIndent() = 0;
-
- /// Decrease indentation.
- virtual void decreaseIndent() = 0;
-
/// Print a block argument in the usual format of:
/// %ssaName : type {attr1=42} loc("here")
/// where location printing is controlled by the standard internal option.
diff --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index 7f0eed0366d19..e2f36ff37883b 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -418,6 +418,21 @@ class AsmPrinter::Impl {
/// Returns the output stream of the printer.
raw_ostream &getStream() { return os; }
+ /// Print a newline and indent the printer to the start of the current
+ /// operation/attribute/type.
+ /// Note: For attributes and types this method should only be used in
+ /// custom dialects. Usage in MLIR dialects is disallowed.
+ void printNewline() {
+ os << newLine;
+ os.indent(currentIndent);
+ }
+
+ /// Increase indentation.
+ void increaseIndent() { currentIndent += indentWidth; }
+
+ /// Decrease indentation.
+ void decreaseIndent() { currentIndent -= indentWidth; }
+
template <typename Container, typename UnaryFunctor>
inline void interleaveComma(const Container &c, UnaryFunctor eachFn) const {
llvm::interleaveComma(c, os, eachFn);
@@ -532,6 +547,12 @@ class AsmPrinter::Impl {
/// A tracker for the number of new lines emitted during printing.
NewLineCounter newLine;
+
+ /// The number of spaces used as an indent.
+ const static unsigned indentWidth = 2;
+
+ /// This is the current indentation level for nested structures.
+ unsigned currentIndent = 0;
};
} // namespace mlir
@@ -1004,6 +1025,9 @@ class DummyAliasDialectAsmPrinter : public DialectAsmPrinter {
/// The following are hooks of `DialectAsmPrinter` that are not necessary for
/// determining potential aliases.
+ void printNewline() override {}
+ void increaseIndent() override {}
+ void decreaseIndent() override {}
void printFloat(const APFloat &) override {}
void printKeywordOrString(StringRef) override {}
void printString(StringRef) override {}
@@ -2907,6 +2931,13 @@ void AsmPrinter::Impl::printDialectAttribute(Attribute attr) {
{
llvm::raw_string_ostream attrNameStr(attrName);
Impl subPrinter(attrNameStr, state);
+
+ // The values of currentIndent and newLine are assigned to the created
+ // subprinter, so that the indent level and number of printed lines can be
+ // tracked.
+ subPrinter.currentIndent = currentIndent;
+ subPrinter.newLine = newLine;
+
DialectAsmPrinter printer(subPrinter);
dialect.printAttribute(attr, printer);
}
@@ -2921,6 +2952,13 @@ void AsmPrinter::Impl::printDialectType(Type type) {
{
llvm::raw_string_ostream typeNameStr(typeName);
Impl subPrinter(typeNameStr, state);
+
+ // The values of currentIndent and newLine are assigned to the created
+ // subprinter, so that the indent level and number of printed lines can be
+ // tracked.
+ subPrinter.currentIndent = currentIndent;
+ subPrinter.newLine = newLine;
+
DialectAsmPrinter printer(subPrinter);
dialect.printType(type, printer);
}
@@ -2961,6 +2999,21 @@ raw_ostream &AsmPrinter::getStream() const {
return impl->getStream();
}
+void AsmPrinter::printNewline() {
+ assert(impl && "expected AsmPrinter::printNewLine to be overriden");
+ impl->printNewline();
+}
+
+void AsmPrinter::increaseIndent() {
+ assert(impl && "expected AsmPrinter::increaseIndent to be overriden");
+ impl->increaseIndent();
+}
+
+void AsmPrinter::decreaseIndent() {
+ assert(impl && "expected AsmPrinter::decreaseIndent to be overriden");
+ impl->decreaseIndent();
+}
+
/// Print the given floating point value in a stablized form.
void AsmPrinter::printFloat(const APFloat &value) {
assert(impl && "expected AsmPrinter::printFloat to be overriden");
@@ -3291,19 +3344,6 @@ class OperationPrinter : public AsmPrinter::Impl, private OpAsmPrinter {
printTrailingLocation(loc);
}
- /// Print a newline and indent the printer to the start of the current
- /// operation.
- void printNewline() override {
- os << newLine;
- os.indent(currentIndent);
- }
-
- /// Increase indentation.
- void increaseIndent() override { currentIndent += indentWidth; }
-
- /// Decrease indentation.
- void decreaseIndent() override { currentIndent -= indentWidth; }
-
/// Print a block argument in the usual format of:
/// %ssaName : type {attr1=42} loc("here")
/// where location printing is controlled by the standard internal option.
@@ -3429,12 +3469,6 @@ class OperationPrinter : public AsmPrinter::Impl, private OpAsmPrinter {
// top-level we start with "builtin" as the default, so that the top-level
// `module` operation prints as-is.
SmallVector<StringRef> defaultDialectStack{"builtin"};
-
- /// The number of spaces used for indenting nested operations.
- const static unsigned indentWidth = 2;
-
- // This is the current indentation level for nested structures.
- unsigned currentIndent = 0;
};
} // namespace
diff --git a/mlir/test/lib/Dialect/Test/TestAttrDefs.td b/mlir/test/lib/Dialect/Test/TestAttrDefs.td
index cfbeee6d91edb..4cf8364252561 100644
--- a/mlir/test/lib/Dialect/Test/TestAttrDefs.td
+++ b/mlir/test/lib/Dialect/Test/TestAttrDefs.td
@@ -478,4 +478,10 @@ def TestSymbolRefAttr : Test_Attr<"TestSymbolRef",
let assemblyFormat = "`<` $symbol `>`";
}
+def TestAttrNewlineAndIndent : Test_Attr<"TestAttrNewlineAndIndent"> {
+ let mnemonic = "newline_and_indent";
+ let parameters = (ins "::mlir::Type":$indentType);
+ let hasCustomAssemblyFormat = 1;
+}
+
#endif // TEST_ATTRDEFS
diff --git a/mlir/test/lib/Dialect/Test/TestAttributes.cpp b/mlir/test/lib/Dialect/Test/TestAttributes.cpp
index 0576809ccdebd..9e20a95c12b42 100644
--- a/mlir/test/lib/Dialect/Test/TestAttributes.cpp
+++ b/mlir/test/lib/Dialect/Test/TestAttributes.cpp
@@ -453,6 +453,30 @@ bool TestConstMemorySpaceAttr::isValidPtrIntCast(
return false;
}
+//===----------------------------------------------------------------------===//
+// TestAttrNewlineAndIndent
+//===----------------------------------------------------------------------===//
+
+Attribute TestAttrNewlineAndIndentAttr::parse(::mlir::AsmParser &parser,
+ ::mlir::Type type) {
+ Type indentType;
+ if (parser.parseLess() || parser.parseType(indentType) ||
+ parser.parseGreater()) {
+ return Attribute();
+ }
+ return get(parser.getContext(), indentType);
+}
+
+void TestAttrNewlineAndIndentAttr::print(::mlir::AsmPrinter &printer) const {
+ printer << "<";
+ printer.increaseIndent();
+ printer.printNewline();
+ printer << getIndentType();
+ printer.decreaseIndent();
+ printer.printNewline();
+ printer << ">";
+}
+
//===----------------------------------------------------------------------===//
// Tablegen Generated Definitions
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/lib/Dialect/Test/TestTypeDefs.td b/mlir/test/lib/Dialect/Test/TestTypeDefs.td
index 9859bd06cb526..d840339a09266 100644
--- a/mlir/test/lib/Dialect/Test/TestTypeDefs.td
+++ b/mlir/test/lib/Dialect/Test/TestTypeDefs.td
@@ -477,4 +477,9 @@ def TestBaseBody : Test_Type<"TestBaseBody",
let mnemonic = "test_base_body";
}
+def TestTypeNewlineAndIndent : Test_Type<"TestTypeNewlineAndIndent"> {
+ let mnemonic = "newline_and_indent";
+ let hasCustomAssemblyFormat = 1;
+}
+
#endif // TEST_TYPEDEFS
diff --git a/mlir/test/lib/Dialect/Test/TestTypes.cpp b/mlir/test/lib/Dialect/Test/TestTypes.cpp
index 9cf64a896d28a..71dd25b0093e0 100644
--- a/mlir/test/lib/Dialect/Test/TestTypes.cpp
+++ b/mlir/test/lib/Dialect/Test/TestTypes.cpp
@@ -583,3 +583,25 @@ ::mlir::LogicalResult TestTensorType::verifyCompatibleBufferType(
return emitError() << "expected MemRefType or TestMemrefType";
}
+
+//===----------------------------------------------------------------------===//
+// TestTypeNewlineAndIndent
+//===----------------------------------------------------------------------===//
+
+Type TestTypeNewlineAndIndentType::parse(::mlir::AsmParser &parser) {
+ if (parser.parseLess() || parser.parseKeyword("indented_content") ||
+ parser.parseGreater()) {
+ return Type();
+ }
+ return get(parser.getContext());
+}
+
+void TestTypeNewlineAndIndentType::print(::mlir::AsmPrinter &printer) const {
+ printer << "<";
+ printer.increaseIndent();
+ printer.printNewline();
+ printer << "indented_content";
+ printer.decreaseIndent();
+ printer.printNewline();
+ printer << ">";
+}
diff --git a/mlir/test/mlir-tblgen/testdialect-attrdefs.mlir b/mlir/test/mlir-tblgen/testdialect-attrdefs.mlir
index 89ad3594eebd8..dca46a30e37f1 100644
--- a/mlir/test/mlir-tblgen/testdialect-attrdefs.mlir
+++ b/mlir/test/mlir-tblgen/testdialect-attrdefs.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt %s -split-input-file -verify-diagnostics | FileCheck %s
+// RUN: mlir-opt %s -split-input-file -verify-diagnostics | FileCheck %s --strict-whitespace
// CHECK-LABEL: func private @compoundA()
// CHECK-SAME: #test.cmpnd_a<1, !test.smpla, [5, 6]>
@@ -44,3 +44,19 @@ func.func private @hexdecimalInteger() attributes {
// expected-error @below {{expected an integer}}
sdg = #test.decimal_shape<1x0xb>
}
+
+// -----
+
+// CHECK-LABEL: @newlineAndIndent
+// CHECK-SAME: indent = #test.newline_and_indent<
+// CHECK-NEXT: {{^ }}!test.newline_and_indent<
+// CHECK-NEXT: {{^ }}indented_content
+// CHECK-NEXT: {{^ }}>
+// CHECK-NEXT: {{^ }}>
+func.func private @newlineAndIndent() attributes {
+ indent = #test.newline_and_indent<
+ !test.newline_and_indent<
+ indented_content
+ >
+ >
+}
diff --git a/mlir/test/mlir-tblgen/testdialect-typedefs.mlir b/mlir/test/mlir-tblgen/testdialect-typedefs.mlir
index 18175edc81cf0..c00d368fdab8b 100644
--- a/mlir/test/mlir-tblgen/testdialect-typedefs.mlir
+++ b/mlir/test/mlir-tblgen/testdialect-typedefs.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt %s | mlir-opt -verify-diagnostics | FileCheck %s
+// RUN: mlir-opt %s | mlir-opt -verify-diagnostics | FileCheck %s --strict-whitespace
//////////////
// Tests the types in the 'Test' dialect, not the ones in 'typedefs.mlir'
@@ -42,3 +42,13 @@ func.func @testInt(%A : !test.int<s, 8>, %B : !test.int<unsigned, 2>, %C : !test
func.func @structTest (%A : !test.struct< {field1, !test.smpla}, {field2, !test.int<none, 3>} > ) {
return
}
+
+// CHECK-LABEL: @newlineAndIndent
+// CHECK-SAME: !test.newline_and_indent<
+// CHECK-NEXT: {{^ }}indented_content
+// CHECK-NEXT: {{^ }}>
+func.func @newlineAndIndent(%A : !test.newline_and_indent<
+ indented_content
+>) {
+ return
+}
diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.cpp
index 34547e9fed062..d3c0f68d8efae 100644
--- a/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.cpp
+++ b/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.cpp
@@ -956,9 +956,7 @@ void DefFormat::genOptionalGroupPrinter(OptionalElement *el, FmtContext &ctx,
void DefFormat::genWhitespacePrinter(WhitespaceElement *el, FmtContext &ctx,
MethodBody &os) {
if (el->getValue() == "\\n") {
- // FIXME: The newline should be `printer.printNewLine()`, i.e., handled by
- // the printer.
- os << tgfmt("$_printer << '\\n';\n", &ctx);
+ os << tgfmt("$_printer.printNewline();\n", &ctx);
} else if (!el->getValue().empty()) {
os << tgfmt("$_printer << \"$0\";\n", &ctx, el->getValue());
} else {
More information about the Mlir-commits
mailing list