1 //===-- include/flang/Evaluate/constant.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_CONSTANT_H_
10 #define FORTRAN_EVALUATE_CONSTANT_H_
11 
12 #include "formatting.h"
13 #include "type.h"
14 #include "flang/Common/default-kinds.h"
15 #include "flang/Common/reference.h"
16 #include <map>
17 #include <vector>
18 
19 namespace llvm {
20 class raw_ostream;
21 }
22 
23 namespace Fortran::semantics {
24 class Symbol;
25 }
26 
27 namespace Fortran::evaluate {
28 
29 using semantics::Symbol;
30 using SymbolRef = common::Reference<const Symbol>;
31 
32 // Wraps a constant value in a class templated by its resolved type.
33 // This Constant<> template class should be instantiated only for
34 // concrete intrinsic types and SomeDerived.  There is no instance
35 // Constant<SomeType> since there is no way to constrain each
36 // element of its array to hold the same type.  To represent a generic
37 // constant, use a generic expression like Expr<SomeInteger> or
38 // Expr<SomeType>) to wrap the appropriate instantiation of Constant<>.
39 
40 template <typename> class Constant;
41 
42 // When describing shapes of constants or specifying 1-based subscript
43 // values as indices into constants, use a vector of integers.
44 using ConstantSubscripts = std::vector<ConstantSubscript>;
GetRank(const ConstantSubscripts & s)45 inline int GetRank(const ConstantSubscripts &s) {
46   return static_cast<int>(s.size());
47 }
48 
49 std::size_t TotalElementCount(const ConstantSubscripts &);
50 
51 // Validate dimension re-ordering like ORDER in RESHAPE.
52 // On success, return a vector that can be used as dimOrder in
53 // ConstantBounds::IncrementSubscripts().
54 std::optional<std::vector<int>> ValidateDimensionOrder(
55     int rank, const std::vector<int> &order);
56 
57 bool HasNegativeExtent(const ConstantSubscripts &);
58 
59 class ConstantBounds {
60 public:
61   ConstantBounds() = default;
62   explicit ConstantBounds(const ConstantSubscripts &shape);
63   explicit ConstantBounds(ConstantSubscripts &&shape);
64   ~ConstantBounds();
shape()65   const ConstantSubscripts &shape() const { return shape_; }
lbounds()66   const ConstantSubscripts &lbounds() const { return lbounds_; }
67   ConstantSubscripts ComputeUbounds(std::optional<int> dim) const;
68   void set_lbounds(ConstantSubscripts &&);
69   void SetLowerBoundsToOne();
Rank()70   int Rank() const { return GetRank(shape_); }
71   Constant<SubscriptInteger> SHAPE() const;
72 
73   // If no optional dimension order argument is passed, increments a vector of
74   // subscripts in Fortran array order (first dimension varying most quickly).
75   // Otherwise, increments the vector of subscripts according to the given
76   // dimension order (dimension dimOrder[0] varying most quickly; dimension
77   // indexing is zero based here). Returns false when last element was visited.
78   bool IncrementSubscripts(
79       ConstantSubscripts &, const std::vector<int> *dimOrder = nullptr) const;
80 
81 protected:
82   ConstantSubscript SubscriptsToOffset(const ConstantSubscripts &) const;
83 
84 private:
85   ConstantSubscripts shape_;
86   ConstantSubscripts lbounds_;
87 };
88 
89 // Constant<> is specialized for Character kinds and SomeDerived.
90 // The non-Character intrinsic types, and SomeDerived, share enough
91 // common behavior that they use this common base class.
92 template <typename RESULT, typename ELEMENT = Scalar<RESULT>>
93 class ConstantBase : public ConstantBounds {
94   static_assert(RESULT::category != TypeCategory::Character);
95 
96 public:
97   using Result = RESULT;
98   using Element = ELEMENT;
99 
100   template <typename A>
101   ConstantBase(const A &x, Result res = Result{}) : result_{res}, values_{x} {}
102   ConstantBase(ELEMENT &&x, Result res = Result{})
103       : result_{res}, values_{std::move(x)} {}
104   ConstantBase(
105       std::vector<Element> &&, ConstantSubscripts &&, Result = Result{});
106 
107   DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ConstantBase)
108   ~ConstantBase();
109 
110   bool operator==(const ConstantBase &) const;
empty()111   bool empty() const { return values_.empty(); }
size()112   std::size_t size() const { return values_.size(); }
values()113   const std::vector<Element> &values() const { return values_; }
result()114   constexpr Result result() const { return result_; }
115 
GetType()116   constexpr DynamicType GetType() const { return result_.GetType(); }
117   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
118 
119 protected:
120   std::vector<Element> Reshape(const ConstantSubscripts &) const;
121   std::size_t CopyFrom(const ConstantBase &source, std::size_t count,
122       ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
123 
124   Result result_;
125   std::vector<Element> values_;
126 };
127 
128 template <typename T> class Constant : public ConstantBase<T> {
129 public:
130   using Result = T;
131   using Base = ConstantBase<T>;
132   using Element = Scalar<T>;
133 
134   using Base::Base;
CLASS_BOILERPLATE(Constant)135   CLASS_BOILERPLATE(Constant)
136 
137   std::optional<Scalar<T>> GetScalarValue() const {
138     if (ConstantBounds::Rank() == 0) {
139       return Base::values_.at(0);
140     } else {
141       return std::nullopt;
142     }
143   }
144 
145   // Apply subscripts.  Excess subscripts are ignored, including the
146   // case of a scalar.
147   Element At(const ConstantSubscripts &) const;
148 
149   Constant Reshape(ConstantSubscripts &&) const;
150   std::size_t CopyFrom(const Constant &source, std::size_t count,
151       ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
152 };
153 
154 template <int KIND>
155 class Constant<Type<TypeCategory::Character, KIND>> : public ConstantBounds {
156 public:
157   using Result = Type<TypeCategory::Character, KIND>;
158   using Element = Scalar<Result>;
159 
160   CLASS_BOILERPLATE(Constant)
161   explicit Constant(const Scalar<Result> &);
162   explicit Constant(Scalar<Result> &&);
163   Constant(
164       ConstantSubscript length, std::vector<Element> &&, ConstantSubscripts &&);
165   ~Constant();
166 
167   bool operator==(const Constant &that) const {
168     return shape() == that.shape() && values_ == that.values_;
169   }
170   bool empty() const;
171   std::size_t size() const;
172 
values()173   const Scalar<Result> &values() const { return values_; }
LEN()174   ConstantSubscript LEN() const { return length_; }
175 
GetScalarValue()176   std::optional<Scalar<Result>> GetScalarValue() const {
177     if (Rank() == 0) {
178       return values_;
179     } else {
180       return std::nullopt;
181     }
182   }
183 
184   // Apply subscripts, if any.
185   Scalar<Result> At(const ConstantSubscripts &) const;
186 
187   // Extract substring(s); returns nullopt for errors.
188   std::optional<Constant> Substring(ConstantSubscript, ConstantSubscript) const;
189 
190   Constant Reshape(ConstantSubscripts &&) const;
191   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
GetType()192   DynamicType GetType() const { return {KIND, length_}; }
193   std::size_t CopyFrom(const Constant &source, std::size_t count,
194       ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
195 
196 private:
197   Scalar<Result> values_; // one contiguous string
198   ConstantSubscript length_;
199 };
200 
201 class StructureConstructor;
202 struct ComponentCompare {
203   bool operator()(SymbolRef x, SymbolRef y) const;
204 };
205 using StructureConstructorValues = std::map<SymbolRef,
206     common::CopyableIndirection<Expr<SomeType>>, ComponentCompare>;
207 
208 template <>
209 class Constant<SomeDerived>
210     : public ConstantBase<SomeDerived, StructureConstructorValues> {
211 public:
212   using Result = SomeDerived;
213   using Element = StructureConstructorValues;
214   using Base = ConstantBase<SomeDerived, StructureConstructorValues>;
215 
216   Constant(const StructureConstructor &);
217   Constant(StructureConstructor &&);
218   Constant(const semantics::DerivedTypeSpec &,
219       std::vector<StructureConstructorValues> &&, ConstantSubscripts &&);
220   Constant(const semantics::DerivedTypeSpec &,
221       std::vector<StructureConstructor> &&, ConstantSubscripts &&);
222   CLASS_BOILERPLATE(Constant)
223 
224   std::optional<StructureConstructor> GetScalarValue() const;
225   StructureConstructor At(const ConstantSubscripts &) const;
226 
227   Constant Reshape(ConstantSubscripts &&) const;
228   std::size_t CopyFrom(const Constant &source, std::size_t count,
229       ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
230 };
231 
232 FOR_EACH_LENGTHLESS_INTRINSIC_KIND(extern template class ConstantBase, )
233 extern template class ConstantBase<SomeDerived, StructureConstructorValues>;
234 FOR_EACH_INTRINSIC_KIND(extern template class Constant, )
235 
236 #define INSTANTIATE_CONSTANT_TEMPLATES \
237   FOR_EACH_LENGTHLESS_INTRINSIC_KIND(template class ConstantBase, ) \
238   template class ConstantBase<SomeDerived, StructureConstructorValues>; \
239   FOR_EACH_INTRINSIC_KIND(template class Constant, )
240 } // namespace Fortran::evaluate
241 #endif // FORTRAN_EVALUATE_CONSTANT_H_
242