diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.h b/flang/include/flang/Optimizer/Dialect/FIROps.h --- a/flang/include/flang/Optimizer/Dialect/FIROps.h +++ b/flang/include/flang/Optimizer/Dialect/FIROps.h @@ -9,6 +9,7 @@ #ifndef OPTIMIZER_DIALECT_FIROPS_H #define OPTIMIZER_DIALECT_FIROPS_H +#include "flang/Optimizer/Dialect/FIRType.h" #include "mlir/Dialect/StandardOps/IR/Ops.h" #include "mlir/Interfaces/LoopLikeInterface.h" #include "mlir/Interfaces/SideEffectInterfaces.h" 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 @@ -32,8 +32,6 @@ "FIR dialect type">; // Fortran intrinsic types -def fir_CharacterType : Type()">, - "FIR character type">; def fir_ComplexType : Type()">, "FIR complex type">; def fir_IntegerType : Type()">, @@ -86,16 +84,12 @@ // A descriptor tuple (captures a reference to an entity and other information) def fir_BoxType : Type()">, "box type">; -// CHARACTER type descriptor. A pair of a data reference and a LEN value. -def fir_BoxCharType : Type()">, - "box character type">; - // PROCEDURE POINTER descriptor. A pair that can capture a host closure. def fir_BoxProcType : Type()">, "box procedure type">; def AnyBoxLike : TypeConstraint, "any box">; + BoxCharType.predicate, fir_BoxProcType.predicate]>, "any box">; def AnyRefOrBox : TypeConstraint, @@ -1140,7 +1134,7 @@ let arguments = (ins AnyReferenceLike:$memref, AnyIntegerLike:$len); - let results = (outs fir_BoxCharType); + let results = (outs BoxCharType); let assemblyFormat = [{ $memref `,` $len attr-dict `:` functional-type(operands, results) @@ -1284,7 +1278,7 @@ ``` }]; - let arguments = (ins fir_BoxCharType:$boxchar); + let arguments = (ins BoxCharType:$boxchar); let results = (outs fir_ReferenceType, AnyIntegerLike); } @@ -1349,7 +1343,7 @@ ``` }]; - let arguments = (ins fir_BoxCharType:$val); + let arguments = (ins BoxCharType:$val); let results = (outs AnyIntegerLike); 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 @@ -43,9 +43,7 @@ namespace detail { struct BoxTypeStorage; -struct BoxCharTypeStorage; struct BoxProcTypeStorage; -struct CharacterTypeStorage; struct ComplexTypeStorage; struct FieldTypeStorage; struct HeapTypeStorage; @@ -101,37 +99,6 @@ // Intrinsic types -/// Model of the Fortran CHARACTER intrinsic type, including the KIND type -/// parameter. The model optionally includes a LEN type parameter. A -/// CharacterType is thus the type of both a single character value and a -/// character with a LEN parameter. -class CharacterType - : public mlir::Type::TypeBase { -public: - using Base::Base; - using LenType = std::int64_t; - - static CharacterType get(mlir::MLIRContext *ctxt, KindTy kind, LenType len); - /// Return unknown length CHARACTER type. - static CharacterType getUnknownLen(mlir::MLIRContext *ctxt, KindTy kind) { - return get(ctxt, kind, unknownLen()); - } - /// Return length 1 CHARACTER type. - static CharacterType getSingleton(mlir::MLIRContext *ctxt, KindTy kind) { - return get(ctxt, kind, singleton()); - } - KindTy getFKind() const; - - /// CHARACTER is a singleton and has a LEN of 1. - static constexpr LenType singleton() { return 1; } - /// CHARACTER has an unknown LEN property. - static constexpr LenType unknownLen() { return -1; } - - /// Access to a CHARACTER's LEN property. Defaults to 1. - LenType getLen() const; -}; - /// Model of a Fortran COMPLEX intrinsic type, including the KIND type /// parameter. COMPLEX is a floating point type with a real and imaginary /// member. @@ -196,17 +163,6 @@ mlir::AffineMapAttr map); }; -/// The type of a pair that describes a CHARACTER variable. Specifically, a -/// CHARACTER consists of a reference to a buffer (the string value) and a LEN -/// type parameter (the runtime length of the buffer). -class BoxCharType : public mlir::Type::TypeBase { -public: - using Base::Base; - static BoxCharType get(mlir::MLIRContext *ctxt, KindTy kind); - CharacterType getEleTy() const; -}; - /// The type of a pair that describes a PROCEDURE reference. Pointers to /// internal procedures must carry an additional reference to the host's /// variables that are referenced. 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 @@ -48,4 +48,114 @@ }]; } +def A_CharacterType : FIR_Type<"Character", "char"> { + let summary = "FIR character type"; + + let description = [{ + Model of the Fortran CHARACTER intrinsic type, including the KIND type + parameter. The model optionally includes a LEN type parameter. A + CharacterType is thus the type of both a single character value and a + character with a LEN parameter. + }]; + + let parameters = (ins "KindTy":$FKind, "CharacterType::LenType":$len); + + let printer = [{ + $_printer << "char<" << getImpl()->FKind; + auto len = getImpl()->len; + if (len != fir::CharacterType::singleton()) { + $_printer << ','; + if (len == fir::CharacterType::unknownLen()) + $_printer << '?'; + else + $_printer << len; + } + $_printer << '>'; + }]; + + // `char` `<` kind [`,` `len`] `>` + let 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(); + } + } + if ($_parser.parseGreater()) + return Type(); + return get(context, kind, len); + }]; + + let extraClassDeclaration = [{ + using KindTy = unsigned; + using LenType = std::int64_t; + + // Return unknown length CHARACTER type. + static CharacterType getUnknownLen(mlir::MLIRContext *ctxt, KindTy kind) { + return get(ctxt, kind, unknownLen()); + } + + // Return length 1 CHARACTER type. + static CharacterType getSingleton(mlir::MLIRContext *ctxt, KindTy kind) { + return get(ctxt, kind, singleton()); + } + + // CHARACTER is a singleton and has a LEN of 1. + static constexpr LenType singleton() { return 1; } + // CHARACTER has an unknown LEN property. + static constexpr LenType unknownLen() { return -1; } + }]; +} + +def BoxCharType : FIR_Type<"BoxChar", "boxchar"> { + let summary = "CHARACTER type descriptor."; + + let description = [{ + The type of a pair that describes a CHARACTER variable. Specifically, a + CHARACTER consists of a reference to a buffer (the string value) and a LEN + type parameter (the runtime length of the buffer). + }]; + + let parameters = (ins "KindTy":$kind); + + let printer = [{ + $_printer << "boxchar<" << getImpl()->kind << ">"; + }]; + + let 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); + }]; + + let genAccessors = 1; + + let extraClassDeclaration = [{ + using KindTy = unsigned; + + // a !fir.boxchar always wraps a !fir.char + CharacterType getElementType(mlir::MLIRContext *ctxt) const { + return CharacterType::getUnknownLen(ctxt, getKind()); + } + + CharacterType getEleTy() const { + return getElementType(getContext()); + } + }]; + + +} + #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 @@ -79,37 +79,11 @@ return BoxType::get(ofTy, map); } -// `boxchar` `<` kind `>` -BoxCharType parseBoxChar(mlir::DialectAsmParser &parser) { - return parseKindSingleton(parser); -} - // `boxproc` `<` return-type `>` BoxProcType parseBoxProc(mlir::DialectAsmParser &parser, mlir::Location loc) { return parseTypeSingleton(parser, loc); } -// `char` `<` kind [`,` `len`] `>` -CharacterType parseCharacter(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 CharacterType::get(parser.getBuilder().getContext(), kind, len); -} - // `complex` `<` kind `>` fir::ComplexType parseComplex(mlir::DialectAsmParser &parser) { return parseKindSingleton(parser); @@ -356,17 +330,20 @@ if (mlir::failed(parser.parseKeyword(&typeNameLit))) return {}; + // 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 parseBox(parser, loc); if (typeNameLit == "boxchar") - return parseBoxChar(parser); + return BoxCharType::parse(dialect->getContext(), parser); if (typeNameLit == "boxproc") return parseBoxProc(parser, loc); if (typeNameLit == "char") - return parseCharacter(parser); + return CharacterType::parse(dialect->getContext(), parser); if (typeNameLit == "complex") return parseComplex(parser); if (typeNameLit == "field") @@ -386,7 +363,6 @@ if (typeNameLit == "ref") return parseReference(parser, loc); if (typeNameLit == "shape") - // TODO move to generatedTypeParser when all types have been moved return ShapeType::parse(dialect->getContext(), parser); if (typeNameLit == "shapeshift") return parseShapeShift(parser); @@ -410,39 +386,6 @@ // Type storage classes -/// `CHARACTER` storage -struct CharacterTypeStorage : public mlir::TypeStorage { - using KeyTy = std::tuple; - - static unsigned hashKey(const KeyTy &key) { - auto hashVal = llvm::hash_combine(std::get<0>(key)); - return llvm::hash_combine(hashVal, llvm::hash_combine(std::get<1>(key))); - } - - bool operator==(const KeyTy &key) const { - return key == KeyTy{getFKind(), getLen()}; - } - - static CharacterTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - const KeyTy &key) { - auto *storage = allocator.allocate(); - return new (storage) - CharacterTypeStorage{std::get<0>(key), std::get<1>(key)}; - } - - KindTy getFKind() const { return kind; } - CharacterType::LenType getLen() const { return len; } - -protected: - KindTy kind; - CharacterType::LenType len; - -private: - CharacterTypeStorage() = delete; - explicit CharacterTypeStorage(KindTy kind, CharacterType::LenType len) - : kind{kind}, len{len} {} -}; - struct ShapeShiftTypeStorage : public mlir::TypeStorage { using KeyTy = unsigned; @@ -658,35 +601,6 @@ : eleTy{eleTy}, map{map} {} }; -/// Boxed CHARACTER object type -struct BoxCharTypeStorage : 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 BoxCharTypeStorage *construct(mlir::TypeStorageAllocator &allocator, - KindTy kind) { - auto *storage = allocator.allocate(); - return new (storage) BoxCharTypeStorage{kind}; - } - - KindTy getFKind() const { return kind; } - - // a !fir.boxchar always wraps a !fir.char - CharacterType getElementType(mlir::MLIRContext *ctxt) const { - return CharacterType::getUnknownLen(ctxt, getFKind()); - } - -protected: - KindTy kind; - -private: - BoxCharTypeStorage() = delete; - explicit BoxCharTypeStorage(KindTy kind) : kind{kind} {} -}; - /// Boxed PROCEDURE POINTER object type struct BoxProcTypeStorage : public mlir::TypeStorage { using KeyTy = mlir::Type; @@ -981,19 +895,6 @@ } // namespace fir -// CHARACTER - -CharacterType fir::CharacterType::get(mlir::MLIRContext *ctxt, KindTy kind, - CharacterType::LenType len) { - return Base::get(ctxt, kind, len); -} - -KindTy fir::CharacterType::getFKind() const { return getImpl()->getFKind(); } - -CharacterType::LenType fir::CharacterType::getLen() const { - return getImpl()->getLen(); -} - // Field FieldType fir::FieldType::get(mlir::MLIRContext *ctxt) { @@ -1063,16 +964,6 @@ return mlir::success(); } -// BoxChar - -BoxCharType fir::BoxCharType::get(mlir::MLIRContext *ctxt, KindTy kind) { - return Base::get(ctxt, kind); -} - -CharacterType fir::BoxCharType::getEleTy() const { - return getImpl()->getElementType(getContext()); -} - // BoxProc BoxProcType fir::BoxProcType::get(mlir::Type elementType) { @@ -1389,8 +1280,7 @@ return; } if (auto type = ty.dyn_cast()) { - os << "boxchar<" << type.getEleTy().cast().getFKind() - << '>'; + type.print(p); return; } if (auto type = ty.dyn_cast()) { @@ -1400,17 +1290,7 @@ return; } if (auto chTy = ty.dyn_cast()) { - // Fortran intrinsic type CHARACTER - os << "char<" << chTy.getFKind(); - auto len = chTy.getLen(); - if (len != fir::CharacterType::singleton()) { - os << ','; - if (len == fir::CharacterType::unknownLen()) - os << '?'; - else - os << len; - } - os << '>'; + chTy.print(p); return; } if (auto type = ty.dyn_cast()) {