Incomplete definition for the custom attribute

Hello

I have a question about the way to define the custom attribute. What I’m trying to do is define a custom attribute for the complex dialect as follows. The attribute gets two parameters as real and imaginary parts.


class Complex_Attr<string attrName, string attrMnemonic, list<Trait> traits = []>
    : AttrDef<Complex_Dialect, attrName, traits> {
  let mnemonic = attrMnemonic;
}

def Complex_NumberAttr : Complex_Attr<"Number", "number"> {
  let summary = "A complex number attribute";

  let description = [{
    A complex number attribute.

    Example:

    ```mlir
    #complex.number<1.0, 2.0>
    ```
  }];

  let parameters = (ins "APFloat":$real, "APFloat":$imag);

  let assemblyFormat = "`<` $real `,` $imag `>`";
}

But this definition seems to fail the correct C++ class definition with throwing the following error. According to the message, it may relate to the storage definition but not sure how to fix that.

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/type_traits:3412:38: error: incomplete type 'mlir::complex::detail::NumberAttrStorage' used in type trait expression
    : public integral_constant<bool, __is_trivially_destructible(_Tp)> {};

...
/Users/sasakikai/dev/llvm-project/mlir/include/mlir/Support/StorageUniquer.h:155:7: error: static_cast from 'mlir::StorageUniquer::BaseStorage *' to 'mlir::complex::detail::NumberAttrStorage *', which are not related by inheritance, is not allowed
      static_cast<Storage *>(storage)->~Storage();
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/sasakikai/dev/llvm-project/build/tools/mlir/include/mlir/Dialect/Complex/IR/ComplexAttributes.h.inc:21:8: note: 'NumberAttrStorage' is incomplete
struct NumberAttrStorage;

Is there something wrong with my definition?

This should be part of the header generated by -gen-attrdef-decls, is it included? Did you check there if the NumberAttrStorage class is defined?

One thing that’s bitten me before is add_mlir_dialect will generate the headers and cpp files for types with -gen-typedef-decls and -gen-typedef-defs: llvm-project/AddMLIR.cmake at 3a20597776a5d2920e511d81653b4d2b6ca0c855 · llvm/llvm-project · GitHub, but it doesn’t include the same for -gen-attrdef-decls and -gen-attrdef-defs. So you end up needing to add it manually in your CMakeLists.txt for the dialect when you define custom attributes.

I’m not sure what is in your patch @Lewuathe , but you may need to add to CMakeLists.txt for the Complex dialect. For example, the Linalg dialect has the following to define custom attributes: llvm-project/CMakeLists.txt at 3a20597776a5d2920e511d81653b4d2b6ca0c855 · llvm/llvm-project · GitHub

Would it make sense to add_mlir_dialect to handle generating attribute defs like it does for type defs?

1 Like

The full definition of the storage class needs to be visible whenever you register the attribute, i.e. it won’t like it if you are registering the attribute in MyDialect.cpp, but defining it in MyAttributes.cpp. You either need to have the full definition available in your MyDialect.cpp, or need to define a new function (e.g., the builtin dialect does this):

Not sure if that’s your exact problem, but that’s what it looks like to me.

– River

Thank you for the advice all!

I could find the class NumberAttrStorage in the file ComplexAttributes.cpp.inc generated by the rule I added in CMakeLists.txt.

namespace mlir {
namespace complex {
namespace detail {
struct NumberAttrStorage : public ::mlir::AttributeStorage {
  using KeyTy = std::tuple<APFloat, APFloat>;
  NumberAttrStorage(APFloat real, APFloat imag) : ::mlir::AttributeStorage(), real(real), imag(imag) {}

  bool operator==(const KeyTy &tblgenKey) const {
    return (real == std::get<0>(tblgenKey)) && (imag == std::get<1>(tblgenKey));
  }

  static ::llvm::hash_code hashKey(const KeyTy &tblgenKey) {
    return ::llvm::hash_combine(std::get<0>(tblgenKey), std::get<1>(tblgenKey));
  }

  static NumberAttrStorage *construct(::mlir::AttributeStorageAllocator &allocator, const KeyTy &tblgenKey) {
    auto real = std::get<0>(tblgenKey);
    auto imag = std::get<1>(tblgenKey);
    return new (allocator.allocate<NumberAttrStorage>()) NumberAttrStorage(real, imag);
  }

  APFloat real;
  APFloat imag;
};

I have added the following commands in CMakeLists.txt for the complex dialect. `ComplexAttributes.[h,cpp].inc are properly. They look like containing NumberAttrStorage class too.

set(LLVM_TARGET_DEFINITIONS ComplexBase.td)
mlir_tablegen(ComplexAttributes.h.inc -gen-attrdef-decls -attrdefs-dialect=complex)
mlir_tablegen(ComplexAttributes.cpp.inc -gen-attrdef-defs -attrdefs-dialect=complex)
add_public_tablegen_target(MLIRComplexAttributesIncGen)
add_dependencies(mlir-headers MLIRComplexAttributesIncGen)

Similar to the linalg dialect, I’ve added the code to add attribute definition as follows.

void complex::ComplexDialect::initialize() {
  addOperations<
#define GET_OP_LIST
#include "mlir/Dialect/Complex/IR/ComplexOps.cpp.inc"
      >();
  addAttributes<
#define GET_ATTRDEF_LIST
#include "mlir/Dialect/Complex/IR/ComplexAttributes.cpp.inc"
      >();
}

But looks like the definition of NumberAttrStorage is completed. This addition might not work. So basically, all files seem to be generated but they might not be complete or invalid.

Just in case, here is the full error message I’ve got.

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/type_traits:3412:38: error: incomplete type 'mlir::complex::detail::NumberAttrStorage' used in type trait expression
    : public integral_constant<bool, __is_trivially_destructible(_Tp)> {};
                                     ^
/Users/sasakikai/dev/llvm-project/mlir/include/mlir/Support/StorageUniquer.h:152:14: note: in instantiation of template class 'std::is_trivially_destructible<mlir::complex::detail::NumberAttrStorage>' requested here
    if (std::is_trivially_destructible<Storage>::value)
             ^
/Users/sasakikai/dev/llvm-project/mlir/include/mlir/IR/AttributeSupport.h:261:10: note: in instantiation of function template specialization 'mlir::StorageUniquer::registerParametricStorageType<mlir::complex::detail::NumberAttrStorage>' requested here
        .registerParametricStorageType<typename T::ImplType>(typeID);
         ^
/Users/sasakikai/dev/llvm-project/mlir/include/mlir/IR/AttributeSupport.h:250:5: note: in instantiation of function template specialization 'mlir::detail::AttributeUniquer::registerAttribute<mlir::complex::NumberAttr>' requested here
    registerAttribute<T>(ctx, T::getTypeID());
    ^
/Users/sasakikai/dev/llvm-project/mlir/include/mlir/IR/Dialect.h:248:31: note: in instantiation of function template specialization 'mlir::detail::AttributeUniquer::registerAttribute<mlir::complex::NumberAttr>' requested here
    detail::AttributeUniquer::registerAttribute<T>(context);
                              ^
/Users/sasakikai/dev/llvm-project/mlir/include/mlir/IR/Dialect.h:225:42: note: in instantiation of function template specialization 'mlir::Dialect::addAttribute<mlir::complex::NumberAttr>' requested here
    (void)std::initializer_list<int>{0, (addAttribute<Args>(), 0)...};
                                         ^
/Users/sasakikai/dev/llvm-project/mlir/lib/Dialect/Complex/IR/ComplexDialect.cpp:21:3: note: in instantiation of function template specialization 'mlir::Dialect::addAttributes<mlir::complex::NumberAttr>' requested here
  addAttributes<
  ^
/Users/sasakikai/dev/llvm-project/build/tools/mlir/include/mlir/Dialect/Complex/IR/ComplexAttributes.h.inc:21:8: note: forward declaration of 'mlir::complex::detail::NumberAttrStorage'
struct NumberAttrStorage;

Finally, I’ve detected the cause. I should have added the following line in the ComplexDialect.cpp in addition to the header files. There would be no class definition for NumberAttrStorage otherwise.

#define GET_ATTRDEF_CLASSES
#include "mlir/Dialect/Complex/IR/ComplexAttributes.cpp.inc"
2 Likes