diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -22,94 +22,6 @@ include "flang/Optimizer/Dialect/FIRTypes.td" -// Types and predicates - -def fir_Type : Type, - "FIR dialect type">; - -// Fortran intrinsic types -def fir_IntegerType : Type()">, - "FIR integer type">; -def fir_LogicalType : Type()">, - "FIR logical type">; -def fir_RealType : Type()">, - "FIR real type">; -def fir_VectorType : Type()">, - "FIR vector type">; - -// Generalized FIR and standard dialect types representing intrinsic types -def AnyIntegerLike : TypeConstraint, "any integer">; -def AnyLogicalLike : TypeConstraint, "any logical">; -def AnyRealLike : TypeConstraint, "any real">; -def AnyIntegerType : Type; - -// Fortran derived (user defined) type -def fir_RecordType : Type()">, - "FIR derived type">; - -// Fortran array attribute -def fir_SequenceType : Type()">, - "array type">; - -// Composable types -def AnyCompositeLike : TypeConstraint, "any composite">; - -// Reference to an entity type -def fir_ReferenceType : Type()">, - "reference type">; - -// Reference to an ALLOCATABLE attribute type -def fir_HeapType : Type()">, - "allocatable type">; - -// Reference to a POINTER attribute type -def fir_PointerType : Type()">, - "pointer type">; - -// Reference types -def AnyReferenceLike : TypeConstraint, "any reference">; - -def AnyBoxLike : TypeConstraint, "any box">; - -def AnyRefOrBox : TypeConstraint, - "any reference or box">; - -def AnyShapeLike : TypeConstraint, "any legal shape type">; -def AnyShapeType : Type; -def fir_SliceType : Type()">, "slice type">; - -def AnyEmboxLike : TypeConstraint, - "any legal embox argument type">; -def AnyEmboxArg : Type; - -// A type descriptor's type -def fir_TypeDescType : Type()">, - "type desc type">; - -// A LEN parameter (in a RecordType) argument's type -def fir_LenType : Type()">, - "LEN parameter type">; - -def AnyComponentLike : TypeConstraint, - "any coordinate index">; -def AnyComponentType : Type; - -def AnyCoordinateLike : TypeConstraint, "any coordinate index">; -def AnyCoordinateType : Type; - // Base class for FIR operations. // All operations automatically get a prefix of "fir.". class fir_Op traits> @@ -2213,7 +2125,7 @@ if (!(type.isa() || type.isa())) return parser.emitError(parser.getCurrentLocation(), "must have character type"); - type = fir::SequenceType::get({sz.getInt()}, type); + type = fir::SequenceType::get(type.getContext(), {sz.getInt()}, type, {}); if (!type || parser.addTypesToList(type, result.types)) return mlir::failure(); return mlir::success(); diff --git a/flang/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h --- a/flang/include/flang/Optimizer/Dialect/FIRType.h +++ b/flang/include/flang/Optimizer/Dialect/FIRType.h @@ -41,18 +41,7 @@ using KindTy = unsigned; namespace detail { -struct HeapTypeStorage; -struct IntegerTypeStorage; -struct LenTypeStorage; -struct LogicalTypeStorage; -struct PointerTypeStorage; -struct RealTypeStorage; struct RecordTypeStorage; -struct ReferenceTypeStorage; -struct SequenceTypeStorage; -struct SliceTypeStorage; -struct TypeDescTypeStorage; -struct VectorTypeStorage; } // namespace detail // These isa_ routines follow the precedent of llvm::isa_or_null<> @@ -91,213 +80,6 @@ /// not a memory reference type, then returns a null `Type`. mlir::Type dyn_cast_ptrEleTy(mlir::Type t); -// Intrinsic types - -/// Model of a Fortran INTEGER intrinsic type, including the KIND type -/// parameter. -class IntegerType : public mlir::Type::TypeBase { -public: - using Base::Base; - static fir::IntegerType get(mlir::MLIRContext *ctxt, KindTy kind); - KindTy getFKind() const; -}; - -/// Model of a Fortran LOGICAL intrinsic type, including the KIND type -/// parameter. -class LogicalType : public mlir::Type::TypeBase { -public: - using Base::Base; - static LogicalType get(mlir::MLIRContext *ctxt, KindTy kind); - KindTy getFKind() const; -}; - -/// Model of a Fortran REAL (and DOUBLE PRECISION) intrinsic type, including the -/// KIND type parameter. -class RealType : public mlir::Type::TypeBase { -public: - using Base::Base; - static RealType get(mlir::MLIRContext *ctxt, KindTy kind); - KindTy getFKind() const; -}; - -// FIR support types - -/// Type of a vector that represents an array slice operation on an array. -/// Fortran slices are triples of lower bound, upper bound, and stride. The rank -/// of a SliceType must be at least 1. -class SliceType : public mlir::Type::TypeBase { -public: - using Base::Base; - static SliceType get(mlir::MLIRContext *ctx, unsigned rank); - unsigned getRank() const; -}; - -/// The type of a heap pointer. Fortran entities with the ALLOCATABLE attribute -/// may be allocated on the heap at runtime. These pointers are explicitly -/// distinguished to disallow the composition of multiple levels of -/// indirection. For example, an ALLOCATABLE POINTER is invalid. -class HeapType : public mlir::Type::TypeBase { -public: - using Base::Base; - static HeapType get(mlir::Type elementType); - - mlir::Type getEleTy() const; - - static mlir::LogicalResult - verify(llvm::function_ref emitError, - mlir::Type eleTy); -}; - -/// The type of a LEN parameter name. Implementations may defer the layout of a -/// Fortran derived type until runtime. This implies that the runtime must be -/// able to determine the offset of LEN type parameters related to an entity. -class LenType - : public mlir::Type::TypeBase { -public: - using Base::Base; - static LenType get(mlir::MLIRContext *ctxt); -}; - -/// The type of entities with the POINTER attribute. These pointers are -/// explicitly distinguished to disallow the composition of multiple levels of -/// indirection. For example, an ALLOCATABLE POINTER is invalid. -class PointerType : public mlir::Type::TypeBase { -public: - using Base::Base; - static PointerType get(mlir::Type elementType); - - mlir::Type getEleTy() const; - - static mlir::LogicalResult - verify(llvm::function_ref emitError, - mlir::Type eleTy); -}; - -/// The type of a reference to an entity in memory. -class ReferenceType - : public mlir::Type::TypeBase { -public: - using Base::Base; - static ReferenceType get(mlir::Type elementType); - - mlir::Type getEleTy() const; - - static mlir::LogicalResult - verify(llvm::function_ref emitError, - mlir::Type eleTy); -}; - -/// A sequence type is a multi-dimensional array of values. The sequence type -/// may have an unknown number of dimensions or the extent of dimensions may be -/// unknown. A sequence type models a Fortran array entity, giving it a type in -/// FIR. A sequence type is assumed to be stored in a column-major order, which -/// differs from LLVM IR and other dialects of MLIR. -class SequenceType : public mlir::Type::TypeBase { -public: - using Base::Base; - using Extent = int64_t; - using Shape = llvm::SmallVector; - - /// Return a sequence type with the specified shape and element type - static SequenceType get(const Shape &shape, mlir::Type elementType, - mlir::AffineMapAttr map = {}); - - /// The element type of this sequence - mlir::Type getEleTy() const; - - /// The shape of the sequence. If the sequence has an unknown shape, the shape - /// returned will be empty. - Shape getShape() const; - - mlir::AffineMapAttr getLayoutMap() const; - - /// The number of dimensions of the sequence - unsigned getDimension() const { return getShape().size(); } - - /// Number of rows of constant extent - unsigned getConstantRows() const; - - /// Is the shape of the sequence constant? - bool hasConstantShape() const { return getConstantRows() == getDimension(); } - - /// Does the sequence have unknown shape? (`array<* x T>`) - bool hasUnknownShape() const { return getShape().empty(); } - - /// Is the interior of the sequence constant? Check if the array is - /// one of constant shape (`array`), unknown shape - /// (`array<*xT>`), or rows with shape and ending with column(s) of - /// unknown extent (`array`). - bool hasConstantInterior() const; - - /// The value `-1` represents an unknown extent for a dimension - static constexpr Extent getUnknownExtent() { return -1; } - - static mlir::LogicalResult - verify(llvm::function_ref emitError, - const Shape &shape, mlir::Type eleTy, mlir::AffineMapAttr map); -}; - -bool operator==(const SequenceType::Shape &, const SequenceType::Shape &); -llvm::hash_code hash_value(const SequenceType::Extent &); -llvm::hash_code hash_value(const SequenceType::Shape &); - -/// The type of a type descriptor object. The runtime may generate type -/// descriptor objects to determine the type of an entity at runtime, etc. -class TypeDescType : public mlir::Type::TypeBase { -public: - using Base::Base; - static TypeDescType get(mlir::Type ofType); - mlir::Type getOfTy() const; - - static mlir::LogicalResult - verify(llvm::function_ref emitError, - mlir::Type ofType); -}; - -// Derived types - -/// Model of Fortran's derived type, TYPE. The name of the TYPE includes any -/// KIND type parameters. The record includes runtime slots for LEN type -/// parameters and for data components. -class RecordType : public mlir::Type::TypeBase { -public: - using Base::Base; - using TypePair = std::pair; - using TypeList = std::vector; - - llvm::StringRef getName(); - TypeList getTypeList(); - TypeList getLenParamList(); - - mlir::Type getType(llvm::StringRef ident); - mlir::Type getType(unsigned index) { - assert(index < getNumFields()); - return getTypeList()[index].second; - } - unsigned getNumFields() { return getTypeList().size(); } - unsigned getNumLenParams() { return getLenParamList().size(); } - - static RecordType get(mlir::MLIRContext *ctxt, llvm::StringRef name); - void finalize(llvm::ArrayRef lenPList, - llvm::ArrayRef typeList); - - detail::RecordTypeStorage const *uniqueKey() const; - - static mlir::LogicalResult - verify(llvm::function_ref emitError, - llvm::StringRef name); -}; - /// Is `t` a FIR Real or MLIR Float type? inline bool isa_real(mlir::Type t) { return t.isa() || t.isa(); @@ -309,26 +91,6 @@ t.isa(); } -/// Replacement for the builtin vector type. -/// The FIR vector type is always rank one. It's size is always a constant. -/// A vector's element type must be real or integer. -class VectorType : public mlir::Type::TypeBase { -public: - using Base::Base; - - static fir::VectorType get(uint64_t len, mlir::Type eleTy); - mlir::Type getEleTy() const; - uint64_t getLen() const; - - static mlir::LogicalResult - verify(llvm::function_ref emitError, uint64_t len, - mlir::Type eleTy); - static bool isValidElementType(mlir::Type t) { - return isa_real(t) || isa_integer(t); - } -}; - mlir::Type parseFirType(FIROpsDialect *, mlir::DialectAsmParser &parser); void printFirType(FIROpsDialect *, mlir::Type ty, mlir::DialectAsmPrinter &p); diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td --- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td +++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td @@ -23,6 +23,9 @@ let mnemonic = typeMnemonic; } +def fir_Type : Type, + "FIR dialect type">; + def fir_BoxCharType : FIR_Type<"BoxChar", "boxchar"> { let summary = "CHARACTER type descriptor."; @@ -34,10 +37,6 @@ let parameters = (ins "KindTy":$kind); - let printer = [{ - $_printer << "boxchar<" << getImpl()->kind << ">"; - }]; - let genAccessors = 1; let extraClassDeclaration = [{ @@ -61,13 +60,6 @@ let parameters = (ins "mlir::Type":$eleTy); - let printer = [{ - $_printer << "boxproc<"; - $_printer.printType(getEleTy()); - $_printer << '>'; - }]; - - let genAccessors = 1; let genVerifyDecl = 1; } @@ -82,15 +74,21 @@ let parameters = (ins "mlir::Type":$eleTy, "mlir::AffineMapAttr":$map); + let skipDefaultBuilders = 1; + + let builders = [ + TypeBuilderWithInferredContext<(ins + "mlir::Type":$eleTy, + CArg<"mlir::AffineMapAttr", "{}">:$map), [{ + return Base::get(eleTy.getContext(), eleTy, map); + }]>, + ]; + let extraClassDeclaration = [{ mlir::Type getElementType() const { return getEleTy(); } mlir::AffineMapAttr getLayoutMap() const { return getMap(); } - static BoxType get(mlir::Type eleTy, mlir::AffineMapAttr map = {}) { - return get(eleTy.getContext(), eleTy, map); - } }]; - let genAccessors = 1; let genVerifyDecl = 1; } @@ -138,12 +136,6 @@ let parameters = (ins "KindTy":$fKind); - let printer = [{ - $_printer << "complex<" << getFKind() << '>'; - }]; - - let genAccessors = 1; - let extraClassDeclaration = [{ using KindTy = unsigned; @@ -159,14 +151,176 @@ derived type until runtime. This implies that the runtime must be able to determine the offset of fields within the entity. }]; +} + +def fir_HeapType : FIR_Type<"Heap", "heap"> { + let summary = "Reference to an ALLOCATABLE attribute type"; + + let description = [{ + The type of a heap pointer. Fortran entities with the ALLOCATABLE attribute + may be allocated on the heap at runtime. These pointers are explicitly + distinguished to disallow the composition of multiple levels of + indirection. For example, an ALLOCATABLE POINTER is invalid. + }]; + + let parameters = (ins "mlir::Type":$eleTy); + + let genVerifyDecl = 1; + + let skipDefaultBuilders = 1; + + let builders = [ + TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{ + assert(singleIndirectionLevel(elementType) && "invalid element type"); + return Base::get(elementType.getContext(), elementType); + }]>, + ]; +} + +def fir_IntegerType : FIR_Type<"Integer", "int"> { + let summary = "FIR integer type"; + + let description = [{ + Model of a Fortran INTEGER intrinsic type, including the KIND type + parameter. + }]; + + let parameters = (ins "KindTy":$fKind); + + let extraClassDeclaration = [{ + using KindTy = unsigned; + }]; +} + +def fir_LenType : FIR_Type<"Len", "len"> { + let summary = "A LEN parameter (in a RecordType) argument's type"; + + let description = [{ + The type of a LEN parameter name. Implementations may defer the layout of a + Fortran derived type until runtime. This implies that the runtime must be + able to determine the offset of LEN type parameters related to an entity. + }]; +} + +def fir_LogicalType : FIR_Type<"Logical", "logical"> { + let summary = "FIR logical type"; + + let description = [{ + Model of a Fortran LOGICAL intrinsic type, including the KIND type + parameter. + }]; + + let parameters = (ins "KindTy":$fKind); + + let extraClassDeclaration = [{ + using KindTy = unsigned; + }]; +} + +def fir_PointerType : FIR_Type<"Pointer", "ptr"> { + let summary = "Reference to a POINTER attribute type"; + + let description = [{ + The type of entities with the POINTER attribute. These pointers are + explicitly distinguished to disallow the composition of multiple levels of + indirection. For example, an ALLOCATABLE POINTER is invalid. + }]; + + let parameters = (ins "mlir::Type":$eleTy); + + let genVerifyDecl = 1; + + let skipDefaultBuilders = 1; + + let builders = [ + TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{ + assert(singleIndirectionLevel(elementType) && "invalid element type"); + return Base::get(elementType.getContext(), elementType); + }]>, + ]; + + let extraClassDeclaration = [{ + mlir::Type getElementType() const { return getEleTy(); } + }]; +} + +def fir_RealType : FIR_Type<"Real", "real"> { + let summary = "FIR real type"; + + let description = [{ + Model of a Fortran REAL (and DOUBLE PRECISION) intrinsic type, including the + KIND type parameter. + }]; + + let parameters = (ins "KindTy":$fKind); + + let extraClassDeclaration = [{ + using KindTy = unsigned; + }]; + + let genVerifyDecl = 1; +} + +def fir_RecordType : FIR_Type<"Record", "type"> { + let summary = "FIR derived type"; + + let description = [{ + Model of Fortran's derived type, TYPE. The name of the TYPE includes any + KIND type parameters. The record includes runtime slots for LEN type + parameters and for data components. + }]; + + let parameters = (ins StringRefParameter<"name">:$name); + + let genVerifyDecl = 1; + let genStorageClass = 0; - let printer = [{ - $_printer << "field"; + let extraClassDeclaration = [{ + using TypePair = std::pair; + using TypeList = std::vector; + TypeList getTypeList() const; + TypeList getLenParamList() const; + + mlir::Type getType(llvm::StringRef ident); + // Returns the index of the field \p ident in the type list. + // Returns maximum unsigned if ident is not a field of this RecordType. + unsigned getFieldIndex(llvm::StringRef ident); + mlir::Type getType(unsigned index) { + assert(index < getNumFields()); + return getTypeList()[index].second; + } + unsigned getNumFields() { return getTypeList().size(); } + unsigned getNumLenParams() { return getLenParamList().size(); } + + void finalize(llvm::ArrayRef lenPList, + llvm::ArrayRef typeList); + + detail::RecordTypeStorage const *uniqueKey() const; }]; +} - let parser = [{ - return get(context); +def fir_ReferenceType : FIR_Type<"Reference", "ref"> { + let summary = "Reference to an entity type"; + + let description = [{ + The type of a reference to an entity in memory. }]; + + let parameters = (ins "mlir::Type":$eleTy); + + let skipDefaultBuilders = 1; + + let builders = [ + TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{ + return Base::get(elementType.getContext(), elementType); + }]>, + ]; + + let extraClassDeclaration = [{ + mlir::Type getElementType() const { return getEleTy(); } + }]; + + let genVerifyDecl = 1; } def fir_ShapeType : FIR_Type<"Shape", "shape"> { @@ -179,18 +333,6 @@ }]; let parameters = (ins "unsigned":$rank); - - let printer = [{ - $_printer << "shape<" << getImpl()->rank << ">"; - }]; - - let parser = [{ - int rank; - if ($_parser.parseLess() || $_parser.parseInteger(rank) || - $_parser.parseGreater()) - return Type(); - return get(context, rank); - }]; } def fir_ShapeShiftType : FIR_Type<"ShapeShift", "shapeshift"> { @@ -204,18 +346,6 @@ }]; let parameters = (ins "unsigned":$rank); - - let printer = [{ - $_printer << "shapeshift<" << getImpl()->rank << ">"; - }]; - - let parser = [{ - int rank; - if ($_parser.parseLess() || $_parser.parseInteger(rank) || - $_parser.parseGreater()) - return Type(); - return get(context, rank); - }]; } def fir_ShiftType : FIR_Type<"Shift", "shift"> { @@ -229,17 +359,189 @@ let parameters = (ins "unsigned":$rank); - let printer = [{ - $_printer << "shift<" << getImpl()->rank << ">"; + let extraClassDeclaration = [{ + using KindTy = unsigned; + + // a !fir.boxchar always wraps a !fir.char + CharacterType getElementType(mlir::MLIRContext *context) const; + + CharacterType getEleTy() const; + }]; +} + +def fir_SequenceType : FIR_Type<"Sequence", "array"> { + let summary = "FIR array type"; + + let description = [{ + A sequence type is a multi-dimensional array of values. The sequence type + may have an unknown number of dimensions or the extent of dimensions may be + unknown. A sequence type models a Fortran array entity, giving it a type in + FIR. A sequence type is assumed to be stored in a column-major order, which + differs from LLVM IR and other dialects of MLIR. + }]; + + let parameters = (ins + ArrayRefParameter<"int64_t", "Sequence shape">:$shape, + "mlir::Type":$eleTy, + "mlir::AffineMapAttr":$layoutMap + ); + + let genVerifyDecl = 1; + + let builders = [ + TypeBuilderWithInferredContext<(ins + "llvm::ArrayRef":$shape, + "mlir::Type":$eleTy), [{ + return get(eleTy.getContext(), shape, eleTy, {}); + }]>, + ]; + + let extraClassDeclaration = [{ + using Extent = int64_t; + using Shape = llvm::SmallVector; + using ShapeRef = llvm::ArrayRef; + unsigned getConstantRows() const; + + // The number of dimensions of the sequence + unsigned getDimension() const { return getShape().size(); } + + // Is the interior of the sequence constant? Check if the array is + // one of constant shape (`array`), unknown shape + // (`array<*xT>`), or rows with shape and ending with column(s) of + // unknown extent (`array`). + bool hasConstantInterior() const; + + // Is the shape of the sequence constant? + bool hasConstantShape() const { return getConstantRows() == getDimension(); } + + // Does the sequence have unknown shape? (`array<* x T>`) + bool hasUnknownShape() const { return getShape().empty(); } + + // The value `-1` represents an unknown extent for a dimension + static constexpr Extent getUnknownExtent() { return -1; } + }]; +} + +def fir_SliceType : FIR_Type<"Slice", "slice"> { + let summary = "FIR slice"; + + let description = [{ + Type of a vector that represents an array slice operation on an array. + Fortran slices are triples of lower bound, upper bound, and stride. The rank + of a SliceType must be at least 1. + }]; + + let parameters = (ins "unsigned":$rank); +} + +def fir_TypeDescType : FIR_Type<"TypeDesc", "tdesc"> { + let summary = "FIR Type descriptor type"; + + let description = [{ + The type of a type descriptor object. The runtime may generate type + descriptor objects to determine the type of an entity at runtime, etc. }]; - let parser = [{ - int rank; - if ($_parser.parseLess() || $_parser.parseInteger(rank) || - $_parser.parseGreater()) - return Type(); - return get(context, rank); + let parameters = (ins "mlir::Type":$ofTy); + + let genVerifyDecl = 1; + + let skipDefaultBuilders = 1; + + let builders = [ + TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{ + return Base::get(elementType.getContext(), elementType); + }]>, + ]; +} + +def fir_VectorType : FIR_Type<"Vector", "vector"> { + let summary = "FIR vector type"; + + let description = [{ + Replacement for the builtin vector type. + The FIR vector type is always rank one. It's size is always a constant. + A vector's element type must be real or integer. }]; + + let parameters = (ins "uint64_t":$len, "mlir::Type":$eleTy); + + let genVerifyDecl = 1; + + let extraClassDeclaration = [{ + static bool isValidElementType(mlir::Type t); + }]; + + let skipDefaultBuilders = 1; + + let builders = [ + TypeBuilderWithInferredContext<(ins + "uint64_t":$len, + "mlir::Type":$eleTy), [{ + return Base::get(eleTy.getContext(), len, eleTy); + }]>, + ]; } +def fir_VoidType : FIR_Type<"Void", "void"> { + let genStorageClass = 0; +} + +// Generalized FIR and standard dialect types representing intrinsic types +def AnyIntegerLike : TypeConstraint, "any integer">; +def AnyLogicalLike : TypeConstraint, "any logical">; +def AnyRealLike : TypeConstraint, "any real">; +def AnyIntegerType : Type; + +// Composable types +def AnyCompositeLike : TypeConstraint, + "any composite">; + +// Reference types +def AnyReferenceLike : TypeConstraint, "any reference">; + +def AnyBoxLike : TypeConstraint, "any box">; + +def AnyRefOrBoxLike : TypeConstraint, + "any reference or box like">; +def AnyRefOrBox : TypeConstraint, + "any reference or box">; + +def AnyShapeLike : TypeConstraint, "any legal shape type">; +def AnyShapeType : Type; +def AnyShapeOrShiftLike : TypeConstraint, + "any legal shape or shift type">; +def AnyShapeOrShiftType : Type; + +def AnyEmboxLike : TypeConstraint, + "any legal embox argument type">; +def AnyEmboxArg : Type; + +def AnyComponentLike : TypeConstraint, + "any coordinate index">; +def AnyComponentType : Type; + +def AnyCoordinateLike : TypeConstraint, "any coordinate index">; +def AnyCoordinateType : Type; + +// The legal types of global symbols +def AnyAddressableLike : TypeConstraint, "any addressable">; + #endif // FIR_DIALECT_FIR_TYPES diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp --- a/flang/lib/Optimizer/Dialect/FIRType.cpp +++ b/flang/lib/Optimizer/Dialect/FIRType.cpp @@ -49,7 +49,7 @@ } template -TYPE parseTypeSingleton(mlir::DialectAsmParser &parser, mlir::Location) { +TYPE parseTypeSingleton(mlir::DialectAsmParser &parser) { mlir::Type ty; if (parser.parseLess() || parser.parseType(ty) || parser.parseGreater()) { parser.emitError(parser.getCurrentLocation(), "type expected"); @@ -58,101 +58,6 @@ return TYPE::get(ty); } -// `slice` `<` rank `>` -SliceType parseSlice(mlir::DialectAsmParser &parser) { - return parseRankSingleton(parser); -} - -// `heap` `<` type `>` -HeapType parseHeap(mlir::DialectAsmParser &parser, mlir::Location loc) { - return parseTypeSingleton(parser, loc); -} - -// `int` `<` kind `>` -fir::IntegerType parseInteger(mlir::DialectAsmParser &parser) { - return parseKindSingleton(parser); -} - -// `len` -LenType parseLen(mlir::DialectAsmParser &parser) { - return LenType::get(parser.getBuilder().getContext()); -} - -// `logical` `<` kind `>` -LogicalType parseLogical(mlir::DialectAsmParser &parser) { - return parseKindSingleton(parser); -} - -// `ptr` `<` type `>` -PointerType parsePointer(mlir::DialectAsmParser &parser, mlir::Location loc) { - return parseTypeSingleton(parser, loc); -} - -// `real` `<` kind `>` -RealType parseReal(mlir::DialectAsmParser &parser) { - return parseKindSingleton(parser); -} - -// `ref` `<` type `>` -ReferenceType parseReference(mlir::DialectAsmParser &parser, - mlir::Location loc) { - return parseTypeSingleton(parser, loc); -} - -// `tdesc` `<` type `>` -TypeDescType parseTypeDesc(mlir::DialectAsmParser &parser, mlir::Location loc) { - return parseTypeSingleton(parser, loc); -} - -// `vector` `<` len `:` type `>` -fir::VectorType parseVector(mlir::DialectAsmParser &parser, - mlir::Location loc) { - int64_t len = 0; - mlir::Type eleTy; - if (parser.parseLess() || parser.parseInteger(len) || parser.parseColon() || - parser.parseType(eleTy) || parser.parseGreater()) { - parser.emitError(parser.getNameLoc(), "invalid vector type"); - return {}; - } - return fir::VectorType::get(len, eleTy); -} - -// `void` -mlir::Type parseVoid(mlir::DialectAsmParser &parser) { - return parser.getBuilder().getNoneType(); -} - -// `array` `<` `*` | bounds (`x` bounds)* `:` type (',' affine-map)? `>` -// bounds ::= `?` | int-lit -SequenceType parseSequence(mlir::DialectAsmParser &parser, mlir::Location) { - if (parser.parseLess()) { - parser.emitError(parser.getNameLoc(), "expecting '<'"); - return {}; - } - SequenceType::Shape shape; - if (parser.parseOptionalStar()) { - if (parser.parseDimensionList(shape, /*allowDynamic=*/true)) { - parser.emitError(parser.getNameLoc(), "invalid shape"); - return {}; - } - } else if (parser.parseColon()) { - parser.emitError(parser.getNameLoc(), "expected ':'"); - return {}; - } - mlir::Type eleTy; - if (parser.parseType(eleTy) || parser.parseGreater()) { - parser.emitError(parser.getNameLoc(), "expecting element type"); - return {}; - } - mlir::AffineMapAttr map; - if (!parser.parseOptionalComma()) - if (parser.parseAttribute(map)) { - parser.emitError(parser.getNameLoc(), "expecting affine map"); - return {}; - } - return SequenceType::get(shape, eleTy, map); -} - /// Is `ty` a standard or FIR integer type? static bool isaIntegerType(mlir::Type ty) { // TODO: why aren't we using isa_integer? investigatation required. @@ -206,71 +111,6 @@ return derivedTy; } -// Fortran derived type -// `type` `<` name -// (`(` id `:` type (`,` id `:` type)* `)`)? -// (`{` id `:` type (`,` id `:` type)* `}`)? '>' -RecordType parseDerived(mlir::DialectAsmParser &parser, mlir::Location) { - llvm::StringRef name; - if (parser.parseLess() || parser.parseKeyword(&name)) { - parser.emitError(parser.getNameLoc(), - "expected a identifier as name of derived type"); - return {}; - } - RecordType result = RecordType::get(parser.getBuilder().getContext(), name); - - RecordType::TypeList lenParamList; - if (!parser.parseOptionalLParen()) { - while (true) { - llvm::StringRef lenparam; - mlir::Type intTy; - if (parser.parseKeyword(&lenparam) || parser.parseColon() || - parser.parseType(intTy)) { - parser.emitError(parser.getNameLoc(), "expected LEN parameter list"); - return {}; - } - lenParamList.emplace_back(lenparam, intTy); - if (parser.parseOptionalComma()) - break; - } - if (parser.parseRParen()) { - parser.emitError(parser.getNameLoc(), "expected ')'"); - return {}; - } - } - - RecordType::TypeList typeList; - if (!parser.parseOptionalLBrace()) { - while (true) { - llvm::StringRef field; - mlir::Type fldTy; - if (parser.parseKeyword(&field) || parser.parseColon() || - parser.parseType(fldTy)) { - parser.emitError(parser.getNameLoc(), "expected field type list"); - return {}; - } - typeList.emplace_back(field, fldTy); - if (parser.parseOptionalComma()) - break; - } - if (parser.parseRBrace()) { - parser.emitError(parser.getNameLoc(), "expected '}'"); - return {}; - } - } - - if (parser.parseGreater()) { - parser.emitError(parser.getNameLoc(), "expected '>' in type type"); - return {}; - } - - if (lenParamList.empty() && typeList.empty()) - return result; - - result.finalize(lenParamList, typeList); - return verifyDerived(parser, result, lenParamList, typeList); -} - #ifndef NDEBUG // !fir.ptr and !fir.heap where X is !fir.ptr, !fir.heap, or !fir.ref // is undefined and disallowed. @@ -287,57 +127,9 @@ mlir::DialectAsmParser &parser) { llvm::StringRef typeNameLit; if (mlir::failed(parser.parseKeyword(&typeNameLit))) - return {}; + return mlir::Type(); - // TODO all TYPE::parse can be move to generatedTypeParser when all types - // have been moved - - auto loc = parser.getEncodedSourceLoc(parser.getNameLoc()); - if (typeNameLit == "array") - return parseSequence(parser, loc); - if (typeNameLit == "box") - return generatedTypeParser(dialect->getContext(), parser, typeNameLit); - if (typeNameLit == "boxchar") - return generatedTypeParser(dialect->getContext(), parser, typeNameLit); - if (typeNameLit == "boxproc") - return generatedTypeParser(dialect->getContext(), parser, typeNameLit); - if (typeNameLit == "char") - return generatedTypeParser(dialect->getContext(), parser, typeNameLit); - if (typeNameLit == "complex") - return generatedTypeParser(dialect->getContext(), parser, typeNameLit); - if (typeNameLit == "field") - return generatedTypeParser(dialect->getContext(), parser, typeNameLit); - if (typeNameLit == "heap") - return parseHeap(parser, loc); - if (typeNameLit == "int") - return parseInteger(parser); - if (typeNameLit == "len") - return parseLen(parser); - if (typeNameLit == "logical") - return parseLogical(parser); - if (typeNameLit == "ptr") - return parsePointer(parser, loc); - if (typeNameLit == "real") - return parseReal(parser); - if (typeNameLit == "ref") - return parseReference(parser, loc); - if (typeNameLit == "shape") - return generatedTypeParser(dialect->getContext(), parser, typeNameLit); - if (typeNameLit == "shapeshift") - return generatedTypeParser(dialect->getContext(), parser, typeNameLit); - if (typeNameLit == "slice") - return parseSlice(parser); - if (typeNameLit == "tdesc") - return parseTypeDesc(parser, loc); - if (typeNameLit == "type") - return parseDerived(parser, loc); - if (typeNameLit == "void") - return parseVoid(parser); - if (typeNameLit == "vector") - return parseVector(parser, loc); - - parser.emitError(parser.getNameLoc(), "unknown FIR type " + typeNameLit); - return {}; + return generatedTypeParser(dialect->getContext(), parser, typeNameLit); } namespace fir { @@ -345,234 +137,6 @@ // Type storage classes -struct SliceTypeStorage : public mlir::TypeStorage { - using KeyTy = unsigned; - - static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); } - - bool operator==(const KeyTy &key) const { return key == getRank(); } - - static SliceTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - unsigned rank) { - auto *storage = allocator.allocate(); - return new (storage) SliceTypeStorage{rank}; - } - - unsigned getRank() const { return rank; } - -protected: - unsigned rank; - -private: - SliceTypeStorage() = delete; - explicit SliceTypeStorage(unsigned rank) : rank{rank} {} -}; - -/// The type of a derived type LEN parameter reference -struct LenTypeStorage : public mlir::TypeStorage { - using KeyTy = KindTy; - - static unsigned hashKey(const KeyTy &) { return llvm::hash_combine(0); } - - bool operator==(const KeyTy &) const { return true; } - - static LenTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - KindTy) { - auto *storage = allocator.allocate(); - return new (storage) LenTypeStorage{0}; - } - -private: - LenTypeStorage() = delete; - explicit LenTypeStorage(KindTy) {} -}; - -/// `LOGICAL` storage -struct LogicalTypeStorage : public mlir::TypeStorage { - using KeyTy = KindTy; - - static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); } - - bool operator==(const KeyTy &key) const { return key == getFKind(); } - - static LogicalTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - KindTy kind) { - auto *storage = allocator.allocate(); - return new (storage) LogicalTypeStorage{kind}; - } - - KindTy getFKind() const { return kind; } - -protected: - KindTy kind; - -private: - LogicalTypeStorage() = delete; - explicit LogicalTypeStorage(KindTy kind) : kind{kind} {} -}; - -/// `INTEGER` storage -struct IntegerTypeStorage : public mlir::TypeStorage { - using KeyTy = KindTy; - - static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); } - - bool operator==(const KeyTy &key) const { return key == getFKind(); } - - static IntegerTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - KindTy kind) { - auto *storage = allocator.allocate(); - return new (storage) IntegerTypeStorage{kind}; - } - - KindTy getFKind() const { return kind; } - -protected: - KindTy kind; - -private: - IntegerTypeStorage() = delete; - explicit IntegerTypeStorage(KindTy kind) : kind{kind} {} -}; - -/// `REAL` storage (for reals of unsupported sizes) -struct RealTypeStorage : public mlir::TypeStorage { - using KeyTy = KindTy; - - static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); } - - bool operator==(const KeyTy &key) const { return key == getFKind(); } - - static RealTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - KindTy kind) { - auto *storage = allocator.allocate(); - return new (storage) RealTypeStorage{kind}; - } - - KindTy getFKind() const { return kind; } - -protected: - KindTy kind; - -private: - RealTypeStorage() = delete; - explicit RealTypeStorage(KindTy kind) : kind{kind} {} -}; - -/// Pointer-like object storage -struct ReferenceTypeStorage : public mlir::TypeStorage { - using KeyTy = mlir::Type; - - static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); } - - bool operator==(const KeyTy &key) const { return key == getElementType(); } - - static ReferenceTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - mlir::Type eleTy) { - assert(eleTy && "element type is null"); - auto *storage = allocator.allocate(); - return new (storage) ReferenceTypeStorage{eleTy}; - } - - mlir::Type getElementType() const { return eleTy; } - -protected: - mlir::Type eleTy; - -private: - ReferenceTypeStorage() = delete; - explicit ReferenceTypeStorage(mlir::Type eleTy) : eleTy{eleTy} {} -}; - -/// Pointer object storage -struct PointerTypeStorage : public mlir::TypeStorage { - using KeyTy = mlir::Type; - - static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); } - - bool operator==(const KeyTy &key) const { return key == getElementType(); } - - static PointerTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - mlir::Type eleTy) { - assert(eleTy && "element type is null"); - auto *storage = allocator.allocate(); - return new (storage) PointerTypeStorage{eleTy}; - } - - mlir::Type getElementType() const { return eleTy; } - -protected: - mlir::Type eleTy; - -private: - PointerTypeStorage() = delete; - explicit PointerTypeStorage(mlir::Type eleTy) : eleTy{eleTy} {} -}; - -/// Heap memory reference object storage -struct HeapTypeStorage : public mlir::TypeStorage { - using KeyTy = mlir::Type; - - static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); } - - bool operator==(const KeyTy &key) const { return key == getElementType(); } - - static HeapTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - mlir::Type eleTy) { - assert(eleTy && "element type is null"); - auto *storage = allocator.allocate(); - return new (storage) HeapTypeStorage{eleTy}; - } - - mlir::Type getElementType() const { return eleTy; } - -protected: - mlir::Type eleTy; - -private: - HeapTypeStorage() = delete; - explicit HeapTypeStorage(mlir::Type eleTy) : eleTy{eleTy} {} -}; - -/// Sequence-like object storage -struct SequenceTypeStorage : public mlir::TypeStorage { - using KeyTy = - std::tuple; - - static unsigned hashKey(const KeyTy &key) { - auto shapeHash = hash_value(std::get(key)); - shapeHash = llvm::hash_combine(shapeHash, std::get(key)); - return llvm::hash_combine(shapeHash, std::get(key)); - } - - bool operator==(const KeyTy &key) const { - return key == KeyTy{getShape(), getElementType(), getLayoutMap()}; - } - - static SequenceTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - const KeyTy &key) { - auto *storage = allocator.allocate(); - return new (storage) SequenceTypeStorage{ - std::get(key), std::get(key), - std::get(key)}; - } - - SequenceType::Shape getShape() const { return shape; } - mlir::Type getElementType() const { return eleTy; } - mlir::AffineMapAttr getLayoutMap() const { return map; } - -protected: - SequenceType::Shape shape; - mlir::Type eleTy; - mlir::AffineMapAttr map; - -private: - SequenceTypeStorage() = delete; - explicit SequenceTypeStorage(const SequenceType::Shape &shape, - mlir::Type eleTy, mlir::AffineMapAttr map) - : shape{shape}, eleTy{eleTy}, map{map} {} -}; - /// Derived type storage struct RecordTypeStorage : public mlir::TypeStorage { using KeyTy = llvm::StringRef; @@ -620,85 +184,27 @@ : name{name}, finalized{false} {} }; -/// Type descriptor type storage -struct TypeDescTypeStorage : public mlir::TypeStorage { - using KeyTy = mlir::Type; +} // namespace detail - static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); } +template +bool inbounds(A v, B lb, B ub) { + return v >= lb && v < ub; +} - bool operator==(const KeyTy &key) const { return key == getOfType(); } +bool isa_fir_type(mlir::Type t) { + return llvm::isa(t.getDialect()); +} - static TypeDescTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - mlir::Type ofTy) { - assert(ofTy && "descriptor type is null"); - auto *storage = allocator.allocate(); - return new (storage) TypeDescTypeStorage{ofTy}; - } +bool isa_std_type(mlir::Type t) { + return t.getDialect().getNamespace().empty(); +} - // The type described by this type descriptor instance - mlir::Type getOfType() const { return ofTy; } - -protected: - mlir::Type ofTy; - -private: - TypeDescTypeStorage() = delete; - explicit TypeDescTypeStorage(mlir::Type ofTy) : ofTy{ofTy} {} -}; - -/// Vector type storage -struct VectorTypeStorage : public mlir::TypeStorage { - using KeyTy = std::tuple; - - static unsigned hashKey(const KeyTy &key) { - return llvm::hash_combine(std::get(key), - std::get(key)); - } - - bool operator==(const KeyTy &key) const { - return key == KeyTy{getLen(), getEleTy()}; - } - - static VectorTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - const KeyTy &key) { - auto *storage = allocator.allocate(); - return new (storage) - VectorTypeStorage{std::get(key), std::get(key)}; - } - - uint64_t getLen() const { return len; } - mlir::Type getEleTy() const { return eleTy; } - -protected: - uint64_t len; - mlir::Type eleTy; - -private: - VectorTypeStorage() = delete; - explicit VectorTypeStorage(uint64_t len, mlir::Type eleTy) - : len{len}, eleTy{eleTy} {} -}; - -} // namespace detail - -template bool inbounds(A v, B lb, B ub) { - return v >= lb && v < ub; -} - -bool isa_fir_type(mlir::Type t) { - return llvm::isa(t.getDialect()); -} - -bool isa_std_type(mlir::Type t) { - return t.getDialect().getNamespace().empty(); -} - -bool isa_fir_or_std_type(mlir::Type t) { - if (auto funcType = t.dyn_cast()) - return llvm::all_of(funcType.getInputs(), isa_fir_or_std_type) && - llvm::all_of(funcType.getResults(), isa_fir_or_std_type); - return isa_fir_type(t) || isa_std_type(t); -} +bool isa_fir_or_std_type(mlir::Type t) { + if (auto funcType = t.dyn_cast()) + return llvm::all_of(funcType.getInputs(), isa_fir_or_std_type) && + llvm::all_of(funcType.getResults(), isa_fir_or_std_type); + return isa_fir_type(t) || isa_std_type(t); +} bool isa_ref_type(mlir::Type t) { return t.isa() || t.isa() || t.isa(); @@ -727,101 +233,205 @@ } // namespace fir -// Len +namespace { -LenType fir::LenType::get(mlir::MLIRContext *ctxt) { - return Base::get(ctxt, 0); -} +static llvm::SmallPtrSet + recordTypeVisited; + +} // namespace -// LOGICAL +void fir::verifyIntegralType(mlir::Type type) { + if (isaIntegerType(type) || type.isa()) + return; + llvm::report_fatal_error("expected integral type"); +} -LogicalType fir::LogicalType::get(mlir::MLIRContext *ctxt, KindTy kind) { - return Base::get(ctxt, kind); +void fir::printFirType(FIROpsDialect *, mlir::Type ty, + mlir::DialectAsmPrinter &p) { + if (mlir::failed(generatedTypePrinter(ty, p))) + llvm::report_fatal_error("unknown type to print"); } -KindTy fir::LogicalType::getFKind() const { return getImpl()->getFKind(); } +bool fir::isa_unknown_size_box(mlir::Type t) { + if (auto boxTy = t.dyn_cast()) { + auto eleTy = boxTy.getEleTy(); + if (auto actualEleTy = fir::dyn_cast_ptrEleTy(eleTy)) + eleTy = actualEleTy; + if (eleTy.isa()) + return true; + if (auto seqTy = eleTy.dyn_cast()) + if (seqTy.hasUnknownShape()) + return true; + } + return false; +} -// INTEGER +//===----------------------------------------------------------------------===// +// BoxProcType +//===----------------------------------------------------------------------===// -fir::IntegerType fir::IntegerType::get(mlir::MLIRContext *ctxt, KindTy kind) { - return Base::get(ctxt, kind); +// `boxproc` `<` return-type `>` +mlir::Type BoxProcType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + mlir::Type ty; + if (parser.parseLess() || parser.parseType(ty) || parser.parseGreater()) { + parser.emitError(parser.getCurrentLocation(), "type expected"); + return {}; + } + return get(context, ty); } -KindTy fir::IntegerType::getFKind() const { return getImpl()->getFKind(); } +void fir::BoxProcType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getEleTy() << '>'; +} -// REAL +mlir::LogicalResult +BoxProcType::verify(llvm::function_ref emitError, + mlir::Type eleTy) { + if (eleTy.isa()) + return mlir::success(); + if (auto refTy = eleTy.dyn_cast()) + if (refTy.isa()) + return mlir::success(); + return emitError() << "invalid type for boxproc" << eleTy << '\n'; +} -RealType fir::RealType::get(mlir::MLIRContext *ctxt, KindTy kind) { - return Base::get(ctxt, kind); +static bool canBePointerOrHeapElementType(mlir::Type eleTy) { + return eleTy.isa(); } -KindTy fir::RealType::getFKind() const { return getImpl()->getFKind(); } +//===----------------------------------------------------------------------===// +// BoxType +//===----------------------------------------------------------------------===// -mlir::LogicalResult -fir::BoxType::verify(llvm::function_ref, - mlir::Type eleTy, mlir::AffineMapAttr map) { - // TODO - return mlir::success(); +// `box` `<` type (',' affine-map)? `>` +mlir::Type fir::BoxType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + mlir::Type ofTy; + if (parser.parseLess() || parser.parseType(ofTy)) { + parser.emitError(parser.getCurrentLocation(), "expected type parameter"); + return {}; + } + + mlir::AffineMapAttr map; + if (!parser.parseOptionalComma()) { + if (parser.parseAttribute(map)) { + parser.emitError(parser.getCurrentLocation(), "expected affine map"); + return {}; + } + } + if (parser.parseGreater()) { + return {}; + } + return get(ofTy, map); } -// Reference +void fir::BoxType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getEleTy(); + if (auto map = getLayoutMap()) { + printer << ", " << map; + } + printer << '>'; +} -ReferenceType fir::ReferenceType::get(mlir::Type elementType) { - return Base::get(elementType.getContext(), elementType); +//===----------------------------------------------------------------------===// +// BoxCharType +//===----------------------------------------------------------------------===// + +mlir::Type fir::BoxCharType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + int kind = 0; + if (parser.parseLess() || parser.parseInteger(kind) || + parser.parseGreater()) { + parser.emitError(parser.getCurrentLocation(), "kind value expected"); + return {}; + } + return get(context, kind); } -mlir::Type fir::ReferenceType::getEleTy() const { - return getImpl()->getElementType(); +void fir::BoxCharType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getKind() << ">"; } -mlir::LogicalResult fir::ReferenceType::verify( - llvm::function_ref emitError, - mlir::Type eleTy) { - if (eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa()) - return emitError() << "cannot build a reference to type: " << eleTy << '\n'; - return mlir::success(); +CharacterType +fir::BoxCharType::getElementType(mlir::MLIRContext *context) const { + return CharacterType::getUnknownLen(context, getKind()); } -// Pointer +CharacterType fir::BoxCharType::getEleTy() const { + return getElementType(getContext()); +} + +//===----------------------------------------------------------------------===// +// CharacterType +//===----------------------------------------------------------------------===// + +// `char` `<` kind [`,` `len`] `>` +mlir::Type fir::CharacterType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + int kind = 0; + if (parser.parseLess() || parser.parseInteger(kind)) { + parser.emitError(parser.getCurrentLocation(), "kind value expected"); + return {}; + } + CharacterType::LenType len = 1; + if (mlir::succeeded(parser.parseOptionalComma())) { + if (mlir::succeeded(parser.parseOptionalQuestion())) { + len = fir::CharacterType::unknownLen(); + } else if (!mlir::succeeded(parser.parseInteger(len))) { + parser.emitError(parser.getCurrentLocation(), "len value expected"); + return {}; + } + } + if (parser.parseGreater()) + return {}; + return get(context, kind, len); +} -PointerType fir::PointerType::get(mlir::Type elementType) { - assert(singleIndirectionLevel(elementType) && "invalid element type"); - return Base::get(elementType.getContext(), elementType); +void fir::CharacterType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getFKind(); + auto len = getLen(); + if (len != fir::CharacterType::singleton()) { + printer << ','; + if (len == fir::CharacterType::unknownLen()) + printer << '?'; + else + printer << len; + } + printer << '>'; } -mlir::Type fir::PointerType::getEleTy() const { - return getImpl()->getElementType(); +//===----------------------------------------------------------------------===// +// ComplexType +//===----------------------------------------------------------------------===// + +mlir::Type fir::ComplexType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseKindSingleton(parser); } -static bool canBePointerOrHeapElementType(mlir::Type eleTy) { - return eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa(); +void fir::ComplexType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getFKind() << '>'; } -mlir::LogicalResult fir::PointerType::verify( - llvm::function_ref emitError, - mlir::Type eleTy) { - if (canBePointerOrHeapElementType(eleTy)) - return emitError() << "cannot build a pointer to type: " << eleTy << '\n'; - return mlir::success(); +mlir::Type fir::ComplexType::getElementType() const { + return fir::RealType::get(getContext(), getFKind()); } -// Heap +//===----------------------------------------------------------------------===// +// HeapType +//===----------------------------------------------------------------------===// -HeapType fir::HeapType::get(mlir::Type elementType) { - assert(singleIndirectionLevel(elementType) && "invalid element type"); - return Base::get(elementType.getContext(), elementType); +// `heap` `<` type `>` +mlir::Type fir::HeapType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseTypeSingleton(parser); } -mlir::Type fir::HeapType::getEleTy() const { - return getImpl()->getElementType(); +void fir::HeapType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getEleTy() << '>'; } mlir::LogicalResult @@ -833,105 +443,172 @@ return mlir::success(); } -// Sequence +//===----------------------------------------------------------------------===// +// IntegerType +//===----------------------------------------------------------------------===// -SequenceType fir::SequenceType::get(const Shape &shape, mlir::Type elementType, - mlir::AffineMapAttr map) { - auto *ctxt = elementType.getContext(); - return Base::get(ctxt, shape, elementType, map); +// `int` `<` kind `>` +mlir::Type fir::IntegerType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseKindSingleton(parser); } -mlir::Type fir::SequenceType::getEleTy() const { - return getImpl()->getElementType(); +void fir::IntegerType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getFKind() << '>'; } -mlir::AffineMapAttr fir::SequenceType::getLayoutMap() const { - return getImpl()->getLayoutMap(); +//===----------------------------------------------------------------------===// +// LogicalType +//===----------------------------------------------------------------------===// + +// `logical` `<` kind `>` +mlir::Type fir::LogicalType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseKindSingleton(parser); } -SequenceType::Shape fir::SequenceType::getShape() const { - return getImpl()->getShape(); +void fir::LogicalType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getFKind() << '>'; } -unsigned fir::SequenceType::getConstantRows() const { - auto shape = getShape(); - unsigned count = 0; - for (auto d : shape) { - if (d < 0) - break; - ++count; - } - return count; +//===----------------------------------------------------------------------===// +// PointerType +//===----------------------------------------------------------------------===// + +// `ptr` `<` type `>` +mlir::Type fir::PointerType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseTypeSingleton(parser); } -// This test helps us determine if we can degenerate an array to a -// pointer to some interior section (possibly a single element) of the -// sequence. This is used to determine if we can lower to the LLVM IR. -bool fir::SequenceType::hasConstantInterior() const { - if (hasUnknownShape()) - return true; - auto rows = getConstantRows(); - auto dim = getDimension(); - if (rows == dim) - return true; - auto shape = getShape(); - for (unsigned i{rows}, size{dim}; i < size; ++i) - if (shape[i] != getUnknownExtent()) - return false; - return true; +void fir::PointerType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getEleTy() << '>'; } -mlir::LogicalResult fir::SequenceType::verify( +mlir::LogicalResult fir::PointerType::verify( llvm::function_ref emitError, - const SequenceType::Shape &shape, mlir::Type eleTy, - mlir::AffineMapAttr map) { - // DIMENSION attribute can only be applied to an intrinsic or record type - if (eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa()) - return emitError() << "cannot build an array of this element type: " - << eleTy << '\n'; + mlir::Type eleTy) { + if (canBePointerOrHeapElementType(eleTy)) + return emitError() << "cannot build a pointer to type: " << eleTy << '\n'; return mlir::success(); } -// compare if two shapes are equivalent -bool fir::operator==(const SequenceType::Shape &sh_1, - const SequenceType::Shape &sh_2) { - if (sh_1.size() != sh_2.size()) - return false; - auto e = sh_1.size(); - for (decltype(e) i = 0; i != e; ++i) - if (sh_1[i] != sh_2[i]) - return false; - return true; -} +//===----------------------------------------------------------------------===// +// RealType +//===----------------------------------------------------------------------===// -// compute the hash of a Shape -llvm::hash_code fir::hash_value(const SequenceType::Shape &sh) { - if (sh.size()) { - return llvm::hash_combine_range(sh.begin(), sh.end()); - } - return llvm::hash_combine(0); +// `real` `<` kind `>` +mlir::Type fir::RealType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseKindSingleton(parser); } -// Slice +void fir::RealType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getFKind() << '>'; +} -SliceType fir::SliceType::get(mlir::MLIRContext *ctxt, unsigned rank) { - return Base::get(ctxt, rank); +mlir::LogicalResult +fir::BoxType::verify(llvm::function_ref emitError, + mlir::Type eleTy, mlir::AffineMapAttr map) { + // TODO + return mlir::success(); } -unsigned fir::SliceType::getRank() const { return getImpl()->getRank(); } +//===----------------------------------------------------------------------===// +// RecordType +//===----------------------------------------------------------------------===// -/// RecordType -/// -/// This type captures a Fortran "derived type" +// Fortran derived type +// `type` `<` name +// (`(` id `:` type (`,` id `:` type)* `)`)? +// (`{` id `:` type (`,` id `:` type)* `}`)? '>' +mlir::Type fir::RecordType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + llvm::StringRef name; + if (parser.parseLess() || parser.parseKeyword(&name)) { + parser.emitError(parser.getNameLoc(), + "expected a identifier as name of derived type"); + return {}; + } + RecordType result = RecordType::get(parser.getBuilder().getContext(), name); -RecordType fir::RecordType::get(mlir::MLIRContext *ctxt, llvm::StringRef name) { - return Base::get(ctxt, name); + RecordType::TypeList lenParamList; + if (!parser.parseOptionalLParen()) { + while (true) { + llvm::StringRef lenparam; + mlir::Type intTy; + if (parser.parseKeyword(&lenparam) || parser.parseColon() || + parser.parseType(intTy)) { + parser.emitError(parser.getNameLoc(), "expected LEN parameter list"); + return {}; + } + lenParamList.emplace_back(lenparam, intTy); + if (parser.parseOptionalComma()) + break; + } + if (parser.parseRParen()) { + parser.emitError(parser.getNameLoc(), "expected ')'"); + return {}; + } + } + + RecordType::TypeList typeList; + if (!parser.parseOptionalLBrace()) { + while (true) { + llvm::StringRef field; + mlir::Type fldTy; + if (parser.parseKeyword(&field) || parser.parseColon() || + parser.parseType(fldTy)) { + parser.emitError(parser.getNameLoc(), "expected field type list"); + return {}; + } + typeList.emplace_back(field, fldTy); + if (parser.parseOptionalComma()) + break; + } + if (parser.parseRBrace()) { + parser.emitError(parser.getNameLoc(), "expected '}'"); + return {}; + } + } + + if (parser.parseGreater()) { + parser.emitError(parser.getNameLoc(), "expected '>' in type type"); + return {}; + } + + if (lenParamList.empty() && typeList.empty()) + return result; + + result.finalize(lenParamList, typeList); + return verifyDerived(parser, result, lenParamList, typeList); +} + +void fir::RecordType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getName(); + if (!recordTypeVisited.count(uniqueKey())) { + recordTypeVisited.insert(uniqueKey()); + if (getLenParamList().size()) { + char ch = '('; + for (auto p : getLenParamList()) { + printer << ch << p.first << ':'; + p.second.print(printer.getStream()); + ch = ','; + } + printer << ')'; + } + if (getTypeList().size()) { + char ch = '{'; + for (auto p : getTypeList()) { + printer << ch << p.first << ':'; + p.second.print(printer.getStream()); + ch = ','; + } + printer << '}'; + } + recordTypeVisited.erase(uniqueKey()); + } + printer << '>'; } void fir::RecordType::finalize(llvm::ArrayRef lenPList, @@ -939,13 +616,15 @@ getImpl()->finalize(lenPList, typeList); } -llvm::StringRef fir::RecordType::getName() { return getImpl()->getName(); } +llvm::StringRef fir::RecordType::getName() const { + return getImpl()->getName(); +} -RecordType::TypeList fir::RecordType::getTypeList() { +RecordType::TypeList fir::RecordType::getTypeList() const { return getImpl()->getTypeList(); } -RecordType::TypeList fir::RecordType::getLenParamList() { +RecordType::TypeList fir::RecordType::getLenParamList() const { return getImpl()->getLenParamList(); } @@ -968,327 +647,242 @@ return {}; } +unsigned fir::RecordType::getFieldIndex(llvm::StringRef ident) { + for (auto f : llvm::enumerate(getTypeList())) + if (ident == f.value().first) + return f.index(); + return std::numeric_limits::max(); +} + //===----------------------------------------------------------------------===// -// Type descriptor type +// ReferenceType //===----------------------------------------------------------------------===// -TypeDescType fir::TypeDescType::get(mlir::Type ofType) { - assert(!ofType.isa()); - return Base::get(ofType.getContext(), ofType); +// `ref` `<` type `>` +mlir::Type fir::ReferenceType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseTypeSingleton(parser); } -mlir::Type fir::TypeDescType::getOfTy() const { return getImpl()->getOfType(); } +void fir::ReferenceType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getEleTy() << '>'; +} -mlir::LogicalResult fir::TypeDescType::verify( +mlir::LogicalResult fir::ReferenceType::verify( llvm::function_ref emitError, mlir::Type eleTy) { - if (eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa() || - eleTy.isa() || eleTy.isa()) - return emitError() << "cannot build a type descriptor of type: " << eleTy - << '\n'; + if (eleTy.isa()) + return emitError() << "cannot build a reference to type: " << eleTy << '\n'; return mlir::success(); } //===----------------------------------------------------------------------===// -// Vector type +// SequenceType //===----------------------------------------------------------------------===// -fir::VectorType fir::VectorType::get(uint64_t len, mlir::Type eleTy) { - return Base::get(eleTy.getContext(), len, eleTy); +// `array` `<` `*` | bounds (`x` bounds)* `:` type (',' affine-map)? `>` +// bounds ::= `?` | int-lit +mlir::Type fir::SequenceType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + if (parser.parseLess()) { + parser.emitError(parser.getNameLoc(), "expecting '<'"); + return {}; + } + SequenceType::Shape shape; + if (parser.parseOptionalStar()) { + if (parser.parseDimensionList(shape, /*allowDynamic=*/true)) { + parser.emitError(parser.getNameLoc(), "invalid shape"); + return {}; + } + } else if (parser.parseColon()) { + parser.emitError(parser.getNameLoc(), "expected ':'"); + return {}; + } + mlir::Type eleTy; + if (parser.parseType(eleTy) || parser.parseGreater()) { + parser.emitError(parser.getNameLoc(), "expecting element type"); + return {}; + } + mlir::AffineMapAttr map; + if (!parser.parseOptionalComma()) + if (parser.parseAttribute(map)) { + parser.emitError(parser.getNameLoc(), "expecting affine map"); + return {}; + } + return SequenceType::get(context, shape, eleTy, map); } -mlir::Type fir::VectorType::getEleTy() const { return getImpl()->getEleTy(); } - -uint64_t fir::VectorType::getLen() const { return getImpl()->getLen(); } +void fir::SequenceType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic(); + auto shape = getShape(); + if (shape.size()) { + printer << '<'; + for (const auto &b : shape) { + if (b >= 0) + printer << b << 'x'; + else + printer << "?x"; + } + } else { + printer << "<*:"; + } + printer << getEleTy(); + if (auto map = getLayoutMap()) { + printer << ", "; + map.print(printer.getStream()); + } + printer << '>'; +} -mlir::LogicalResult fir::VectorType::verify( - llvm::function_ref emitError, uint64_t len, - mlir::Type eleTy) { - if (!(fir::isa_real(eleTy) || fir::isa_integer(eleTy))) - return emitError() << "cannot build a vector of type " << eleTy << '\n'; - return mlir::success(); +unsigned fir::SequenceType::getConstantRows() const { + auto shape = getShape(); + unsigned count = 0; + for (auto d : shape) { + if (d < 0) + break; + ++count; + } + return count; } -namespace { +// This test helps us determine if we can degenerate an array to a +// pointer to some interior section (possibly a single element) of the +// sequence. This is used to determine if we can lower to the LLVM IR. +bool fir::SequenceType::hasConstantInterior() const { + if (hasUnknownShape()) + return true; + auto rows = getConstantRows(); + auto dim = getDimension(); + if (rows == dim) + return true; + auto shape = getShape(); + for (unsigned i = rows, size = dim; i < size; ++i) + if (shape[i] != getUnknownExtent()) + return false; + return true; +} -void printBounds(llvm::raw_ostream &os, const SequenceType::Shape &bounds) { - os << '<'; - for (auto &b : bounds) { - if (b >= 0) - os << b << 'x'; - else - os << "?x"; - } +mlir::LogicalResult fir::SequenceType::verify( + llvm::function_ref emitError, + llvm::ArrayRef shape, mlir::Type eleTy, + mlir::AffineMapAttr layoutMap) { + // DIMENSION attribute can only be applied to an intrinsic or record type + if (eleTy.isa()) + return emitError() << "cannot build an array of this element type: " + << eleTy << '\n'; + return mlir::success(); } -llvm::SmallPtrSet recordTypeVisited; +//===----------------------------------------------------------------------===// +// ShapeType +//===----------------------------------------------------------------------===// -} // namespace +mlir::Type fir::ShapeType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseRankSingleton(parser); +} -void fir::verifyIntegralType(mlir::Type type) { - if (isaIntegerType(type) || type.isa()) - return; - llvm::report_fatal_error("expected integral type"); +void fir::ShapeType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getImpl()->rank << ">"; } -void fir::printFirType(FIROpsDialect *, mlir::Type ty, - mlir::DialectAsmPrinter &p) { - auto &os = p.getStream(); - if (auto type = ty.dyn_cast()) { - // Fortran derived type - os << "type<" << type.getName(); - if (!recordTypeVisited.count(type.uniqueKey())) { - recordTypeVisited.insert(type.uniqueKey()); - if (type.getLenParamList().size()) { - char ch = '('; - for (auto p : type.getLenParamList()) { - os << ch << p.first << ':'; - p.second.print(os); - ch = ','; - } - os << ')'; - } - if (type.getTypeList().size()) { - char ch = '{'; - for (auto p : type.getTypeList()) { - os << ch << p.first << ':'; - p.second.print(os); - ch = ','; - } - os << '}'; - } - recordTypeVisited.erase(type.uniqueKey()); - } - os << '>'; - return; - } - if (auto type = ty.dyn_cast()) { - os << "slice<" << type.getRank() << '>'; - return; - } - if (auto type = ty.dyn_cast()) { - os << "heap<"; - p.printType(type.getEleTy()); - os << '>'; - return; - } - if (auto type = ty.dyn_cast()) { - // Fortran intrinsic type INTEGER - os << "int<" << type.getFKind() << '>'; - return; - } - if (auto type = ty.dyn_cast()) { - os << "len"; - return; - } - if (auto type = ty.dyn_cast()) { - // Fortran intrinsic type LOGICAL - os << "logical<" << type.getFKind() << '>'; - return; - } - if (auto type = ty.dyn_cast()) { - os << "ptr<"; - p.printType(type.getEleTy()); - os << '>'; - return; - } - if (auto type = ty.dyn_cast()) { - // Fortran intrinsic types REAL and DOUBLE PRECISION - os << "real<" << type.getFKind() << '>'; - return; - } - if (auto type = ty.dyn_cast()) { - os << "ref<"; - p.printType(type.getEleTy()); - os << '>'; - return; - } - if (auto type = ty.dyn_cast()) { - os << "array"; - auto shape = type.getShape(); - if (shape.size()) { - printBounds(os, shape); - } else { - os << "<*:"; - } - p.printType(ty.cast().getEleTy()); - if (auto map = type.getLayoutMap()) { - os << ", "; - map.print(os); - } - os << '>'; - return; - } - if (auto type = ty.dyn_cast()) { - os << "tdesc<"; - p.printType(type.getOfTy()); - os << '>'; - return; - } - if (auto type = ty.dyn_cast()) { - os << "vector<" << type.getLen() << ':'; - p.printType(type.getEleTy()); - os << '>'; - return; - } +//===----------------------------------------------------------------------===// +// ShapeShiftType +//===----------------------------------------------------------------------===// - if (mlir::succeeded(generatedTypePrinter(ty, p))) { - return; - } +mlir::Type fir::ShapeShiftType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseRankSingleton(parser); } -bool fir::isa_unknown_size_box(mlir::Type t) { - if (auto boxTy = t.dyn_cast()) { - auto eleTy = boxTy.getEleTy(); - if (auto actualEleTy = fir::dyn_cast_ptrEleTy(eleTy)) - eleTy = actualEleTy; - if (eleTy.isa()) - return true; - if (auto seqTy = eleTy.dyn_cast()) - if (seqTy.hasUnknownShape()) - return true; - } - return false; +void fir::ShapeShiftType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getRank() << ">"; } //===----------------------------------------------------------------------===// -// BoxProcType +// ShiftType //===----------------------------------------------------------------------===// -// `boxproc` `<` return-type `>` -mlir::Type BoxProcType::parse(mlir::MLIRContext *context, - mlir::DialectAsmParser &parser) { - mlir::Type ty; - if (parser.parseLess() || parser.parseType(ty) || parser.parseGreater()) { - parser.emitError(parser.getCurrentLocation(), "type expected"); - return Type(); - } - return get(context, ty); +mlir::Type fir::ShiftType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseRankSingleton(parser); } -mlir::LogicalResult -BoxProcType::verify(llvm::function_ref emitError, - mlir::Type eleTy) { - if (eleTy.isa()) - return mlir::success(); - if (auto refTy = eleTy.dyn_cast()) - if (refTy.isa()) - return mlir::success(); - return emitError() << "invalid type for boxproc" << eleTy << '\n'; +void fir::ShiftType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getRank() << ">"; } //===----------------------------------------------------------------------===// -// BoxType +// SliceType //===----------------------------------------------------------------------===// -// `box` `<` type (',' affine-map)? `>` -mlir::Type fir::BoxType::parse(mlir::MLIRContext *context, - mlir::DialectAsmParser &parser) { - mlir::Type ofTy; - if (parser.parseLess() || parser.parseType(ofTy)) { - parser.emitError(parser.getCurrentLocation(), "expected type parameter"); - return Type(); - } - - mlir::AffineMapAttr map; - if (!parser.parseOptionalComma()) { - if (parser.parseAttribute(map)) { - parser.emitError(parser.getCurrentLocation(), "expected affine map"); - return Type(); - } - } - if (parser.parseGreater()) { - parser.emitError(parser.getCurrentLocation(), "expected '>'"); - return Type(); - } - return get(ofTy, map); +// `slice` `<` rank `>` +mlir::Type fir::SliceType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseRankSingleton(parser); } -void fir::BoxType::print(::mlir::DialectAsmPrinter &printer) const { - printer << "box<"; - printer.printType(getEleTy()); - if (auto map = getLayoutMap()) { - printer << ", "; - printer.printAttribute(map); - } - printer << '>'; +void fir::SliceType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getRank() << '>'; } //===----------------------------------------------------------------------===// -// BoxCharType +// TypeDescType //===----------------------------------------------------------------------===// -mlir::Type fir::BoxCharType::parse(mlir::MLIRContext *context, - mlir::DialectAsmParser &parser) { - int kind = 0; - if (parser.parseLess() || parser.parseInteger(kind) || - parser.parseGreater()) { - parser.emitError(parser.getCurrentLocation(), "kind value expected"); - return Type(); - } - return get(context, kind); +// `tdesc` `<` type `>` +mlir::Type fir::TypeDescType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + return parseTypeSingleton(parser); } -CharacterType -fir::BoxCharType::getElementType(mlir::MLIRContext *context) const { - return CharacterType::getUnknownLen(context, getKind()); +void fir::TypeDescType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getOfTy() << '>'; } -CharacterType fir::BoxCharType::getEleTy() const { - return getElementType(getContext()); +mlir::LogicalResult fir::TypeDescType::verify( + llvm::function_ref emitError, + mlir::Type eleTy) { + if (eleTy.isa()) + return emitError() << "cannot build a type descriptor of type: " << eleTy + << '\n'; + return mlir::success(); } //===----------------------------------------------------------------------===// -// CharacterType +// VectorType //===----------------------------------------------------------------------===// -// `char` `<` kind [`,` `len`] `>` -mlir::Type fir::CharacterType::parse(mlir::MLIRContext *context, - mlir::DialectAsmParser &parser) { - int kind = 0; - if (parser.parseLess() || parser.parseInteger(kind)) { - parser.emitError(parser.getCurrentLocation(), "kind value expected"); - return Type(); - } - CharacterType::LenType len = 1; - if (mlir::succeeded(parser.parseOptionalComma())) { - if (mlir::succeeded(parser.parseOptionalQuestion())) { - len = fir::CharacterType::unknownLen(); - } else if (!mlir::succeeded(parser.parseInteger(len))) { - parser.emitError(parser.getCurrentLocation(), "len value expected"); - return Type(); - } +// `vector` `<` len `:` type `>` +mlir::Type fir::VectorType::parse(mlir::MLIRContext *context, + mlir::DialectAsmParser &parser) { + int64_t len = 0; + mlir::Type eleTy; + if (parser.parseLess() || parser.parseInteger(len) || parser.parseColon() || + parser.parseType(eleTy) || parser.parseGreater()) { + parser.emitError(parser.getNameLoc(), "invalid vector type"); + return {}; } - if (parser.parseGreater()) - return Type(); - return get(context, kind, len); + return fir::VectorType::get(len, eleTy); } -void fir::CharacterType::print(::mlir::DialectAsmPrinter &printer) const { - printer << "char<" << getFKind(); - auto len = getLen(); - if (len != fir::CharacterType::singleton()) { - printer << ','; - if (len == fir::CharacterType::unknownLen()) - printer << '?'; - else - printer << len; - } - printer << '>'; +void fir::VectorType::print(mlir::DialectAsmPrinter &printer) const { + printer << getMnemonic() << "<" << getLen() << ':' << getEleTy() << '>'; } -//===----------------------------------------------------------------------===// -// ComplexType -//===----------------------------------------------------------------------===// - -mlir::Type fir::ComplexType::parse(mlir::MLIRContext *context, - mlir::DialectAsmParser &parser) { - return parseKindSingleton(parser); +mlir::LogicalResult fir::VectorType::verify( + llvm::function_ref emitError, uint64_t len, + mlir::Type eleTy) { + if (!(fir::isa_real(eleTy) || fir::isa_integer(eleTy))) + return emitError() << "cannot build a vector of type " << eleTy << '\n'; + return mlir::success(); } -mlir::Type fir::ComplexType::getElementType() const { - return fir::RealType::get(getContext(), getFKind()); +bool fir::VectorType::isValidElementType(mlir::Type t) { + return isa_real(t) || isa_integer(t); }