xref: /llvm-project/flang/lib/Evaluate/fold.cpp (revision a054c882053e63e6fce7b412a93dc7fc228f11fd)
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