• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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