1 //===-- include/flang/Evaluate/fold.h ---------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef FORTRAN_EVALUATE_FOLD_H_
10 #define FORTRAN_EVALUATE_FOLD_H_
11
12 // Implements expression tree rewriting, particularly constant expression
13 // and designator reference evaluation.
14
15 #include "common.h"
16 #include "constant.h"
17 #include "expression.h"
18 #include "tools.h"
19 #include "type.h"
20 #include <variant>
21
22 namespace Fortran::evaluate::characteristics {
23 class TypeAndShape;
24 }
25
26 namespace Fortran::evaluate {
27
28 using namespace Fortran::parser::literals;
29
30 // Fold() rewrites an expression and returns it. When the rewritten expression
31 // is a constant, UnwrapConstantValue() and GetScalarConstantValue() below will
32 // be able to extract it.
33 // Note the rvalue reference argument: the rewrites are performed in place
34 // for efficiency.
Fold(FoldingContext & context,Expr<T> && expr)35 template <typename T> Expr<T> Fold(FoldingContext &context, Expr<T> &&expr) {
36 return Expr<T>::Rewrite(context, std::move(expr));
37 }
38
39 characteristics::TypeAndShape Fold(
40 FoldingContext &, characteristics::TypeAndShape &&);
41
42 template <typename A>
Fold(FoldingContext & context,std::optional<A> && x)43 std::optional<A> Fold(FoldingContext &context, std::optional<A> &&x) {
44 if (x) {
45 return Fold(context, std::move(*x));
46 } else {
47 return std::nullopt;
48 }
49 }
50
51 // UnwrapConstantValue() isolates the known constant value of
52 // an expression, if it has one. It returns a pointer, which is
53 // const-qualified when the expression is so. The value can be
54 // parenthesized.
55 template <typename T, typename EXPR>
56 auto UnwrapConstantValue(EXPR &expr) -> common::Constify<Constant<T>, EXPR> * {
57 if (auto *c{UnwrapExpr<Constant<T>>(expr)}) {
58 return c;
59 } else {
60 if constexpr (!std::is_same_v<T, SomeDerived>) {
61 if (auto *parens{UnwrapExpr<Parentheses<T>>(expr)}) {
62 return UnwrapConstantValue<T>(parens->left());
63 }
64 }
65 return nullptr;
66 }
67 }
68
69 // GetScalarConstantValue() extracts the known scalar constant value of
70 // an expression, if it has one. The value can be parenthesized.
71 template <typename T, typename EXPR>
72 constexpr auto GetScalarConstantValue(const EXPR &expr)
73 -> std::optional<Scalar<T>> {
74 if (const Constant<T> *constant{UnwrapConstantValue<T>(expr)}) {
75 return constant->GetScalarValue();
76 } else {
77 return std::nullopt;
78 }
79 }
80
81 // When an expression is a constant integer, ToInt64() extracts its value.
82 // Ensure that the expression has been folded beforehand when folding might
83 // be required.
84 template <int KIND>
ToInt64(const Expr<Type<TypeCategory::Integer,KIND>> & expr)85 constexpr std::optional<std::int64_t> ToInt64(
86 const Expr<Type<TypeCategory::Integer, KIND>> &expr) {
87 if (auto scalar{
88 GetScalarConstantValue<Type<TypeCategory::Integer, KIND>>(expr)}) {
89 return scalar->ToInt64();
90 } else {
91 return std::nullopt;
92 }
93 }
94
95 std::optional<std::int64_t> ToInt64(const Expr<SomeInteger> &);
96 std::optional<std::int64_t> ToInt64(const Expr<SomeType> &);
97
98 template <typename A>
ToInt64(const std::optional<A> & x)99 std::optional<std::int64_t> ToInt64(const std::optional<A> &x) {
100 if (x) {
101 return ToInt64(*x);
102 } else {
103 return std::nullopt;
104 }
105 }
106
ToInt64(const A * p)107 template <typename A> std::optional<std::int64_t> ToInt64(const A *p) {
108 if (p) {
109 return ToInt64(*p);
110 } else {
111 return std::nullopt;
112 }
113 }
114 } // namespace Fortran::evaluate
115 #endif // FORTRAN_EVALUATE_FOLD_H_
116