cornell-zhang / hcl-dialect

HeteroCL-MLIR dialect for accelerator design
https://cornell-zhang.github.io/heterocl/index.html
Other
40 stars 17 forks source link

[MLIR] Tablegen Doesn't Copy ArrayRef In Generated Type Storage Class Constructor #63

Closed zzzDavid closed 2 years ago

zzzDavid commented 2 years ago

This is a weird MLIR tablegen issue I came across when I try to add a hcl.struct type.

The struct tablegen type definition is like this:

def Struct : HeteroCL_Type<"Struct"> {
  let summary = "struct type";
  let mnemonic = "struct";
  let parameters = (ins "ArrayRef<Type>":$elementTypes);
  let printer = [{
    $_printer << "<";
    llvm::interleaveComma(getImpl()->elementTypes, $_printer);
    $_printer << '>';
  }];
  let parser = [{
    if ($_parser.parseLess())
      return Type();
    SmallVector<mlir::Type, 1> elementTypes;
    do {
      mlir::Type elementType;
      if ($_parser.parseType(elementType))
        return nullptr;

      elementTypes.push_back(elementType);
    } while (succeeded($_parser.parseOptionalComma()));

    if ($_parser.parseGreater())
      return Type();
    return get($_ctxt, elementTypes);
  }];
}

As we have parameters, there will be a TypeStorage class generated by tablegen, the constructor of that type storage class looks like this:

  static StructTypeStorage *construct(::mlir::TypeStorageAllocator &allocator, const KeyTy &tblgenKey) {
    auto elementTypes = std::get<0>(tblgenKey);
    // We need: auto elementTypes = allocator.copyInto(std::get<0>(tblgenKey));
    return new (allocator.allocate<StructTypeStorage>()) StructTypeStorage(elementTypes);
  }

The elementTypes is an array member of the storage class: ArrayRef<Type> elementTypes. We need to do an allocator.copyInto when constructing the TypeStorage object (uniquing the type object), or else we get this error:

mlir/include/mlir/IR/TypeSupport.h:128: const mlir::AbstractType& mlir::TypeStorage::getAbstractType(): Assertion `abstractType && "Malformed type storage object." failed.

Segmentation fault.
Aborted
zzzDavid commented 2 years ago

It turns out there's a special syntax for ArrayRef: https://github.com/llvm/llvm-project/blob/09c2b7c35af8c4bad39f03e9f60df8bd07323028/mlir/test/lib/Dialect/Test/TestTypeDefs.td#L42

After using this syntax in the tablegen def, everything works fine:

def Struct : HeteroCL_Type<"Struct"> {
  let summary = "struct type";
  let mnemonic = "struct";
  let parameters = (ins ArrayRefParameter<"Type", "elementTypes">:$elementTypes);
  let printer = [{
    $_printer << "<";
    llvm::interleaveComma(getImpl()->elementTypes, $_printer);
    $_printer << '>';
  }];
  let parser = [{
    if ($_parser.parseLess())
      return Type();
    SmallVector<mlir::Type, 1> elementTypes;
    do {
      mlir::Type elementType;
      if ($_parser.parseType(elementType))
        return nullptr;

      elementTypes.push_back(elementType);
    } while (succeeded($_parser.parseOptionalComma()));

    if ($_parser.parseGreater())
      return Type();
    return get($_ctxt, elementTypes);
  }];
}

The more you know :dizzy: