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, @@ -1138,7 +1132,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) @@ -1282,7 +1276,7 @@ ``` }]; - let arguments = (ins fir_BoxCharType:$boxchar); + let arguments = (ins BoxCharType:$boxchar); let results = (outs fir_ReferenceType, AnyIntegerLike); } @@ -1347,7 +1341,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; @@ -100,37 +98,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. @@ -195,17 +162,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 @@ -73,4 +73,64 @@ }]; } +def 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 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 genAccessors = 1; + + let extraClassDeclaration = [{ + using KindTy = unsigned; + + // a !fir.boxchar always wraps a !fir.char + CharacterType getElementType(mlir::MLIRContext *context) const; + + CharacterType getEleTy() const; + }]; +} + #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); @@ -351,17 +325,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 generatedTypeParser(dialect->getContext(), parser, typeNameLit); if (typeNameLit == "boxproc") return parseBoxProc(parser, loc); if (typeNameLit == "char") - return parseCharacter(parser); + return generatedTypeParser(dialect->getContext(), parser, typeNameLit); if (typeNameLit == "complex") return parseComplex(parser); if (typeNameLit == "field") @@ -404,39 +381,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 SliceTypeStorage : public mlir::TypeStorage { using KeyTy = unsigned; @@ -629,35 +573,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; @@ -952,19 +867,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) { @@ -1034,16 +936,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) { @@ -1350,31 +1242,12 @@ os << '>'; return; } - if (auto type = ty.dyn_cast()) { - os << "boxchar<" << type.getEleTy().cast().getFKind() - << '>'; - return; - } if (auto type = ty.dyn_cast()) { os << "boxproc<"; p.printType(type.getEleTy()); os << '>'; 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 << '>'; - return; - } if (auto type = ty.dyn_cast()) { // Fortran intrinsic type COMPLEX os << "complex<" << type.getFKind() << '>'; @@ -1500,3 +1373,69 @@ } return false; } + +namespace fir { + +//===----------------------------------------------------------------------===// +// BoxCharType +//===----------------------------------------------------------------------===// + +mlir::Type 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); +} + +CharacterType BoxCharType::getElementType(mlir::MLIRContext *context) const { + return CharacterType::getUnknownLen(context, getKind()); +} + +CharacterType BoxCharType::getEleTy() const { + return getElementType(getContext()); +} + +//===----------------------------------------------------------------------===// +// CharacterType +//===----------------------------------------------------------------------===// + +// `char` `<` kind [`,` `len`] `>` +mlir::Type 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(); + } + } + if (parser.parseGreater()) + return Type(); + return get(context, kind, len); +} + +void 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 << '>'; +} + +} // namespace fir