164ab3302SCarolineConcatto //===-- lib/Evaluate/fold.cpp ---------------------------------------------===// 264ab3302SCarolineConcatto // 364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information. 564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 664ab3302SCarolineConcatto // 764ab3302SCarolineConcatto //===----------------------------------------------------------------------===// 864ab3302SCarolineConcatto 964ab3302SCarolineConcatto #include "flang/Evaluate/fold.h" 1064ab3302SCarolineConcatto #include "fold-implementation.h" 11a50bb84eSpeter klausler #include "flang/Evaluate/characteristics.h" 1264ab3302SCarolineConcatto 1364ab3302SCarolineConcatto namespace Fortran::evaluate { 1464ab3302SCarolineConcatto 15a50bb84eSpeter klausler characteristics::TypeAndShape Fold( 16a50bb84eSpeter klausler FoldingContext &context, characteristics::TypeAndShape &&x) { 17a50bb84eSpeter klausler x.Rewrite(context); 18a50bb84eSpeter klausler return std::move(x); 19a50bb84eSpeter klausler } 20a50bb84eSpeter klausler 2164ab3302SCarolineConcatto std::optional<Constant<SubscriptInteger>> GetConstantSubscript( 2264ab3302SCarolineConcatto FoldingContext &context, Subscript &ss, const NamedEntity &base, int dim) { 2364ab3302SCarolineConcatto ss = FoldOperation(context, std::move(ss)); 24cd03e96fSPeter Klausler return common::visit( 2564ab3302SCarolineConcatto common::visitors{ 2664ab3302SCarolineConcatto [](IndirectSubscriptIntegerExpr &expr) 2764ab3302SCarolineConcatto -> std::optional<Constant<SubscriptInteger>> { 2864ab3302SCarolineConcatto if (const auto *constant{ 2964ab3302SCarolineConcatto UnwrapConstantValue<SubscriptInteger>(expr.value())}) { 3064ab3302SCarolineConcatto return *constant; 3164ab3302SCarolineConcatto } else { 3264ab3302SCarolineConcatto return std::nullopt; 3364ab3302SCarolineConcatto } 3464ab3302SCarolineConcatto }, 3564ab3302SCarolineConcatto [&](Triplet &triplet) -> std::optional<Constant<SubscriptInteger>> { 3664ab3302SCarolineConcatto auto lower{triplet.lower()}, upper{triplet.upper()}; 3764ab3302SCarolineConcatto std::optional<ConstantSubscript> stride{ToInt64(triplet.stride())}; 3864ab3302SCarolineConcatto if (!lower) { 393b61587cSPeter Klausler lower = GetLBOUND(context, base, dim); 4064ab3302SCarolineConcatto } 4164ab3302SCarolineConcatto if (!upper) { 423b61587cSPeter Klausler if (auto lb{GetLBOUND(context, base, dim)}) { 433b61587cSPeter Klausler upper = ComputeUpperBound( 443b61587cSPeter Klausler context, std::move(*lb), GetExtent(context, base, dim)); 453b61587cSPeter Klausler } 4664ab3302SCarolineConcatto } 4764ab3302SCarolineConcatto auto lbi{ToInt64(lower)}, ubi{ToInt64(upper)}; 4864ab3302SCarolineConcatto if (lbi && ubi && stride && *stride != 0) { 4964ab3302SCarolineConcatto std::vector<SubscriptInteger::Scalar> values; 5064ab3302SCarolineConcatto while ((*stride > 0 && *lbi <= *ubi) || 5164ab3302SCarolineConcatto (*stride < 0 && *lbi >= *ubi)) { 5264ab3302SCarolineConcatto values.emplace_back(*lbi); 5364ab3302SCarolineConcatto *lbi += *stride; 5464ab3302SCarolineConcatto } 5564ab3302SCarolineConcatto return Constant<SubscriptInteger>{std::move(values), 5664ab3302SCarolineConcatto ConstantSubscripts{ 5764ab3302SCarolineConcatto static_cast<ConstantSubscript>(values.size())}}; 5864ab3302SCarolineConcatto } else { 5964ab3302SCarolineConcatto return std::nullopt; 6064ab3302SCarolineConcatto } 6164ab3302SCarolineConcatto }, 6264ab3302SCarolineConcatto }, 6364ab3302SCarolineConcatto ss.u); 6464ab3302SCarolineConcatto } 6564ab3302SCarolineConcatto 6664ab3302SCarolineConcatto Expr<SomeDerived> FoldOperation( 6764ab3302SCarolineConcatto FoldingContext &context, StructureConstructor &&structure) { 684171f80dSpeter klausler StructureConstructor ctor{structure.derivedTypeSpec()}; 69c4360b45SPeter Klausler bool isConstant{true}; 70*a054c882SPeter Klausler auto restorer{context.WithPDTInstance(structure.derivedTypeSpec())}; 7164ab3302SCarolineConcatto for (auto &&[symbol, value] : std::move(structure)) { 724171f80dSpeter klausler auto expr{Fold(context, std::move(value.value()))}; 73c4360b45SPeter Klausler if (IsPointer(symbol)) { 74c4360b45SPeter Klausler if (IsProcedure(symbol)) { 75c4360b45SPeter Klausler isConstant &= IsInitialProcedureTarget(expr); 76c4360b45SPeter Klausler } else { 77c4360b45SPeter Klausler isConstant &= IsInitialDataTarget(expr); 78c4360b45SPeter Klausler } 79c4360b45SPeter Klausler } else { 80c4360b45SPeter Klausler isConstant &= IsActuallyConstant(expr); 81641ede93Speter klausler if (auto valueShape{GetConstantExtents(context, expr)}) { 824171f80dSpeter klausler if (auto componentShape{GetConstantExtents(context, symbol)}) { 834171f80dSpeter klausler if (GetRank(*componentShape) > 0 && GetRank(*valueShape) == 0) { 84641ede93Speter klausler expr = ScalarConstantExpander{std::move(*componentShape)}.Expand( 854171f80dSpeter klausler std::move(expr)); 86c4360b45SPeter Klausler isConstant &= expr.Rank() > 0; 874171f80dSpeter klausler } else { 88c4360b45SPeter Klausler isConstant &= *valueShape == *componentShape; 894171f80dSpeter klausler } 904171f80dSpeter klausler } 91641ede93Speter klausler } 924171f80dSpeter klausler } 93c4360b45SPeter Klausler ctor.Add(symbol, std::move(expr)); 944171f80dSpeter klausler } 95c4360b45SPeter Klausler if (isConstant) { 964171f80dSpeter klausler return Expr<SomeDerived>{Constant<SomeDerived>{std::move(ctor)}}; 974171f80dSpeter klausler } else { 984171f80dSpeter klausler return Expr<SomeDerived>{std::move(ctor)}; 994171f80dSpeter klausler } 10064ab3302SCarolineConcatto } 10164ab3302SCarolineConcatto 10264ab3302SCarolineConcatto Component FoldOperation(FoldingContext &context, Component &&component) { 10364ab3302SCarolineConcatto return {FoldOperation(context, std::move(component.base())), 10464ab3302SCarolineConcatto component.GetLastSymbol()}; 10564ab3302SCarolineConcatto } 10664ab3302SCarolineConcatto 10764ab3302SCarolineConcatto NamedEntity FoldOperation(FoldingContext &context, NamedEntity &&x) { 10864ab3302SCarolineConcatto if (Component * c{x.UnwrapComponent()}) { 10964ab3302SCarolineConcatto return NamedEntity{FoldOperation(context, std::move(*c))}; 11064ab3302SCarolineConcatto } else { 11164ab3302SCarolineConcatto return std::move(x); 11264ab3302SCarolineConcatto } 11364ab3302SCarolineConcatto } 11464ab3302SCarolineConcatto 11564ab3302SCarolineConcatto Triplet FoldOperation(FoldingContext &context, Triplet &&triplet) { 11664ab3302SCarolineConcatto MaybeExtentExpr lower{triplet.lower()}; 11764ab3302SCarolineConcatto MaybeExtentExpr upper{triplet.upper()}; 11864ab3302SCarolineConcatto return {Fold(context, std::move(lower)), Fold(context, std::move(upper)), 11964ab3302SCarolineConcatto Fold(context, triplet.stride())}; 12064ab3302SCarolineConcatto } 12164ab3302SCarolineConcatto 12264ab3302SCarolineConcatto Subscript FoldOperation(FoldingContext &context, Subscript &&subscript) { 123cd03e96fSPeter Klausler return common::visit( 124cd03e96fSPeter Klausler common::visitors{ 12564ab3302SCarolineConcatto [&](IndirectSubscriptIntegerExpr &&expr) { 12664ab3302SCarolineConcatto expr.value() = Fold(context, std::move(expr.value())); 12764ab3302SCarolineConcatto return Subscript(std::move(expr)); 12864ab3302SCarolineConcatto }, 12964ab3302SCarolineConcatto [&](Triplet &&triplet) { 130cd03e96fSPeter Klausler return Subscript(FoldOperation(context, std::move(triplet))); 13164ab3302SCarolineConcatto }, 13264ab3302SCarolineConcatto }, 13364ab3302SCarolineConcatto std::move(subscript.u)); 13464ab3302SCarolineConcatto } 13564ab3302SCarolineConcatto 13664ab3302SCarolineConcatto ArrayRef FoldOperation(FoldingContext &context, ArrayRef &&arrayRef) { 13764ab3302SCarolineConcatto NamedEntity base{FoldOperation(context, std::move(arrayRef.base()))}; 13864ab3302SCarolineConcatto for (Subscript &subscript : arrayRef.subscript()) { 13964ab3302SCarolineConcatto subscript = FoldOperation(context, std::move(subscript)); 14064ab3302SCarolineConcatto } 14164ab3302SCarolineConcatto return ArrayRef{std::move(base), std::move(arrayRef.subscript())}; 14264ab3302SCarolineConcatto } 14364ab3302SCarolineConcatto 14464ab3302SCarolineConcatto CoarrayRef FoldOperation(FoldingContext &context, CoarrayRef &&coarrayRef) { 14564ab3302SCarolineConcatto std::vector<Subscript> subscript; 14664ab3302SCarolineConcatto for (Subscript x : coarrayRef.subscript()) { 14764ab3302SCarolineConcatto subscript.emplace_back(FoldOperation(context, std::move(x))); 14864ab3302SCarolineConcatto } 14964ab3302SCarolineConcatto std::vector<Expr<SubscriptInteger>> cosubscript; 15064ab3302SCarolineConcatto for (Expr<SubscriptInteger> x : coarrayRef.cosubscript()) { 15164ab3302SCarolineConcatto cosubscript.emplace_back(Fold(context, std::move(x))); 15264ab3302SCarolineConcatto } 15364ab3302SCarolineConcatto CoarrayRef folded{std::move(coarrayRef.base()), std::move(subscript), 15464ab3302SCarolineConcatto std::move(cosubscript)}; 15564ab3302SCarolineConcatto if (std::optional<Expr<SomeInteger>> stat{coarrayRef.stat()}) { 15664ab3302SCarolineConcatto folded.set_stat(Fold(context, std::move(*stat))); 15764ab3302SCarolineConcatto } 15864ab3302SCarolineConcatto if (std::optional<Expr<SomeInteger>> team{coarrayRef.team()}) { 15964ab3302SCarolineConcatto folded.set_team( 16064ab3302SCarolineConcatto Fold(context, std::move(*team)), coarrayRef.teamIsTeamNumber()); 16164ab3302SCarolineConcatto } 16264ab3302SCarolineConcatto return folded; 16364ab3302SCarolineConcatto } 16464ab3302SCarolineConcatto 16564ab3302SCarolineConcatto DataRef FoldOperation(FoldingContext &context, DataRef &&dataRef) { 166cd03e96fSPeter Klausler return common::visit(common::visitors{ 16764ab3302SCarolineConcatto [&](SymbolRef symbol) { return DataRef{*symbol}; }, 16864ab3302SCarolineConcatto [&](auto &&x) { 169cd03e96fSPeter Klausler return DataRef{ 170cd03e96fSPeter Klausler FoldOperation(context, std::move(x))}; 17164ab3302SCarolineConcatto }, 17264ab3302SCarolineConcatto }, 17364ab3302SCarolineConcatto std::move(dataRef.u)); 17464ab3302SCarolineConcatto } 17564ab3302SCarolineConcatto 17664ab3302SCarolineConcatto Substring FoldOperation(FoldingContext &context, Substring &&substring) { 17764ab3302SCarolineConcatto auto lower{Fold(context, substring.lower())}; 17864ab3302SCarolineConcatto auto upper{Fold(context, substring.upper())}; 17964ab3302SCarolineConcatto if (const DataRef * dataRef{substring.GetParentIf<DataRef>()}) { 18064ab3302SCarolineConcatto return Substring{FoldOperation(context, DataRef{*dataRef}), 18164ab3302SCarolineConcatto std::move(lower), std::move(upper)}; 18264ab3302SCarolineConcatto } else { 18364ab3302SCarolineConcatto auto p{*substring.GetParentIf<StaticDataObject::Pointer>()}; 18464ab3302SCarolineConcatto return Substring{std::move(p), std::move(lower), std::move(upper)}; 18564ab3302SCarolineConcatto } 18664ab3302SCarolineConcatto } 18764ab3302SCarolineConcatto 18864ab3302SCarolineConcatto ComplexPart FoldOperation(FoldingContext &context, ComplexPart &&complexPart) { 18964ab3302SCarolineConcatto DataRef complex{complexPart.complex()}; 19064ab3302SCarolineConcatto return ComplexPart{ 19164ab3302SCarolineConcatto FoldOperation(context, std::move(complex)), complexPart.part()}; 19264ab3302SCarolineConcatto } 19364ab3302SCarolineConcatto 19464ab3302SCarolineConcatto std::optional<std::int64_t> GetInt64Arg( 19564ab3302SCarolineConcatto const std::optional<ActualArgument> &arg) { 19664ab3302SCarolineConcatto if (const auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(arg)}) { 19764ab3302SCarolineConcatto return ToInt64(*intExpr); 19864ab3302SCarolineConcatto } else { 19964ab3302SCarolineConcatto return std::nullopt; 20064ab3302SCarolineConcatto } 20164ab3302SCarolineConcatto } 20264ab3302SCarolineConcatto 20364ab3302SCarolineConcatto std::optional<std::int64_t> GetInt64ArgOr( 20464ab3302SCarolineConcatto const std::optional<ActualArgument> &arg, std::int64_t defaultValue) { 20564ab3302SCarolineConcatto if (!arg) { 20664ab3302SCarolineConcatto return defaultValue; 20764ab3302SCarolineConcatto } else if (const auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(arg)}) { 20864ab3302SCarolineConcatto return ToInt64(*intExpr); 20964ab3302SCarolineConcatto } else { 21064ab3302SCarolineConcatto return std::nullopt; 21164ab3302SCarolineConcatto } 21264ab3302SCarolineConcatto } 21364ab3302SCarolineConcatto 21464ab3302SCarolineConcatto Expr<ImpliedDoIndex::Result> FoldOperation( 21564ab3302SCarolineConcatto FoldingContext &context, ImpliedDoIndex &&iDo) { 21664ab3302SCarolineConcatto if (std::optional<ConstantSubscript> value{context.GetImpliedDo(iDo.name)}) { 21764ab3302SCarolineConcatto return Expr<ImpliedDoIndex::Result>{*value}; 21864ab3302SCarolineConcatto } else { 21964ab3302SCarolineConcatto return Expr<ImpliedDoIndex::Result>{std::move(iDo)}; 22064ab3302SCarolineConcatto } 22164ab3302SCarolineConcatto } 22264ab3302SCarolineConcatto 22364ab3302SCarolineConcatto template class ExpressionBase<SomeDerived>; 22464ab3302SCarolineConcatto template class ExpressionBase<SomeType>; 22564ab3302SCarolineConcatto 2261f879005STim Keith } // namespace Fortran::evaluate 227