Extracting attributes as operands

Hi Folks

For a code such as in

I was able to get the symbol name using code such as

auto name = op->getAttrOfType<mlir::StringAttr>("sym_name").getValue();

But I run into problems when i try something similar to get the type .
e.g.
auto memrefType = op->getAttrOfType<MemrefType>("type")
etc just won’t work.

I am bit confused also why I was not able to use op->Operand(0) to access syn_name.
Could someone please explain where I am going wrong mixing ‘operands’ versus ‘getAttr’ because (ins Operand0 Operand1 ..) is how i think of let arguments =

Thanks a lot.

Hi,

As it isn’t an operand, it’s an attribute. Arguments in ODS are ordered list of operands and attributes which matches to order in DRR among others (see Operation Definition Specification (ODS) - MLIR for more information).

What error is reported? (I’d assume it is due to using a Type where an Attribute is expected, and TypeAttr would probably work if used here and then one would cast the value of the TypeAttr, which is a Type, to MemrefType).

This would be wrong. It’s an Attribute of type TypeAttr and not of type MemRefType. In fact, you should just be using the tablegen generated accessor here:

MemRefType memrefType = op.type();

However, the following will also work although it’d be bad to hardcode this way:

auto ... = op->getAttrOfType<TypeAttr>("type").getValue().cast<MemRefType>();

Somehow for me the type() function is not auto-generated although I followed the Memref TableGen description quite verbatim. Using

auto globalOp = llvm::dyn_cast<mlir::myDialect::CreateGlobalOp>(inst);
... = globalOp->type()

gives :

error: 'class mlir::Operation' has no member named 'type'

You have to use . : globalOp.type() ; because the operator -> will forward to Operation *.
The error message hints at it: is says 'class mlir::Operation' has no member... and not 'class ...GlobalOp' has no member

Hi:
I am bit confused between how operators "->’ and “.” are overloaded in mlir . I am able to do the following, but based on your inputs it seems there might be a cleaner way to do the same i.e. use nameAttr() and other methods that are only available to globalOp. Please suggest.

void foo( mlir::Operation *inst) {
      if (llvm::isa<mlir::myDialect::GetGlobalOp>(inst)) {
            auto globalOp = llvm::dyn_cast<mlir::myDialect::GetGlobalOp>(inst);
            llvm::StringRef name = globalOp.nameAttr().getValue();
            ...
      }
}

. isn’t something that can be overloaded in C++: you will directly access the GetGlobalOp class members that way. Only -> is forwarded to the underlying Operation pointer.

In general isa followed by cast is an anti-pattern, the expected way is to use dyn_cast instead of isa + cast that way:

      if (auto globalOp = llvm::dyn_cast<mlir::myDialect::GetGlobalOp>(inst)) {
            llvm::StringRef name = globalOp.nameAttr().getValue();
            ...
      }

Also I suspect you can access the name directly this way: llvm::StringRef name = globalOp.name();

Thanks. I see -> is forwarded to the underlying Operation pointer.

In general isa followed by cast is an anti-pattern

Aren’t there cases where this can be useful to exit early in a nested loop? e.g.
(Edit: perhaps useful isn’t the right term. Avoid nested pyramids.)

for (auto&& inst : instances) {
  if (!isa<mlir::myDialect::GetGlobalOp>(inst))
    continue;
  llvm::StringRef name = llvm::cast<mlir::myDialect::GetGlobalOp>(inst).nameAttr().getValue();
  ...
}

// versus

for (auto&& inst : instances) {
  if (auto globalOp = llvm::dyn_cast<mlir::myDialect::GetGlobalOp>(inst)) {
    llvm::StringRef name = globalOp.nameAttr().getValue();
    ...
  }
}

Yes: the LLVM coding guidelines prefer early-exit/early-continue to reduce indentation.
I usually write it this way though:

for (auto&& inst : instances) {
  auto globalOp = llvm::dyn_cast<mlir::myDialect::GetGlobalOp>(inst);
  if (!globalOp)
    continue;
  llvm::StringRef name = globalOp.name();
  ...
}