// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // GetShape() analyzes an expression and determines its shape, if possible, // representing the result as a vector of scalar integer expressions. #ifndef FORTRAN_EVALUATE_SHAPE_H_ #define FORTRAN_EVALUATE_SHAPE_H_ #include "expression.h" #include "tools.h" #include "type.h" #include "variable.h" #include "../common/indirection.h" #include #include namespace Fortran::parser { class ContextualMessages; } namespace Fortran::evaluate { class FoldingContext; using ExtentType = SubscriptInteger; using ExtentExpr = Expr; using MaybeExtentExpr = std::optional; using Shape = std::vector; bool IsImpliedShape(const Symbol &); bool IsExplicitShape(const Symbol &); // Conversions between various representations of shapes. Shape AsShape(const Constant &); std::optional AsShape(FoldingContext &, ExtentExpr &&); std::optional AsExtentArrayExpr(const Shape &); std::optional> AsConstantShape(const Shape &); Constant AsConstantShape(const ConstantSubscripts &); ConstantSubscripts AsConstantExtents(const Constant &); std::optional AsConstantExtents(const Shape &); inline int GetRank(const Shape &s) { return static_cast(s.size()); } // The dimension here is zero-based, unlike DIM= arguments to many intrinsics. MaybeExtentExpr GetLowerBound( FoldingContext &, const NamedEntity &, int dimension); Shape GetLowerBounds(FoldingContext &, const NamedEntity &); MaybeExtentExpr GetExtent(FoldingContext &, const NamedEntity &, int dimension); MaybeExtentExpr GetExtent( FoldingContext &, const Subscript &, const NamedEntity &, int dimension); MaybeExtentExpr GetUpperBound( FoldingContext &, MaybeExtentExpr &&lower, MaybeExtentExpr &&extent); // Compute an element count for a triplet or trip count for a DO. ExtentExpr CountTrips( ExtentExpr &&lower, ExtentExpr &&upper, ExtentExpr &&stride); ExtentExpr CountTrips( const ExtentExpr &lower, const ExtentExpr &upper, const ExtentExpr &stride); MaybeExtentExpr CountTrips( MaybeExtentExpr &&lower, MaybeExtentExpr &&upper, MaybeExtentExpr &&stride); // Computes SIZE() == PRODUCT(shape) MaybeExtentExpr GetSize(Shape &&); // Utility predicate: does an expression reference any implied DO index? bool ContainsAnyImpliedDoIndex(const ExtentExpr &); // Compilation-time shape conformance checking, when corresponding extents // are known. bool CheckConformance(parser::ContextualMessages &, const Shape &, const Shape &, const char * = "left operand", const char * = "right operand"); // The implementation of GetShape() is wrapped in a helper class // so that the member functions may mutually recurse without prototypes. class GetShapeHelper { public: explicit GetShapeHelper(FoldingContext &context) : context_{context} {} template std::optional GetShape(const Expr &expr) { return GetShape(expr.u); } std::optional GetShape(const Symbol &); std::optional GetShape(const Symbol *); std::optional GetShape(const Component &); std::optional GetShape(const NamedEntity &); std::optional GetShape(const BaseObject &); std::optional GetShape(const ArrayRef &); std::optional GetShape(const CoarrayRef &); std::optional GetShape(const DataRef &); std::optional GetShape(const Substring &); std::optional GetShape(const ComplexPart &); std::optional GetShape(const ActualArgument &); std::optional GetShape(const ProcedureDesignator &); std::optional GetShape(const ProcedureRef &); std::optional GetShape(const ImpliedDoIndex &); std::optional GetShape(const Relational &); std::optional GetShape(const StructureConstructor &); std::optional GetShape(const DescriptorInquiry &); std::optional GetShape(const BOZLiteralConstant &); std::optional GetShape(const NullPointer &); template std::optional GetShape(const Constant &c) { Constant shape{c.SHAPE()}; return AsShape(shape); } template std::optional GetShape(const Designator &designator) { return GetShape(designator.u); } template std::optional GetShape(const Variable &variable) { return GetShape(variable.u); } template std::optional GetShape(const Operation &operation) { if constexpr (sizeof...(O) > 1) { if (operation.right().Rank() > 0) { return GetShape(operation.right()); } } return GetShape(operation.left()); } template std::optional GetShape(const TypeParamInquiry &) { return Shape{}; // always scalar, even when applied to an array } template std::optional GetShape(const ArrayConstructor &aconst) { return Shape{GetArrayConstructorExtent(aconst)}; } template std::optional GetShape(const std::variant &u) { return std::visit([&](const auto &x) { return GetShape(x); }, u); } template std::optional GetShape(const common::Indirection &p) { return GetShape(p.value()); } template std::optional GetShape(const std::optional &x) { if (x.has_value()) { return GetShape(*x); } else { return std::nullopt; } } private: template MaybeExtentExpr GetArrayConstructorValueExtent( const ArrayConstructorValue &value) { return std::visit( common::visitors{ [&](const Expr &x) -> MaybeExtentExpr { if (std::optional xShape{GetShape(x)}) { // Array values in array constructors get linearized. return GetSize(std::move(*xShape)); } else { return std::nullopt; } }, [&](const ImpliedDo &ido) -> MaybeExtentExpr { // Don't be heroic and try to figure out triangular implied DO // nests. if (!ContainsAnyImpliedDoIndex(ido.lower()) && !ContainsAnyImpliedDoIndex(ido.upper()) && !ContainsAnyImpliedDoIndex(ido.stride())) { if (auto nValues{GetArrayConstructorExtent(ido.values())}) { return std::move(*nValues) * CountTrips(ido.lower(), ido.upper(), ido.stride()); } } return std::nullopt; }, }, value.u); } template MaybeExtentExpr GetArrayConstructorExtent( const ArrayConstructorValues &values) { ExtentExpr result{0}; for (const auto &value : values) { if (MaybeExtentExpr n{GetArrayConstructorValueExtent(value)}) { result = std::move(result) + std::move(*n); } else { return std::nullopt; } } return result; } FoldingContext &context_; }; template std::optional GetShape(FoldingContext &context, const A &x) { return GetShapeHelper{context}.GetShape(x); } } #endif // FORTRAN_EVALUATE_SHAPE_H_