| //===-- lib/Evaluate/fold.cpp ---------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "flang/Evaluate/fold.h" |
| #include "fold-implementation.h" |
| #include "flang/Evaluate/characteristics.h" |
| |
| namespace Fortran::evaluate { |
| |
| characteristics::TypeAndShape Fold( |
| FoldingContext &context, characteristics::TypeAndShape &&x) { |
| x.Rewrite(context); |
| return std::move(x); |
| } |
| |
| std::optional<Constant<SubscriptInteger>> GetConstantSubscript( |
| FoldingContext &context, Subscript &ss, const NamedEntity &base, int dim) { |
| ss = FoldOperation(context, std::move(ss)); |
| return std::visit( |
| common::visitors{ |
| [](IndirectSubscriptIntegerExpr &expr) |
| -> std::optional<Constant<SubscriptInteger>> { |
| if (const auto *constant{ |
| UnwrapConstantValue<SubscriptInteger>(expr.value())}) { |
| return *constant; |
| } else { |
| return std::nullopt; |
| } |
| }, |
| [&](Triplet &triplet) -> std::optional<Constant<SubscriptInteger>> { |
| auto lower{triplet.lower()}, upper{triplet.upper()}; |
| std::optional<ConstantSubscript> stride{ToInt64(triplet.stride())}; |
| if (!lower) { |
| lower = GetLowerBound(context, base, dim); |
| } |
| if (!upper) { |
| upper = |
| ComputeUpperBound(context, GetLowerBound(context, base, dim), |
| GetExtent(context, base, dim)); |
| } |
| auto lbi{ToInt64(lower)}, ubi{ToInt64(upper)}; |
| if (lbi && ubi && stride && *stride != 0) { |
| std::vector<SubscriptInteger::Scalar> values; |
| while ((*stride > 0 && *lbi <= *ubi) || |
| (*stride < 0 && *lbi >= *ubi)) { |
| values.emplace_back(*lbi); |
| *lbi += *stride; |
| } |
| return Constant<SubscriptInteger>{std::move(values), |
| ConstantSubscripts{ |
| static_cast<ConstantSubscript>(values.size())}}; |
| } else { |
| return std::nullopt; |
| } |
| }, |
| }, |
| ss.u); |
| } |
| |
| Expr<SomeDerived> FoldOperation( |
| FoldingContext &context, StructureConstructor &&structure) { |
| StructureConstructor ctor{structure.derivedTypeSpec()}; |
| bool constantExtents{true}; |
| for (auto &&[symbol, value] : std::move(structure)) { |
| auto expr{Fold(context, std::move(value.value()))}; |
| if (!IsPointer(symbol)) { |
| bool ok{false}; |
| if (auto valueShape{GetConstantExtents(context, expr)}) { |
| if (auto componentShape{GetConstantExtents(context, symbol)}) { |
| if (GetRank(*componentShape) > 0 && GetRank(*valueShape) == 0) { |
| expr = ScalarConstantExpander{std::move(*componentShape)}.Expand( |
| std::move(expr)); |
| ok = expr.Rank() > 0; |
| } else { |
| ok = *valueShape == *componentShape; |
| } |
| } |
| } |
| if (!ok) { |
| constantExtents = false; |
| } |
| } |
| ctor.Add(symbol, Fold(context, std::move(expr))); |
| } |
| if (constantExtents && IsConstantExpr(ctor)) { |
| return Expr<SomeDerived>{Constant<SomeDerived>{std::move(ctor)}}; |
| } else { |
| return Expr<SomeDerived>{std::move(ctor)}; |
| } |
| } |
| |
| Component FoldOperation(FoldingContext &context, Component &&component) { |
| return {FoldOperation(context, std::move(component.base())), |
| component.GetLastSymbol()}; |
| } |
| |
| NamedEntity FoldOperation(FoldingContext &context, NamedEntity &&x) { |
| if (Component * c{x.UnwrapComponent()}) { |
| return NamedEntity{FoldOperation(context, std::move(*c))}; |
| } else { |
| return std::move(x); |
| } |
| } |
| |
| Triplet FoldOperation(FoldingContext &context, Triplet &&triplet) { |
| MaybeExtentExpr lower{triplet.lower()}; |
| MaybeExtentExpr upper{triplet.upper()}; |
| return {Fold(context, std::move(lower)), Fold(context, std::move(upper)), |
| Fold(context, triplet.stride())}; |
| } |
| |
| Subscript FoldOperation(FoldingContext &context, Subscript &&subscript) { |
| return std::visit(common::visitors{ |
| [&](IndirectSubscriptIntegerExpr &&expr) { |
| expr.value() = Fold(context, std::move(expr.value())); |
| return Subscript(std::move(expr)); |
| }, |
| [&](Triplet &&triplet) { |
| return Subscript( |
| FoldOperation(context, std::move(triplet))); |
| }, |
| }, |
| std::move(subscript.u)); |
| } |
| |
| ArrayRef FoldOperation(FoldingContext &context, ArrayRef &&arrayRef) { |
| NamedEntity base{FoldOperation(context, std::move(arrayRef.base()))}; |
| for (Subscript &subscript : arrayRef.subscript()) { |
| subscript = FoldOperation(context, std::move(subscript)); |
| } |
| return ArrayRef{std::move(base), std::move(arrayRef.subscript())}; |
| } |
| |
| CoarrayRef FoldOperation(FoldingContext &context, CoarrayRef &&coarrayRef) { |
| std::vector<Subscript> subscript; |
| for (Subscript x : coarrayRef.subscript()) { |
| subscript.emplace_back(FoldOperation(context, std::move(x))); |
| } |
| std::vector<Expr<SubscriptInteger>> cosubscript; |
| for (Expr<SubscriptInteger> x : coarrayRef.cosubscript()) { |
| cosubscript.emplace_back(Fold(context, std::move(x))); |
| } |
| CoarrayRef folded{std::move(coarrayRef.base()), std::move(subscript), |
| std::move(cosubscript)}; |
| if (std::optional<Expr<SomeInteger>> stat{coarrayRef.stat()}) { |
| folded.set_stat(Fold(context, std::move(*stat))); |
| } |
| if (std::optional<Expr<SomeInteger>> team{coarrayRef.team()}) { |
| folded.set_team( |
| Fold(context, std::move(*team)), coarrayRef.teamIsTeamNumber()); |
| } |
| return folded; |
| } |
| |
| DataRef FoldOperation(FoldingContext &context, DataRef &&dataRef) { |
| return std::visit(common::visitors{ |
| [&](SymbolRef symbol) { return DataRef{*symbol}; }, |
| [&](auto &&x) { |
| return DataRef{FoldOperation(context, std::move(x))}; |
| }, |
| }, |
| std::move(dataRef.u)); |
| } |
| |
| Substring FoldOperation(FoldingContext &context, Substring &&substring) { |
| auto lower{Fold(context, substring.lower())}; |
| auto upper{Fold(context, substring.upper())}; |
| if (const DataRef * dataRef{substring.GetParentIf<DataRef>()}) { |
| return Substring{FoldOperation(context, DataRef{*dataRef}), |
| std::move(lower), std::move(upper)}; |
| } else { |
| auto p{*substring.GetParentIf<StaticDataObject::Pointer>()}; |
| return Substring{std::move(p), std::move(lower), std::move(upper)}; |
| } |
| } |
| |
| ComplexPart FoldOperation(FoldingContext &context, ComplexPart &&complexPart) { |
| DataRef complex{complexPart.complex()}; |
| return ComplexPart{ |
| FoldOperation(context, std::move(complex)), complexPart.part()}; |
| } |
| |
| std::optional<std::int64_t> GetInt64Arg( |
| const std::optional<ActualArgument> &arg) { |
| if (const auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(arg)}) { |
| return ToInt64(*intExpr); |
| } else { |
| return std::nullopt; |
| } |
| } |
| |
| std::optional<std::int64_t> GetInt64ArgOr( |
| const std::optional<ActualArgument> &arg, std::int64_t defaultValue) { |
| if (!arg) { |
| return defaultValue; |
| } else if (const auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(arg)}) { |
| return ToInt64(*intExpr); |
| } else { |
| return std::nullopt; |
| } |
| } |
| |
| Expr<ImpliedDoIndex::Result> FoldOperation( |
| FoldingContext &context, ImpliedDoIndex &&iDo) { |
| if (std::optional<ConstantSubscript> value{context.GetImpliedDo(iDo.name)}) { |
| return Expr<ImpliedDoIndex::Result>{*value}; |
| } else { |
| return Expr<ImpliedDoIndex::Result>{std::move(iDo)}; |
| } |
| } |
| |
| template class ExpressionBase<SomeDerived>; |
| template class ExpressionBase<SomeType>; |
| |
| } // namespace Fortran::evaluate |