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 {
23
24 using namespace Fortran::parser::literals;
25
26 // Fold() rewrites an expression and returns it. When the rewritten expression
27 // is a constant, UnwrapConstantValue() and GetScalarConstantValue() below will
28 // be able to extract it.
29 // Note the rvalue reference argument: the rewrites are performed in place
30 // for efficiency.
Fold(FoldingContext & context,Expr<T> && expr)31 template <typename T> Expr<T> Fold(FoldingContext &context, Expr<T> &&expr) {
32 return Expr<T>::Rewrite(context, std::move(expr));
33 }
34
35 template <typename T>
Fold(FoldingContext & context,std::optional<Expr<T>> && expr)36 std::optional<Expr<T>> Fold(
37 FoldingContext &context, std::optional<Expr<T>> &&expr) {
38 if (expr) {
39 return Fold(context, std::move(*expr));
40 } else {
41 return std::nullopt;
42 }
43 }
44
45 // UnwrapConstantValue() isolates the known constant value of
46 // an expression, if it has one. It returns a pointer, which is
47 // const-qualified when the expression is so. The value can be
48 // parenthesized.
49 template <typename T, typename EXPR>
50 auto UnwrapConstantValue(EXPR &expr) -> common::Constify<Constant<T>, EXPR> * {
51 if (auto *c{UnwrapExpr<Constant<T>>(expr)}) {
52 return c;
53 } else {
54 if constexpr (!std::is_same_v<T, SomeDerived>) {
55 if (auto *parens{UnwrapExpr<Parentheses<T>>(expr)}) {
56 return UnwrapConstantValue<T>(parens->left());
57 }
58 }
59 return nullptr;
60 }
61 }
62
63 // GetScalarConstantValue() extracts the known scalar constant value of
64 // an expression, if it has one. The value can be parenthesized.
65 template <typename T, typename EXPR>
66 auto GetScalarConstantValue(const EXPR &expr) -> std::optional<Scalar<T>> {
67 if (const Constant<T> *constant{UnwrapConstantValue<T>(expr)}) {
68 return constant->GetScalarValue();
69 } else {
70 return std::nullopt;
71 }
72 }
73
74 // When an expression is a constant integer, ToInt64() extracts its value.
75 // Ensure that the expression has been folded beforehand when folding might
76 // be required.
77 template <int KIND>
ToInt64(const Expr<Type<TypeCategory::Integer,KIND>> & expr)78 std::optional<std::int64_t> ToInt64(
79 const Expr<Type<TypeCategory::Integer, KIND>> &expr) {
80 if (auto scalar{
81 GetScalarConstantValue<Type<TypeCategory::Integer, KIND>>(expr)}) {
82 return scalar->ToInt64();
83 } else {
84 return std::nullopt;
85 }
86 }
87
88 std::optional<std::int64_t> ToInt64(const Expr<SomeInteger> &);
89 std::optional<std::int64_t> ToInt64(const Expr<SomeType> &);
90
91 template <typename A>
ToInt64(const std::optional<A> & x)92 std::optional<std::int64_t> ToInt64(const std::optional<A> &x) {
93 if (x) {
94 return ToInt64(*x);
95 } else {
96 return std::nullopt;
97 }
98 }
99 } // namespace Fortran::evaluate
100 #endif // FORTRAN_EVALUATE_FOLD_H_
101