Inconsistent Printer and Parser Behavior for Nested Attributes in MLIR TableGen

Hello, I am new to MLIR, and I am trying to determine whether the following behavior is intended or a bug.

Defining an assembly format using TableGen (i.e., struct(params)) for a nested attribute results in different behaviors between the parser and the printer.

Reproduction

I defined an internal attribute (InternalAttr) with integer parameters and an external attribute (ExternalAttr) that contains a list of InternalAttr as a parameter.

//===----------------------------------------------------------------------===//
// Test
//===----------------------------------------------------------------------===//

def InternalAttr : OpenMP_Attr<"Internal", "internal"> {
  let parameters = (ins
    "int64_t":$key,
    "int64_t":$value
  );

  let assemblyFormat = "`<` struct(params) `>`";
}

def ExternalAttr : OpenMP_Attr<"External", "external"> {
  let parameters = (ins
    ArrayRefParameter<"InternalAttr">:$internals
  );

  let assemblyFormat = "`<` `[` struct(params) `]` `>`";
}

Behavior

The parser expects the following format:

module attributes {omp.internal = #omp.internal<key = 8, value = 9>} {}

module attributes {omp.external = #omp.external<[internals = #omp.internal<key = 1, value = 2>, #omp.internal<key = 8, value = 9>]>} {}

The parser for external attribute requires the mnemonic (#omp.internal) to be explicitly present for each InternalAttr inside ExternalAttr.

However, the printer prints the following format:

// RUN: mlir-opt %s
module attributes {omp.internal = #omp.internal<key = 8, value = 9>} {
}
module attributes {omp.external = #omp.external<[internals = <key = 1, value = 2>, <key = 8, value = 9>]>} {
}

Unlike the parser, the printer omits the mnemonic (#omp.internal) for InternalAttr inside ExternalAttr.

It seems to me that either:

  • The printer should retain the #omp.internal mnemonic, ensuring consistency with the parser, or
  • The parser should not require the #omp.internal mnemonic when parsing, since ExternalAttr is a well-defined closed type.

Could you clarify whether this behavior is intentional? If not, what would be the correct approach to ensure consistency between parsing and printing?

Thanks in advance for your guidance!

We have a test that does exactly this:

So this is the expected behavior right now, can you try to provide a PR with this example in the test dialect that demonstrate the issue you’re facing?

@mehdi_amini I made a PR that reproduces the behavior of nested attribute’s parser and printer. Thank you in advance!

Thanks! This is likely an issue with the handling of ArrayRefParameter here, but I personally won’t have time to look into this in the next weeks unfortunately.

1 Like

Thanks for the reply. I don’t know if I can, but I’ll try to fix this issue next week.

I’m very sorry for the long delay. Recently, I finally had some time to look into this issue.

It seems that the problem was caused by the lack of qualified marking related to struct(params), and I’ve created a patch to address it.
@mehdi_amini Would you be able to review it? If this isn’t the right way to approach the problem, I’d really appreciate it if you could let me know.

You can find the PR here: [mlir] [attribute] Fix inconsistent nested attribute parser and printer by JueonPark · Pull Request #133872 · llvm/llvm-project · GitHub

I believe I may have misunderstood.

Initially, I thought the current parser always required all nested attributes to be qualified. Therefore, I assumed the printer also needed to print all nested attributes as qualified.

This was incorrect. The current parser was already parsing unqualified nested attributes correctly and was in sync with the printer.

Thank you for your time reviewing this!