Index: flang/include/flang/Common/Fortran-features.h =================================================================== --- flang/include/flang/Common/Fortran-features.h +++ flang/include/flang/Common/Fortran-features.h @@ -33,7 +33,7 @@ ProgramReturn, ImplicitNoneTypeNever, ImplicitNoneTypeAlways, ForwardRefImplicitNone, OpenAccessAppend, BOZAsDefaultInteger, DistinguishableSpecifics, DefaultSave, PointerInSeqType, NonCharacterFormat, - SaveMainProgram, SaveBigMainProgramVariables) + SaveMainProgram, SaveBigMainProgramVariables, Vector) using LanguageFeatures = EnumSet; Index: flang/include/flang/Common/Fortran.h =================================================================== --- flang/include/flang/Common/Fortran.h +++ flang/include/flang/Common/Fortran.h @@ -19,7 +19,10 @@ namespace Fortran::common { // Fortran has five kinds of intrinsic data types, plus the derived types. -ENUM_CLASS(TypeCategory, Integer, Real, Complex, Character, Logical, Derived) +ENUM_CLASS(TypeCategory, Integer, Real, Complex, Character, Logical, Derived, + Vector, // Extension +) +ENUM_CLASS(VectorElementCategory, Integer, Unsigned, Real) constexpr bool IsNumericTypeCategory(TypeCategory category) { return category == TypeCategory::Integer || category == TypeCategory::Real || Index: flang/include/flang/Evaluate/expression.h =================================================================== --- flang/include/flang/Evaluate/expression.h +++ flang/include/flang/Evaluate/expression.h @@ -753,6 +753,13 @@ u; }; +template <> class Expr : public ExpressionBase { +public: + using Result = SomeVector; + EVALUATE_UNION_CLASS_BOILERPLATE(Expr) + std::variant, FunctionRef> u; +}; + // A polymorphic expression of known intrinsic type category, but dynamic // kind, represented as a discriminated union over Expr> // for each supported kind K in the category. @@ -874,7 +881,9 @@ }; FOR_EACH_CATEGORY_TYPE(extern template class Expr, ) +FOR_VECTOR_TYPE(extern template class Expr, ) FOR_EACH_TYPE_AND_KIND(extern template class ExpressionBase, ) +FOR_VECTOR_TYPE(extern template class ExpressionBase, ) FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructorValues, ) FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructor, ) @@ -882,11 +891,13 @@ #define INSTANTIATE_EXPRESSION_TEMPLATES \ FOR_EACH_INTRINSIC_KIND(template class Expr, ) \ FOR_EACH_CATEGORY_TYPE(template class Expr, ) \ + FOR_VECTOR_TYPE(template class Expr, ) \ FOR_EACH_INTEGER_KIND(template class Relational, ) \ FOR_EACH_REAL_KIND(template class Relational, ) \ FOR_EACH_CHARACTER_KIND(template class Relational, ) \ template class Relational; \ FOR_EACH_TYPE_AND_KIND(template class ExpressionBase, ) \ + FOR_VECTOR_TYPE(template class ExpressionBase, ) \ FOR_EACH_INTRINSIC_KIND(template class ArrayConstructorValues, ) \ FOR_EACH_INTRINSIC_KIND(template class ArrayConstructor, ) } // namespace Fortran::evaluate Index: flang/include/flang/Evaluate/tools.h =================================================================== --- flang/include/flang/Evaluate/tools.h +++ flang/include/flang/Evaluate/tools.h @@ -852,6 +852,8 @@ dyType.kind(), std::move(x)); case TypeCategory::Derived: return AsGenericExpr(Expr{WRAPPER{std::move(x)}}); + case TypeCategory::Vector: + return AsGenericExpr(Expr{WRAPPER{std::move(x)}}); } } Index: flang/include/flang/Evaluate/type.h =================================================================== --- flang/include/flang/Evaluate/type.h +++ flang/include/flang/Evaluate/type.h @@ -35,6 +35,7 @@ namespace Fortran::semantics { class DeclTypeSpec; class DerivedTypeSpec; +class VectorTypeSpec; class ParamValue; class Symbol; bool IsDescriptor(const Symbol &); @@ -105,6 +106,8 @@ kind_ = ClassKind; } } + explicit constexpr DynamicType(const semantics::VectorTypeSpec &vt) + : category_{TypeCategory::Vector}, vector_{&vt} {} CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(DynamicType) // A rare use case used for representing the characteristics of an @@ -123,6 +126,7 @@ result.category_ = TypeCategory::Derived; result.kind_ = ClassKind; result.derived_ = nullptr; + result.vector_ = nullptr; return result; // CLASS(*) } @@ -131,6 +135,7 @@ result.category_ = TypeCategory::Derived; result.kind_ = AssumedTypeKind; result.derived_ = nullptr; + result.vector_ = nullptr; return result; // TYPE(*) } @@ -180,6 +185,9 @@ constexpr const semantics::DerivedTypeSpec &GetDerivedTypeSpec() const { return DEREF(derived_); } + constexpr const semantics::VectorTypeSpec &GetVectorTypeSpec() const { + return DEREF(vector_); + } bool RequiresDescriptor() const; bool HasDeferredTypeParameter() const; @@ -245,6 +253,7 @@ std::optional knownLength_; #endif const semantics::DerivedTypeSpec *derived_{nullptr}; // TYPE(T), CLASS(T) + const semantics::VectorTypeSpec *vector_{nullptr}; // VECTOR(NumericType) }; // Return the DerivedTypeSpec of a DynamicType if it has one. @@ -255,6 +264,7 @@ const semantics::DerivedTypeSpec &); std::string DerivedTypeSpecAsFortran(const semantics::DerivedTypeSpec &); +std::string VectorTypeSpecAsFortran(const semantics::VectorTypeSpec &); template struct TypeBase { static constexpr TypeCategory category{CATEGORY}; @@ -424,14 +434,39 @@ const semantics::DerivedTypeSpec *derivedTypeSpec_{nullptr}; }; +template <> class SomeKind { +public: + static constexpr TypeCategory category{TypeCategory::Vector}; + + constexpr explicit SomeKind(const semantics::VectorTypeSpec &vts) + : vectorTypeSpec_{&vts} {} + constexpr explicit SomeKind(const DynamicType &vt) + : SomeKind(vt.GetVectorTypeSpec()) {} + CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(SomeKind) + + constexpr DynamicType GetType() const { + return DynamicType{*vectorTypeSpec_}; + } + const semantics::VectorTypeSpec &vectorTypeSpec() const { + CHECK(vectorTypeSpec_); + return *vectorTypeSpec_; + } + bool operator==(const SomeKind &) const; + std::string AsFortran() const; + +private: + const semantics::VectorTypeSpec *vectorTypeSpec_{nullptr}; +}; + using SomeInteger = SomeKind; using SomeReal = SomeKind; using SomeComplex = SomeKind; using SomeCharacter = SomeKind; using SomeLogical = SomeKind; using SomeDerived = SomeKind; +using SomeVector = SomeKind; using SomeCategory = std::tuple; + SomeCharacter, SomeLogical, SomeDerived, SomeVector>; using AllTypes = common::CombineTuples>; @@ -525,8 +560,11 @@ PREFIX SUFFIX; \ PREFIX SUFFIX; \ PREFIX SUFFIX; + #define FOR_EACH_TYPE_AND_KIND(PREFIX, SUFFIX) \ FOR_EACH_INTRINSIC_KIND(PREFIX, SUFFIX) \ FOR_EACH_CATEGORY_TYPE(PREFIX, SUFFIX) + +#define FOR_VECTOR_TYPE(PREFIX, SUFFIX) PREFIX SUFFIX; } // namespace Fortran::evaluate #endif // FORTRAN_EVALUATE_TYPE_H_ Index: flang/include/flang/Evaluate/variable.h =================================================================== --- flang/include/flang/Evaluate/variable.h +++ flang/include/flang/Evaluate/variable.h @@ -387,8 +387,9 @@ public: using Result = T; - static_assert( - IsSpecificIntrinsicType || std::is_same_v); + static_assert(IsSpecificIntrinsicType || + std::is_same_v || + std::is_same_v); EVALUATE_UNION_CLASS_BOILERPLATE(Designator) Designator(const DataRef &that) : u{common::CopyVariant(that.u)} {} Designator(DataRef &&that) @@ -431,6 +432,7 @@ }; #define INSTANTIATE_VARIABLE_TEMPLATES \ - FOR_EACH_SPECIFIC_TYPE(template class Designator, ) + FOR_EACH_SPECIFIC_TYPE(template class Designator, ) \ + FOR_VECTOR_TYPE(template class Designator, ) } // namespace Fortran::evaluate #endif // FORTRAN_EVALUATE_VARIABLE_H_ Index: flang/include/flang/Lower/AbstractConverter.h =================================================================== --- flang/include/flang/Lower/AbstractConverter.h +++ flang/include/flang/Lower/AbstractConverter.h @@ -196,6 +196,10 @@ /// Generate the type from a Variable virtual mlir::Type genType(const pft::Variable &) = 0; + /// Generate the type from a VectorTypeSpec + virtual mlir::Type + genType(const Fortran::semantics::VectorTypeSpec &tySpec) = 0; + /// Register a runtime derived type information object symbol to ensure its /// object will be generated as a global. virtual void registerRuntimeTypeInfo(mlir::Location loc, Index: flang/include/flang/Lower/ConvertType.h =================================================================== --- flang/include/flang/Lower/ConvertType.h +++ flang/include/flang/Lower/ConvertType.h @@ -71,6 +71,11 @@ translateDerivedTypeToFIRType(Fortran::lower::AbstractConverter &, const Fortran::semantics::DerivedTypeSpec &); +/// Get a FIR type for a Vector type. +mlir::Type +translateVectorTypeToFIRType(Fortran::lower::AbstractConverter &, + const Fortran::semantics::VectorTypeSpec &); + /// Translate a SomeExpr to an mlir::Type. mlir::Type translateSomeExprToFIRType(Fortran::lower::AbstractConverter &, const SomeExpr &expr); @@ -96,6 +101,7 @@ }; using namespace evaluate; FOR_EACH_SPECIFIC_TYPE(extern template class TypeBuilder, ) +FOR_VECTOR_TYPE(extern template class TypeBuilder, ) } // namespace lower } // namespace Fortran Index: flang/include/flang/Parser/dump-parse-tree.h =================================================================== --- flang/include/flang/Parser/dump-parse-tree.h +++ flang/include/flang/Parser/dump-parse-tree.h @@ -710,11 +710,14 @@ NODE(Union, EndUnionStmt) NODE(Union, UnionStmt) NODE(parser, UnlockStmt) + NODE(parser, UnsignedTypeSpec) NODE(parser, UseStmt) NODE_ENUM(UseStmt, ModuleNature) NODE(parser, Value) NODE(parser, ValueStmt) NODE(parser, Variable) + NODE(parser, VectorTypeSpec) + NODE(parser, VectorElementType) NODE(parser, Verbatim) NODE(parser, Volatile) NODE(parser, VolatileStmt) Index: flang/include/flang/Parser/parse-tree.h =================================================================== --- flang/include/flang/Parser/parse-tree.h +++ flang/include/flang/Parser/parse-tree.h @@ -708,6 +708,19 @@ u; }; +// Extension: VECTOR type +// VECTOR(integer-type-spec) | VECTOR(REAL [kind-selector]) | +// VECTOR(UNSIGNED [kind-selector]) +WRAPPER_CLASS(UnsignedTypeSpec, std::optional); +struct VectorElementType { + UNION_CLASS_BOILERPLATE(VectorElementType); + VectorElementType(IntegerTypeSpec &&its) : u(std::move(its)) {} + VectorElementType(IntrinsicTypeSpec::Real &&r) : u(std::move(r)) {} + VectorElementType(UnsignedTypeSpec &&us) : u(std::move(us)) {} + std::variant u; +}; +WRAPPER_CLASS(VectorTypeSpec, VectorElementType); + // R755 type-param-spec -> [keyword =] type-param-value struct TypeParamSpec { TUPLE_CLASS_BOILERPLATE(TypeParamSpec); @@ -748,7 +761,9 @@ EMPTY_CLASS(ClassStar); EMPTY_CLASS(TypeStar); WRAPPER_CLASS(Record, Name); - std::variant u; + std::variant + u; }; // R709 kind-param -> digit-string | scalar-int-constant-name Index: flang/include/flang/Semantics/scope.h =================================================================== --- flang/include/flang/Semantics/scope.h +++ flang/include/flang/Semantics/scope.h @@ -211,6 +211,7 @@ DeclTypeSpec &MakeDerivedType(DeclTypeSpec::Category, DerivedTypeSpec &&); const DeclTypeSpec &MakeTypeStarType(); const DeclTypeSpec &MakeClassStarType(); + const DeclTypeSpec &MakeVectorType(VectorElementCategory, KindExpr &&kind); const DeclTypeSpec *GetType(const SomeExpr &); std::size_t size() const { return size_; } Index: flang/include/flang/Semantics/semantics.h =================================================================== --- flang/include/flang/Semantics/semantics.h +++ flang/include/flang/Semantics/semantics.h @@ -155,6 +155,7 @@ const DeclTypeSpec &MakeNumericType(TypeCategory, int kind = 0); const DeclTypeSpec &MakeLogicalType(int kind = 0); + const DeclTypeSpec &MakeVectorType(VectorElementCategory, int kind = 0); bool AnyFatalError() const; Index: flang/include/flang/Semantics/type.h =================================================================== --- flang/include/flang/Semantics/type.h +++ flang/include/flang/Semantics/type.h @@ -46,6 +46,7 @@ using SubscriptIntExpr = evaluate::Expr; using MaybeSubscriptIntExpr = std::optional; using KindExpr = SubscriptIntExpr; +using VectorElementCategory = common::VectorElementCategory; // An array spec bound: an explicit integer expression, assumed size // or implied shape(*), or assumed or deferred shape(:). In the absence @@ -321,6 +322,42 @@ llvm::raw_ostream &, const DerivedTypeSpec &); }; +class VectorTypeSpec { +public: + VectorTypeSpec(VectorElementCategory pVectorElemCategory, KindExpr &&pKind); + + bool operator==(const VectorTypeSpec &x) const { + return vectorElementCategory_ == x.vectorElementCategory() && + vectorElementKind_ == x.vectorElementKind(); + } + bool operator!=(const VectorTypeSpec &x) const { return !operator==(x); } + VectorElementCategory vectorElementCategory() const { + return vectorElementCategory_; + } + int vectorElementKind() const { return vectorElementKind_; } + int vectorAlignment() const { return vectorAlignment_; } + int vectorLenInBytes() const { return vectorLenInBytes_; } + std::string AsFortran() const; + + static TypeCategory elementTypeCatToIntrinsicTypeCat( + VectorElementCategory cat) { + switch (cat) { + SWITCH_COVERS_ALL_CASES + case VectorElementCategory::Integer: + case VectorElementCategory::Unsigned: + return TypeCategory::Integer; + case VectorElementCategory::Real: + return TypeCategory::Real; + } + } + +private: + VectorElementCategory vectorElementCategory_; + int vectorElementKind_; + static const int vectorLenInBytes_ = 16; + static const int vectorAlignment_ = 16; +}; + class DeclTypeSpec { public: enum Category { @@ -330,7 +367,8 @@ TypeDerived, ClassDerived, TypeStar, - ClassStar + ClassStar, + Vector }; // intrinsic-type-spec or TYPE(intrinsic-type-spec), not character @@ -344,6 +382,8 @@ DeclTypeSpec(Category, DerivedTypeSpec &&); // TYPE(*) or CLASS(*) DeclTypeSpec(Category); + // Extension: VECTOR type + DeclTypeSpec(VectorTypeSpec &&); bool operator==(const DeclTypeSpec &) const; bool operator!=(const DeclTypeSpec &that) const { return !operator==(that); } @@ -373,18 +413,24 @@ CHECK(category_ == TypeDerived || category_ == ClassDerived); return std::get(typeSpec_); } + const VectorTypeSpec &vectorTypeSpec() const { + CHECK(category_ == Vector); + return std::get(typeSpec_); + } inline IntrinsicTypeSpec *AsIntrinsic(); inline const IntrinsicTypeSpec *AsIntrinsic() const; inline DerivedTypeSpec *AsDerived(); inline const DerivedTypeSpec *AsDerived() const; + inline VectorTypeSpec *AsVector(); + inline const VectorTypeSpec *AsVector() const; std::string AsFortran() const; private: Category category_; std::variant + CharacterTypeSpec, DerivedTypeSpec, VectorTypeSpec> typeSpec_; }; llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DeclTypeSpec &); @@ -446,6 +492,17 @@ } bool IsInteroperableIntrinsicType(const DeclTypeSpec &); +inline VectorTypeSpec *DeclTypeSpec::AsVector() { + switch (category_) { + case Vector: + return &std::get(typeSpec_); + default: + return nullptr; + } +} +inline const VectorTypeSpec *DeclTypeSpec::AsVector() const { + return const_cast(this)->AsVector(); +} } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_TYPE_H_ Index: flang/lib/Evaluate/expression.cpp =================================================================== --- flang/lib/Evaluate/expression.cpp +++ flang/lib/Evaluate/expression.cpp @@ -224,6 +224,10 @@ return u == that.u; } +bool Expr::operator==(const Expr &that) const { + return u == that.u; +} + bool Expr::operator==(const Expr &that) const { return u == that.u; } Index: flang/lib/Evaluate/fold-implementation.h =================================================================== --- flang/lib/Evaluate/fold-implementation.h +++ flang/lib/Evaluate/fold-implementation.h @@ -2057,6 +2057,8 @@ return FoldOperation(context, std::move(x)); } else if constexpr (std::is_same_v) { return FoldOperation(context, std::move(x)); + } else if constexpr (std::is_same_v) { + return std::move(expr); } else if constexpr (common::HasMember) { return std::move(expr); Index: flang/lib/Evaluate/fold.cpp =================================================================== --- flang/lib/Evaluate/fold.cpp +++ flang/lib/Evaluate/fold.cpp @@ -286,6 +286,7 @@ } template class ExpressionBase; +template class ExpressionBase; template class ExpressionBase; } // namespace Fortran::evaluate Index: flang/lib/Evaluate/formatting.cpp =================================================================== --- flang/lib/Evaluate/formatting.cpp +++ flang/lib/Evaluate/formatting.cpp @@ -484,6 +484,10 @@ result = "CLASS("s + result + ')'; } return result; + } else if (vector_) { + CHECK(category_ == TypeCategory::Vector); + std::string result{VectorTypeSpecAsFortran(*vector_)}; + return result; } else if (charLengthParamValue_ || knownLength()) { std::string result{"CHARACTER(KIND="s + std::to_string(kind_) + ",LEN="}; if (knownLength()) { @@ -547,6 +551,17 @@ return ss.str(); } +std::string SomeVector::AsFortran() const { + return "VECTOR("s + VectorTypeSpecAsFortran(vectorTypeSpec()) + ')'; +} + +std::string VectorTypeSpecAsFortran(const semantics::VectorTypeSpec &spec) { + int kind = spec.vectorElementKind(); + return parser::ToUpperCaseLetters( + EnumToString(spec.vectorElementCategory())) + + '(' + std::to_string(kind) + ')'; +} + llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const Symbol &symbol) { return o << symbol.name().ToString(); } Index: flang/lib/Evaluate/target.cpp =================================================================== --- flang/lib/Evaluate/target.cpp +++ flang/lib/Evaluate/target.cpp @@ -10,6 +10,7 @@ #include "flang/Common/template.h" #include "flang/Evaluate/common.h" #include "flang/Evaluate/type.h" +#include "flang/Semantics/type.h" namespace Fortran::evaluate { Index: flang/lib/Evaluate/tools.cpp =================================================================== --- flang/lib/Evaluate/tools.cpp +++ flang/lib/Evaluate/tools.cpp @@ -47,6 +47,8 @@ return expr; // no parentheses around typeless } else if constexpr (std::is_same_v>) { return AsGenericExpr(Parentheses{std::move(x)}); + } else if constexpr (std::is_same_v>) { + return expr; // no parentheses around Vector Type } else { return common::visit( [](auto &&y) { @@ -495,6 +497,10 @@ messages.Say("Operand cannot be negated"_err_en_US); return NoExpr(); }, + [&](Expr &&) { + messages.Say("VECTOR cannot be negated"_err_en_US); + return NoExpr(); + }, }, std::move(x.u)); } @@ -669,6 +675,9 @@ } } break; + case TypeCategory::Vector: + // No type conversion for Vector types. + return std::nullopt; } return std::nullopt; } Index: flang/lib/Evaluate/type.cpp =================================================================== --- flang/lib/Evaluate/type.cpp +++ flang/lib/Evaluate/type.cpp @@ -133,6 +133,8 @@ if (derived_ && derived_->scope()) { return derived_->scope()->alignment().value_or(1); } + } else if (category_ == TypeCategory::Vector) { + return vector_->vectorAlignment(); } else { return targetCharacteristics.GetAlignment(category_, kind_); } @@ -168,6 +170,9 @@ static_cast(alignedSize)}; } break; + case TypeCategory::Vector: + auto size{vector_->vectorLenInBytes()}; + return Expr{size}; } return std::nullopt; } @@ -458,6 +463,8 @@ const auto yLen{y.knownLength()}; return x.kind() == y.kind() && (ignoreLengths || !xLen || !yLen || *xLen == *yLen); + } else if (x.category() == TypeCategory::Vector) { + return x.GetVectorTypeSpec() == y.GetVectorTypeSpec(); } else if (x.category() != TypeCategory::Derived) { return x.kind() == y.kind(); } else { @@ -540,6 +547,8 @@ return DynamicType::UnlimitedPolymorphic(); } else if (type.category() == semantics::DeclTypeSpec::TypeStar) { return DynamicType::AssumedType(); + } else if (const auto *vectorType{type.AsVector()}) { + return DynamicType{*vectorType}; } else { common::die("DynamicType::From(DeclTypeSpec): failed"); } Index: flang/lib/Lower/Bridge.cpp =================================================================== --- flang/lib/Lower/Bridge.cpp +++ flang/lib/Lower/Bridge.cpp @@ -564,6 +564,10 @@ &getMLIRContext(), tc, bridge.getDefaultKinds().GetDefaultKind(tc), std::nullopt); } + mlir::Type + genType(const Fortran::semantics::VectorTypeSpec &tySpec) override final { + return Fortran::lower::translateVectorTypeToFIRType(*this, tySpec); + } bool createHostAssociateVarClone( const Fortran::semantics::Symbol &sym) override final { @@ -931,6 +935,9 @@ static bool isDerivedCategory(Fortran::common::TypeCategory cat) { return cat == Fortran::common::TypeCategory::Derived; } + static bool isVectorCategory(Fortran::common::TypeCategory cat) { + return cat == Fortran::common::TypeCategory::Vector; + } /// Insert a new block before \p block. Leave the insertion point unchanged. mlir::Block *insertBlock(mlir::Block *block) { @@ -3066,7 +3073,8 @@ // Scalar assignment const bool isNumericScalar = isNumericScalarCategory(lhsType->category()); - fir::ExtendedValue rhs = isNumericScalar + const bool isVector = isVectorCategory(lhsType->category()); + fir::ExtendedValue rhs = (isNumericScalar || isVector) ? genExprValue(assign.rhs, stmtCtx) : genExprAddr(assign.rhs, stmtCtx); const bool lhsIsWholeAllocatable = @@ -3114,7 +3122,7 @@ return genExprAddr(assign.lhs, stmtCtx); }(); - if (isNumericScalar) { + if (isNumericScalar || isVector) { // Fortran 2018 10.2.1.3 p8 and p9 // Conversions should have been inserted by semantic analysis, // but they can be incorrect between the rhs and lhs. Correct @@ -3128,7 +3136,8 @@ // conversion to the actual type. mlir::Type toTy = genType(assign.lhs); mlir::Value cast = - builder->convertWithSemantics(loc, toTy, val); + isVector ? val + : builder->convertWithSemantics(loc, toTy, val); if (fir::dyn_cast_ptrEleTy(addr.getType()) != toTy) { assert(isFuncResultDesignator(assign.lhs) && "type mismatch"); addr = builder->createConvert( Index: flang/lib/Lower/CallInterface.cpp =================================================================== --- flang/lib/Lower/CallInterface.cpp +++ flang/lib/Lower/CallInterface.cpp @@ -795,6 +795,11 @@ mlir::Type mlirType = translateDynamicType(dynamicType); addFirResult(mlirType, FirPlaceHolder::resultEntityPosition, Property::Value); + } else if (dynamicType.category() == + Fortran::common::TypeCategory::Vector) { + mlir::Type mlirType = translateDynamicType(dynamicType); + addFirResult(mlirType, FirPlaceHolder::resultEntityPosition, + Property::Value); } else { // All result other than characters/derived are simply returned by value // in implicit interfaces @@ -909,6 +914,10 @@ if (std::optional constantLen = toInt64(dynamicType.GetCharLength())) return getConverter().genType(cat, dynamicType.kind(), {*constantLen}); + + if (cat == Fortran::common::TypeCategory::Vector) { + return getConverter().genType(dynamicType.GetVectorTypeSpec()); + } // INTEGER, REAL, LOGICAL, COMPLEX, and CHARACTER with dynamic length. return getConverter().genType(cat, dynamicType.kind()); } Index: flang/lib/Lower/ConvertConstant.cpp =================================================================== --- flang/lib/Lower/ConvertConstant.cpp +++ flang/lib/Lower/ConvertConstant.cpp @@ -670,6 +670,9 @@ if constexpr (T::Result::category == Fortran::common::TypeCategory::Derived) { return genConstantValue(converter, loc, x); + } else if constexpr (T::Result::category == + Fortran::common::TypeCategory::Vector) { + fir::emitFatalError(loc, "unexpected Vector constant value"); } else { return std::visit( [&](const auto &preciseKind) { Index: flang/lib/Lower/ConvertExpr.cpp =================================================================== --- flang/lib/Lower/ConvertExpr.cpp +++ flang/lib/Lower/ConvertExpr.cpp @@ -1711,11 +1711,15 @@ } mlir::Type genType(const Fortran::evaluate::DynamicType &dt) { - if (dt.category() != Fortran::common::TypeCategory::Derived) + if (dt.category() == Fortran::common::TypeCategory::Derived) { + if (dt.IsUnlimitedPolymorphic()) + return mlir::NoneType::get(&converter.getMLIRContext()); + return converter.genType(dt.GetDerivedTypeSpec()); + } else if (dt.category() == Fortran::common::TypeCategory::Vector) { + return converter.genType(dt.GetVectorTypeSpec()); + } else { return converter.genType(dt.category(), dt.kind()); - if (dt.IsUnlimitedPolymorphic()) - return mlir::NoneType::get(&converter.getMLIRContext()); - return converter.genType(dt.GetDerivedTypeSpec()); + } } /// Lower a function reference Index: flang/lib/Lower/ConvertType.cpp =================================================================== --- flang/lib/Lower/ConvertType.cpp +++ flang/lib/Lower/ConvertType.cpp @@ -23,6 +23,8 @@ #define DEBUG_TYPE "flang-lower-type" +using Fortran::common::VectorElementCategory; + //===--------------------------------------------------------------------===// // Intrinsic type translation helpers //===--------------------------------------------------------------------===// @@ -53,20 +55,24 @@ return Fortran::evaluate::Type::Scalar::bits; } -static mlir::Type genIntegerType(mlir::MLIRContext *context, int kind) { +static mlir::Type genIntegerType(mlir::MLIRContext *context, int kind, + bool isUnsigned = false) { if (Fortran::evaluate::IsValidKindOfIntrinsicType( Fortran::common::TypeCategory::Integer, kind)) { + mlir::IntegerType::SignednessSemantics signedness = + (isUnsigned ? mlir::IntegerType::SignednessSemantics::Unsigned + : mlir::IntegerType::SignednessSemantics::Signless); switch (kind) { case 1: - return mlir::IntegerType::get(context, getIntegerBits<1>()); + return mlir::IntegerType::get(context, getIntegerBits<1>(), signedness); case 2: - return mlir::IntegerType::get(context, getIntegerBits<2>()); + return mlir::IntegerType::get(context, getIntegerBits<2>(), signedness); case 4: - return mlir::IntegerType::get(context, getIntegerBits<4>()); + return mlir::IntegerType::get(context, getIntegerBits<4>(), signedness); case 8: - return mlir::IntegerType::get(context, getIntegerBits<8>()); + return mlir::IntegerType::get(context, getIntegerBits<8>(), signedness); case 16: - return mlir::IntegerType::get(context, getIntegerBits<16>()); + return mlir::IntegerType::get(context, getIntegerBits<16>(), signedness); } } llvm_unreachable("INTEGER kind not translated"); @@ -150,6 +156,8 @@ baseType = mlir::NoneType::get(context); } else if (category == Fortran::common::TypeCategory::Derived) { baseType = genDerivedType(dynamicType->GetDerivedTypeSpec()); + } else if (category == Fortran::common::TypeCategory::Vector) { + baseType = genVectorType(dynamicType->GetVectorTypeSpec()); } else { // LOGICAL, INTEGER, REAL, COMPLEX, CHARACTER llvm::SmallVector params; @@ -259,6 +267,9 @@ } else if (const Fortran::semantics::DerivedTypeSpec *tySpec = type->AsDerived()) { ty = genDerivedType(*tySpec); + } else if (const Fortran::semantics::VectorTypeSpec *tySpec = + type->AsVector()) { + ty = genVectorType(*tySpec); } else { fir::emitFatalError(loc, "symbol's type must have a type spec"); } @@ -369,6 +380,24 @@ return rec; } + mlir::Type genVectorType(const Fortran::semantics::VectorTypeSpec &tySpec) { + int64_t kind = tySpec.vectorElementKind(); + if (!kind) { + llvm::report_fatal_error("Unspecified kind for vector element type"); + } + int64_t noOfElements = tySpec.vectorLenInBytes() / kind; + switch (tySpec.vectorElementCategory()) { + case VectorElementCategory::Integer: + return fir::VectorType::get(noOfElements, genIntegerType(context, kind)); + case VectorElementCategory::Unsigned: + return fir::VectorType::get(noOfElements, + genIntegerType(context, kind, true)); + case VectorElementCategory::Real: + return fir::VectorType::get(noOfElements, genRealType(context, kind)); + } + llvm_unreachable("Vector element type not implemented"); + } + // To get the character length from a symbol, make an fold a designator for // the symbol to cover the case where the symbol is an assumed length named // constant and its length comes from its init expression length. @@ -494,6 +523,12 @@ return TypeBuilderImpl{converter}.genDerivedType(tySpec); } +mlir::Type Fortran::lower::translateVectorTypeToFIRType( + Fortran::lower::AbstractConverter &converter, + const Fortran::semantics::VectorTypeSpec &tySpec) { + return TypeBuilderImpl{converter}.genVectorType(tySpec); +} + mlir::Type Fortran::lower::translateSomeExprToFIRType( Fortran::lower::AbstractConverter &converter, const SomeExpr &expr) { return TypeBuilderImpl{converter}.genExprType(expr); @@ -533,3 +568,4 @@ using namespace Fortran::evaluate; using namespace Fortran::common; FOR_EACH_SPECIFIC_TYPE(template class Fortran::lower::TypeBuilder, ) +FOR_VECTOR_TYPE(template class Fortran::lower::TypeBuilder, ) Index: flang/lib/Lower/Mangler.cpp =================================================================== --- flang/lib/Lower/Mangler.cpp +++ flang/lib/Lower/Mangler.cpp @@ -231,6 +231,8 @@ return "c" + std::to_string(kind); case Fortran::common::TypeCategory::Derived: return derivedName.str(); + case Fortran::common::TypeCategory::Vector: + return "Vector"; } llvm_unreachable("bad TypeCategory"); } Index: flang/lib/Parser/Fortran-parsers.cpp =================================================================== --- flang/lib/Parser/Fortran-parsers.cpp +++ flang/lib/Parser/Fortran-parsers.cpp @@ -172,6 +172,7 @@ // type (BYTE or DOUBLECOMPLEX), not the extension intrinsic type. TYPE_CONTEXT_PARSER("declaration type spec"_en_US, construct(intrinsicTypeSpec) || + construct(vectorTypeSpec) || "TYPE" >> (parenthesized(construct( !"DOUBLECOMPLEX"_tok >> !"BYTE"_tok >> intrinsicTypeSpec)) || @@ -218,6 +219,18 @@ construct(construct( "BYTE" >> construct>(pure(1))))))) +// Extension: VECTOR type +// VECTOR(integer-type-spec) | VECTOR(REAL [kind-selector]) +TYPE_CONTEXT_PARSER("Vector type spec"_en_US, + extension("nonstandard usage: VECTOR"_port_en_US, + construct("VECTOR" >> + parenthesized(construct(integerTypeSpec) || + construct(unsignedTypeSpec) || + construct(construct( + "REAL" >> maybe(kindSelector))))))) +// UNSIGNED type +TYPE_PARSER(construct("UNSIGNED" >> maybe(kindSelector))) + // R705 integer-type-spec -> INTEGER [kind-selector] TYPE_PARSER(construct("INTEGER" >> maybe(kindSelector))) Index: flang/lib/Parser/type-parsers.h =================================================================== --- flang/lib/Parser/type-parsers.h +++ flang/lib/Parser/type-parsers.h @@ -137,5 +137,7 @@ constexpr Parser openmpConstruct; constexpr Parser openmpDeclarativeConstruct; constexpr Parser ompEndLoopDirective; +constexpr Parser vectorTypeSpec; // Extension +constexpr Parser unsignedTypeSpec; // Extension } // namespace Fortran::parser #endif // FORTRAN_PARSER_TYPE_PARSERS_H_ Index: flang/lib/Parser/unparse.cpp =================================================================== --- flang/lib/Parser/unparse.cpp +++ flang/lib/Parser/unparse.cpp @@ -161,6 +161,9 @@ void Post(const IntrinsicTypeSpec::DoubleComplex &) { Word("DOUBLE COMPLEX"); } + void Before(const UnsignedTypeSpec &) { Word("UNSIGNED"); } + void Before(const VectorTypeSpec &) { Word("VECTOR("); } + void Post(const VectorTypeSpec &) { Put(')'); } void Before(const IntegerTypeSpec &) { // R705 Word("INTEGER"); } Index: flang/lib/Semantics/expression.cpp =================================================================== --- flang/lib/Semantics/expression.cpp +++ flang/lib/Semantics/expression.cpp @@ -4195,6 +4195,7 @@ const DynamicType &lhsType, const DynamicType &rhsType) { if (lhsType.category() == rhsType.category() && (lhsType.category() == TypeCategory::Derived || + lhsType.category() == TypeCategory::Vector || lhsType.kind() == rhsType.kind())) { // no conversion necessary } else if (auto rhsExpr{evaluate::Fold(context_.GetFoldingContext(), Index: flang/lib/Semantics/resolve-names.cpp =================================================================== --- flang/lib/Semantics/resolve-names.cpp +++ flang/lib/Semantics/resolve-names.cpp @@ -678,6 +678,9 @@ const DeclTypeSpec &MakeLogicalType( const std::optional &); const DeclTypeSpec &MakeLogicalType(int); + const DeclTypeSpec &MakeVectorType( + VectorElementCategory, const std::optional &); + const DeclTypeSpec &MakeVectorType(VectorElementCategory, int); void NotePossibleBadForwardRef(const parser::Name &); std::optional HadForwardRef(const Symbol &) const; bool CheckPossibleBadForwardRef(const Symbol &); @@ -936,6 +939,8 @@ void Post(const parser::CharLength &); void Post(const parser::LengthSelector &); bool Pre(const parser::KindParam &); + bool Pre(const parser::VectorTypeSpec &); + void Post(const parser::VectorTypeSpec &); bool Pre(const parser::DeclarationTypeSpec::Type &); void Post(const parser::DeclarationTypeSpec::Type &); bool Pre(const parser::DeclarationTypeSpec::Class &); @@ -1081,6 +1086,7 @@ // to warn about use of the implied DO intex therein. std::optional checkIndexUseInOwnBounds_; bool hasBindCName_{false}; + bool isVectorType{false}; bool HandleAttributeStmt(Attr, const std::list &); Symbol &HandleAttributeStmt(Attr, const parser::Name &); @@ -2601,6 +2607,22 @@ return context().MakeLogicalType(kind); } +const DeclTypeSpec &ScopeHandler::MakeVectorType( + VectorElementCategory elementCategory, + const std::optional &kind) { + KindExpr value{GetKindParamExpr( + VectorTypeSpec::elementTypeCatToIntrinsicTypeCat(elementCategory), kind)}; + if (auto known{evaluate::ToInt64(value)}) { + return MakeVectorType(elementCategory, static_cast(*known)); + } else { + return currScope_->MakeVectorType(elementCategory, std::move(value)); + } +} +const DeclTypeSpec &ScopeHandler::MakeVectorType( + VectorElementCategory category, int kind) { + return context().MakeVectorType(category, kind); +} + void ScopeHandler::NotePossibleBadForwardRef(const parser::Name &name) { if (inSpecificationPart_ && name.symbol) { auto kind{currScope().kind()}; @@ -4587,10 +4609,14 @@ } void DeclarationVisitor::Post(const parser::IntegerTypeSpec &x) { - SetDeclTypeSpec(MakeNumericType(TypeCategory::Integer, x.v)); + if (!isVectorType) { + SetDeclTypeSpec(MakeNumericType(TypeCategory::Integer, x.v)); + } } void DeclarationVisitor::Post(const parser::IntrinsicTypeSpec::Real &x) { - SetDeclTypeSpec(MakeNumericType(TypeCategory::Real, x.kind)); + if (!isVectorType) { + SetDeclTypeSpec(MakeNumericType(TypeCategory::Real, x.kind)); + } } void DeclarationVisitor::Post(const parser::IntrinsicTypeSpec::Complex &x) { SetDeclTypeSpec(MakeNumericType(TypeCategory::Complex, x.kind)); @@ -4651,6 +4677,29 @@ return false; } +bool DeclarationVisitor::Pre(const parser::VectorTypeSpec &) { + isVectorType = true; + return true; +} +void DeclarationVisitor::Post(const parser::VectorTypeSpec &x) { + isVectorType = false; + common::visit(common::visitors{ + [=](const parser::IntegerTypeSpec &y) { + SetDeclTypeSpec(MakeVectorType( + VectorElementCategory::Integer, std::move(y.v))); + }, + [=](const parser::IntrinsicTypeSpec::Real &y) { + SetDeclTypeSpec(MakeVectorType( + VectorElementCategory::Real, std::move(y.kind))); + }, + [=](const parser::UnsignedTypeSpec &y) { + SetDeclTypeSpec(MakeVectorType( + VectorElementCategory::Unsigned, std::move(y.v))); + }, + }, + x.v.u); +} + bool DeclarationVisitor::Pre(const parser::DeclarationTypeSpec::Type &) { CHECK(GetDeclTypeSpecCategory() == DeclTypeSpec::Category::TypeDerived); return true; @@ -6730,6 +6779,10 @@ } case common::TypeCategory::Character: CRASH_NO_CASE; + case common::TypeCategory::Vector: + return context().MakeVectorType( + type.GetVectorTypeSpec().vectorElementCategory(), + type.GetVectorTypeSpec().vectorElementKind()); } } Index: flang/lib/Semantics/scope.cpp =================================================================== --- flang/lib/Semantics/scope.cpp +++ flang/lib/Semantics/scope.cpp @@ -187,6 +187,12 @@ const DeclTypeSpec &Scope::MakeClassStarType() { return MakeLengthlessType(DeclTypeSpec{DeclTypeSpec::ClassStar}); } +const DeclTypeSpec &Scope::MakeVectorType( + VectorElementCategory elementTypeCategory, KindExpr &&kind) { + return MakeLengthlessType( + VectorTypeSpec{elementTypeCategory, std::move(kind)}); +} + // Types that can't have length parameters can be reused without having to // compare length expressions. They are stored in the global scope. const DeclTypeSpec &Scope::MakeLengthlessType(DeclTypeSpec &&type) { @@ -242,6 +248,10 @@ ? DeclTypeSpec::ClassDerived : DeclTypeSpec::TypeDerived, DerivedTypeSpec{dyType->GetDerivedTypeSpec()}); + case TypeCategory::Vector: + return &MakeVectorType( + dyType->GetVectorTypeSpec().vectorElementCategory(), + KindExpr{dyType->GetVectorTypeSpec().vectorElementKind()}); } } } Index: flang/lib/Semantics/semantics.cpp =================================================================== --- flang/lib/Semantics/semantics.cpp +++ flang/lib/Semantics/semantics.cpp @@ -315,6 +315,14 @@ return globalScope_.MakeLogicalType(KindExpr{kind}); } +const DeclTypeSpec &SemanticsContext::MakeVectorType( + VectorElementCategory elementCategory, int kind) { + if (kind == 0) { + kind = GetDefaultKind( + VectorTypeSpec::elementTypeCatToIntrinsicTypeCat(elementCategory)); + } + return globalScope_.MakeVectorType(elementCategory, KindExpr{kind}); +} bool SemanticsContext::AnyFatalError() const { return !messages_.empty() && (warningsAreErrors_ || messages_.AnyFatalError()); Index: flang/lib/Semantics/type.cpp =================================================================== --- flang/lib/Semantics/type.cpp +++ flang/lib/Semantics/type.cpp @@ -226,6 +226,16 @@ return true; } +VectorTypeSpec::VectorTypeSpec( + VectorElementCategory pVectorElementCategory, KindExpr &&pKind) + : vectorElementCategory_(pVectorElementCategory) { + auto kind{Fortran::evaluate::ToInt64(pKind).value_or(0)}; + if (!kind) { + llvm::report_fatal_error("Unspecified kind for vector element type"); + } + vectorElementKind_ = kind; +} + class InstantiateHelper { public: InstantiateHelper(Scope &scope) : scope_{scope} {} @@ -716,6 +726,11 @@ return "CHARACTER(" + length_.AsFortran() + ',' + KindAsFortran(kind()) + ')'; } +std::string VectorTypeSpec::AsFortran() const { + return "VECTOR(" + std::string{EnumToString(vectorElementCategory())} + "(" + + std::to_string(vectorElementKind()) + ")" + ')'; +} + llvm::raw_ostream &operator<<( llvm::raw_ostream &os, const CharacterTypeSpec &x) { return os << x.AsFortran(); @@ -740,6 +755,9 @@ DeclTypeSpec::DeclTypeSpec(Category category) : category_{category} { CHECK(category == TypeStar || category == ClassStar); } +DeclTypeSpec::DeclTypeSpec(VectorTypeSpec &&typeSpec) + : category_{Vector}, typeSpec_{std::move(typeSpec)} {} + bool DeclTypeSpec::IsNumeric(TypeCategory tc) const { return category_ == Numeric && numericTypeSpec().category() == tc; } @@ -788,6 +806,8 @@ return "TYPE(*)"; case ClassStar: return "CLASS(*)"; + case Vector: + return vectorTypeSpec().AsFortran(); } } Index: flang/runtime/descriptor-io.h =================================================================== --- flang/runtime/descriptor-io.h +++ flang/runtime/descriptor-io.h @@ -510,6 +510,9 @@ } case TypeCategory::Derived: return FormattedDerivedTypeIO(io, descriptor); + case TypeCategory::Vector: + handler.Crash("DescriptorIO: Unsupported VECTOR type in descriptor"); + return false; } } handler.Crash("DescriptorIO: bad type code (%d) in descriptor", Index: flang/runtime/type-code.cpp =================================================================== --- flang/runtime/type-code.cpp +++ flang/runtime/type-code.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "flang/Runtime/type-code.h" +#include namespace Fortran::runtime { @@ -107,6 +108,9 @@ case TypeCategory::Derived: raw_ = CFI_type_struct; break; + case TypeCategory::Vector: + assert(false && "Vector is not supported."); + break; } } Index: flang/runtime/type-info.cpp =================================================================== --- flang/runtime/type-info.cpp +++ flang/runtime/type-info.cpp @@ -8,6 +8,7 @@ #include "type-info.h" #include "terminator.h" +#include #include namespace Fortran::runtime::typeInfo { @@ -47,6 +48,9 @@ return type->sizeInBytes(); } break; + case TypeCategory::Vector: + assert(false && "Vector is not supported."); + break; } return 0; }