Skip to content

Commit 63f0c00

Browse files
committed
Add a qualified directive to the Op, Attribute, and Type declarative assembly format
This patch introduces a new directive that allow to parse/print attributes and types fully qualified. This is a follow-up to ee09087 which introduces the eliding of the `!dialect.mnemonic` by default and allows to force to fully qualify each type/attribute individually. Differential Revision: https://reviews.llvm.org/D116905
1 parent 140a6b1 commit 63f0c00

File tree

12 files changed

+202
-12
lines changed

12 files changed

+202
-12
lines changed

mlir/docs/OpDefinitions.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,16 @@ The available directives are as follows:
651651
- `input` must be either an operand or result [variable](#variables), the
652652
`operands` directive, or the `results` directive.
653653

654+
* `qualified` ( type_or_attribute )
655+
656+
- Wraps a `type` directive or an attribute parameter.
657+
- Used to force printing the type or attribute prefixed with its dialect
658+
and mnemonic. For example the `vector.multi_reduction` operation has a
659+
`kind` attribute ; by default the declarative assembly will print:
660+
`vector.multi_reduction <minf>, ...` but using `qualified($kind)` in the
661+
declarative assembly format will print it instead as:
662+
`vector.multi_reduction #vector.kind<minf>, ...`.
663+
654664
#### Literals
655665

656666
A literal is either a keyword or punctuation surrounded by \`\`.

mlir/docs/Tutorials/DefiningAttributesAndTypes.md

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -489,9 +489,11 @@ for these parameters are expected to return `FailureOr<$cppStorageType>`.
489489

490490
Attribute and type assembly formats have the following directives:
491491

492-
* `params`: capture all parameters of an attribute or type.
493-
* `struct`: generate a "struct-like" parser and printer for a list of key-value
494-
pairs.
492+
* `params`: capture all parameters of an attribute or type.
493+
* `qualified`: mark a parameter to be printed with its leading dialect and
494+
mnemonic.
495+
* `struct`: generate a "struct-like" parser and printer for a list of
496+
key-value pairs.
495497

496498
#### `params` Directive
497499

@@ -517,6 +519,34 @@ The `params` directive can also be passed to other directives, such as `struct`,
517519
as an argument that refers to all parameters in place of explicitly listing all
518520
parameters as variables.
519521

522+
#### `qualified` Directive
523+
524+
This directive can be used to wrap attribute or type parameters such that they
525+
are printed in a fully qualified form, i.e., they include the dialect name and
526+
mnemonic prefix.
527+
528+
For example:
529+
530+
```tablegen
531+
def OuterType : TypeDef<My_Dialect, "MyOuterType"> {
532+
let parameters = (ins MyPairType:$inner);
533+
let mnemonic = "outer";
534+
let assemblyFormat = "`<` pair `:` $inner `>`";
535+
}
536+
def OuterQualifiedType : TypeDef<My_Dialect, "MyOuterQualifiedType"> {
537+
let parameters = (ins MyPairType:$inner);
538+
let mnemonic = "outer_qual";
539+
let assemblyFormat = "`<` pair `:` qualified($inner) `>`";
540+
}
541+
```
542+
543+
In the IR, the types will appear as:
544+
545+
```mlir
546+
!my_dialect.outer<pair : <42, 24>>
547+
!my_dialect.outer_qual<pair : !mydialect.pair<42, 24>>
548+
```
549+
520550
#### `struct` Directive
521551

522552
The `struct` directive accepts a list of variables to capture and will generate

mlir/test/lib/Dialect/Test/TestAttrDefs.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ def CompoundNestedOuter : Test_Attr<"CompoundNestedOuter"> {
144144
let assemblyFormat = "`<` `i` $inner `>`";
145145
}
146146

147+
def CompoundNestedOuterQual : Test_Attr<"CompoundNestedOuterQual"> {
148+
let mnemonic = "cmpnd_nested_outer_qual";
149+
150+
// List of type parameters.
151+
let parameters = (ins CompoundNestedInner:$inner);
152+
let assemblyFormat = "`<` `i` qualified($inner) `>`";
153+
}
154+
147155
def TestParamOne : AttrParameter<"int64_t", ""> {}
148156

149157
def TestParamTwo : AttrParameter<"std::string", "", "llvm::StringRef"> {

mlir/test/lib/Dialect/Test/TestOps.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,11 +1955,21 @@ def FormatNestedCompoundAttr : TEST_Op<"format_cpmd_nested_attr"> {
19551955
let assemblyFormat = "`nested` $nested attr-dict-with-keyword";
19561956
}
19571957

1958+
def FormatQualifiedCompoundAttr : TEST_Op<"format_qual_cpmd_nested_attr"> {
1959+
let arguments = (ins CompoundNestedOuter:$nested);
1960+
let assemblyFormat = "`nested` qualified($nested) attr-dict-with-keyword";
1961+
}
1962+
19581963
def FormatNestedType : TEST_Op<"format_cpmd_nested_type"> {
19591964
let arguments = (ins CompoundNestedOuterType:$nested);
19601965
let assemblyFormat = "$nested `nested` type($nested) attr-dict-with-keyword";
19611966
}
19621967

1968+
def FormatQualifiedNestedType : TEST_Op<"format_qual_cpmd_nested_type"> {
1969+
let arguments = (ins CompoundNestedOuterType:$nested);
1970+
let assemblyFormat = "$nested `nested` qualified(type($nested)) attr-dict-with-keyword";
1971+
}
1972+
19631973
//===----------------------------------------------------------------------===//
19641974
// Custom Directives
19651975

mlir/test/lib/Dialect/Test/TestTypeDefs.td

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,20 @@ def CompoundNestedInnerType : Test_Type<"CompoundNestedInner"> {
6565
def CompoundNestedOuterType : Test_Type<"CompoundNestedOuter"> {
6666
let mnemonic = "cmpnd_nested_outer";
6767

68+
// List of type parameters.
69+
let parameters = (ins CompoundNestedInnerType:$inner);
70+
let assemblyFormat = "`<` `i` $inner `>`";
71+
}
72+
73+
def CompoundNestedOuterTypeQual : Test_Type<"CompoundNestedOuterQual"> {
74+
let mnemonic = "cmpnd_nested_outer_qual";
75+
6876
// List of type parameters.
6977
let parameters = (
7078
ins
7179
CompoundNestedInnerType:$inner
7280
);
73-
let assemblyFormat = "`<` `i` $inner `>`";
81+
let assemblyFormat = "`<` `i` qualified($inner) `>`";
7482
}
7583

7684
// An example of how one could implement a standard integer.

mlir/test/mlir-tblgen/op-format.mlir

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,24 @@ module attributes {test.someAttr = #test.cmpnd_nested_outer<i <42 <1, !test.smpl
301301
// CHECK: test.format_cpmd_nested_attr nested <i <42 <1, !test.smpla, [5, 6]>>>
302302
test.format_cpmd_nested_attr nested <i <42 <1, !test.smpla, [5, 6]>>>
303303

304+
//-----
305+
306+
// CHECK: test.format_qual_cpmd_nested_attr nested #test.cmpnd_nested_outer<i <42 <1, !test.smpla, [5, 6]>>>
307+
test.format_qual_cpmd_nested_attr nested #test.cmpnd_nested_outer<i <42 <1, !test.smpla, [5, 6]>>>
308+
309+
//-----
310+
311+
// Check the `qualified` directive in the declarative assembly format.
312+
// CHECK: @qualifiedCompoundNestedExplicit(%arg0: !test.cmpnd_nested_outer<i <42 <1, !test.smpla, [5, 6]>>>)
313+
func @qualifiedCompoundNestedExplicit(%arg0: !test.cmpnd_nested_outer<i !test.cmpnd_inner<42 <1, !test.smpla, [5, 6]>>>) -> () {
314+
// Verify that the type prefix is not elided
315+
// CHECK: format_qual_cpmd_nested_type %arg0 nested !test.cmpnd_nested_outer<i <42 <1, !test.smpla, [5, 6]>>>
316+
test.format_qual_cpmd_nested_type %arg0 nested !test.cmpnd_nested_outer<i <42 <1, !test.smpla, [5, 6]>>>
317+
return
318+
}
319+
320+
//-----
321+
304322
//===----------------------------------------------------------------------===//
305323
// Format custom directives
306324
//===----------------------------------------------------------------------===//

mlir/test/mlir-tblgen/testdialect-attrdefs.mlir

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ func private @compoundA() attributes {foo = #test.cmpnd_a<1, !test.smpla, [5, 6]
99

1010
// CHECK: test.result_has_same_type_as_attr #test<"attr_with_type_builder 10 : i16"> -> i16
1111
%b = test.result_has_same_type_as_attr #test<"attr_with_type_builder 10 : i16"> -> i16
12+
13+
// CHECK-LABEL: @qualifiedAttr()
14+
// CHECK-SAME: #test.cmpnd_nested_outer_qual<i #test.cmpnd_nested_inner<42 <1, !test.smpla, [5, 6]>>>
15+
func private @qualifiedAttr() attributes {foo = #test.cmpnd_nested_outer_qual<i #test.cmpnd_nested_inner<42 <1, !test.smpla, [5, 6]>>>}

mlir/test/mlir-tblgen/testdialect-typedefs.mlir

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ func @compoundNestedExplicit(%arg0: !test.cmpnd_nested_outer<i !test.cmpnd_inner
2929
return
3030
}
3131

32+
// CHECK-LABEL: @compoundNestedQual
33+
// CHECK-SAME: !test.cmpnd_nested_outer_qual<i !test.cmpnd_inner<42 <1, !test.smpla, [5, 6]>>>
34+
func private @compoundNestedQual(%arg0: !test.cmpnd_nested_outer_qual<i !test.cmpnd_inner<42 <1, !test.smpla, [5, 6]>>>) -> ()
35+
3236
// CHECK: @testInt(%arg0: !test.int<signed, 8>, %arg1: !test.int<unsigned, 2>, %arg2: !test.int<none, 1>)
3337
func @testInt(%A : !test.int<s, 8>, %B : !test.int<unsigned, 2>, %C : !test.int<n, 1>) {
3438
return

mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.cpp

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,15 @@ class VariableElement : public Element {
8989
/// Get the parameter in the element.
9090
const AttrOrTypeParameter &getParam() const { return param; }
9191

92+
/// Indicate if this variable is printed "qualified" (that is it is
93+
/// prefixed with the `#dialect.mnemonic`).
94+
bool shouldBeQualified() { return shouldBeQualifiedFlag; }
95+
void setShouldBeQualified(bool qualified = true) {
96+
shouldBeQualifiedFlag = qualified;
97+
}
98+
9299
private:
100+
bool shouldBeQualifiedFlag = false;
93101
AttrOrTypeParameter param;
94102
};
95103

@@ -166,6 +174,10 @@ static const char *const defaultParameterParser =
166174
static const char *const defaultParameterPrinter =
167175
"$_printer.printStrippedAttrOrType($_self)";
168176

177+
/// Qualified printer for attribute or type parameters: it does not elide
178+
/// dialect and mnemonic.
179+
static const char *const qualifiedParameterPrinter = "$_printer << $_self";
180+
169181
/// Print an error when failing to parse an element.
170182
///
171183
/// $0: The parameter C++ class name.
@@ -251,7 +263,7 @@ class AttrOrTypeFormat {
251263
void genLiteralPrinter(StringRef value, FmtContext &ctx, MethodBody &os);
252264
/// Generate the printer code for a variable.
253265
void genVariablePrinter(const AttrOrTypeParameter &param, FmtContext &ctx,
254-
MethodBody &os);
266+
MethodBody &os, bool printQualified = false);
255267
/// Generate the printer code for a `params` directive.
256268
void genParamsPrinter(ParamsDirective *el, FmtContext &ctx, MethodBody &os);
257269
/// Generate the printer code for a `struct` directive.
@@ -435,7 +447,8 @@ void AttrOrTypeFormat::genElementPrinter(Element *el, FmtContext &ctx,
435447
if (auto *strct = dyn_cast<StructDirective>(el))
436448
return genStructPrinter(strct, ctx, os);
437449
if (auto *var = dyn_cast<VariableElement>(el))
438-
return genVariablePrinter(var->getParam(), ctx, os);
450+
return genVariablePrinter(var->getParam(), ctx, os,
451+
var->shouldBeQualified());
439452

440453
llvm_unreachable("unknown format element");
441454
}
@@ -455,7 +468,8 @@ void AttrOrTypeFormat::genLiteralPrinter(StringRef value, FmtContext &ctx,
455468
}
456469

457470
void AttrOrTypeFormat::genVariablePrinter(const AttrOrTypeParameter &param,
458-
FmtContext &ctx, MethodBody &os) {
471+
FmtContext &ctx, MethodBody &os,
472+
bool printQualified) {
459473
/// Insert a space before the next parameter, if necessary.
460474
if (shouldEmitSpace || !lastWasPunctuation)
461475
os << tgfmt(" $_printer << ' ';\n", &ctx);
@@ -464,7 +478,9 @@ void AttrOrTypeFormat::genVariablePrinter(const AttrOrTypeParameter &param,
464478

465479
ctx.withSelf(getParameterAccessorName(param.getName()) + "()");
466480
os << " ";
467-
if (auto printer = param.getPrinter())
481+
if (printQualified)
482+
os << tgfmt(qualifiedParameterPrinter, &ctx) << ";\n";
483+
else if (auto printer = param.getPrinter())
468484
os << tgfmt(*printer, &ctx) << ";\n";
469485
else
470486
os << tgfmt(defaultParameterPrinter, &ctx) << ";\n";
@@ -546,6 +562,9 @@ class FormatParser {
546562
FailureOr<std::unique_ptr<Element>> parseDirective(ParserContext ctx);
547563
/// Parse a `params` directive.
548564
FailureOr<std::unique_ptr<Element>> parseParamsDirective();
565+
/// Parse a `qualified` directive.
566+
FailureOr<std::unique_ptr<Element>>
567+
parseQualifiedDirective(ParserContext ctx);
549568
/// Parse a `struct` directive.
550569
FailureOr<std::unique_ptr<Element>> parseStructDirective();
551570

@@ -643,6 +662,8 @@ FailureOr<std::unique_ptr<Element>>
643662
FormatParser::parseDirective(ParserContext ctx) {
644663

645664
switch (curToken.getKind()) {
665+
case FormatToken::kw_qualified:
666+
return parseQualifiedDirective(ctx);
646667
case FormatToken::kw_params:
647668
return parseParamsDirective();
648669
case FormatToken::kw_struct:
@@ -656,6 +677,24 @@ FormatParser::parseDirective(ParserContext ctx) {
656677
}
657678
}
658679

680+
FailureOr<std::unique_ptr<Element>>
681+
FormatParser::parseQualifiedDirective(ParserContext ctx) {
682+
consumeToken();
683+
if (failed(parseToken(FormatToken::l_paren,
684+
"expected '(' before argument list")))
685+
return failure();
686+
FailureOr<std::unique_ptr<Element>> var = parseElement(ctx);
687+
if (failed(var))
688+
return var;
689+
if (!isa<VariableElement>(*var))
690+
return emitError("`qualified` argument list expected a variable");
691+
cast<VariableElement>(var->get())->setShouldBeQualified();
692+
if (failed(
693+
parseToken(FormatToken::r_paren, "expected ')' after argument list")))
694+
return failure();
695+
return var;
696+
}
697+
659698
FailureOr<std::unique_ptr<Element>> FormatParser::parseParamsDirective() {
660699
consumeToken();
661700
/// Collect all of the attribute's or type's parameters.

mlir/tools/mlir-tblgen/FormatGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ FormatToken FormatLexer::lexIdentifier(const char *tokStart) {
172172
.Case("struct", FormatToken::kw_struct)
173173
.Case("successors", FormatToken::kw_successors)
174174
.Case("type", FormatToken::kw_type)
175+
.Case("qualified", FormatToken::kw_qualified)
175176
.Default(FormatToken::identifier);
176177
return FormatToken(kind, str);
177178
}

mlir/tools/mlir-tblgen/FormatGen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class FormatToken {
5959
kw_functional_type,
6060
kw_operands,
6161
kw_params,
62+
kw_qualified,
6263
kw_ref,
6364
kw_regions,
6465
kw_results,

0 commit comments

Comments
 (0)