xref: /llvm-project/flang/include/flang/Evaluate/constant.h (revision 3a8a52f4a52e0c301a5f3d6acce684c7fd4a6d57)
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>;
45 inline int GetRank(const ConstantSubscripts &s) {
46   return static_cast<int>(s.size());
47 }
48 
49 // Returns the number of elements of shape, if no overflow occurs.
50 std::optional<uint64_t> TotalElementCount(const ConstantSubscripts &shape);
51 
52 // Validate dimension re-ordering like ORDER in RESHAPE.
53 // On success, return a vector that can be used as dimOrder in
54 // ConstantBounds::IncrementSubscripts().
55 std::optional<std::vector<int>> ValidateDimensionOrder(
56     int rank, const std::vector<int> &order);
57 
58 bool HasNegativeExtent(const ConstantSubscripts &);
59 
60 class ConstantBounds {
61 public:
62   ConstantBounds() = default;
63   explicit ConstantBounds(const ConstantSubscripts &shape);
64   explicit ConstantBounds(ConstantSubscripts &&shape);
65   ~ConstantBounds();
66   const ConstantSubscripts &shape() const { return shape_; }
67   int Rank() const { return GetRank(shape_); }
68   static constexpr int Corank() { return 0; }
69   Constant<SubscriptInteger> SHAPE() const;
70 
71   // It is possible in this representation for a constant array to have
72   // lower bounds other than 1, which is of course not expressible in
73   // Fortran.  This case arises only from definitions of named constant
74   // arrays with such bounds, as in:
75   //   REAL, PARAMETER :: NAMED(0:1) = [1.,2.]
76   // Bundling the lower bounds of the named constant with its
77   // constant value allows folding of subscripted array element
78   // references, LBOUND, and UBOUND without having to thread the named
79   // constant or its bounds throughout folding.
80   const ConstantSubscripts &lbounds() const { return lbounds_; }
81   ConstantSubscripts ComputeUbounds(std::optional<int> dim) const;
82   void set_lbounds(ConstantSubscripts &&);
83   void SetLowerBoundsToOne();
84   bool HasNonDefaultLowerBound() const;
85 
86   // If no optional dimension order argument is passed, increments a vector of
87   // subscripts in Fortran array order (first dimension varying most quickly).
88   // Otherwise, increments the vector of subscripts according to the given
89   // dimension order (dimension dimOrder[0] varying most quickly; dimension
90   // indexing is zero based here). Returns false when last element was visited.
91   bool IncrementSubscripts(
92       ConstantSubscripts &, const std::vector<int> *dimOrder = nullptr) const;
93 
94 protected:
95   ConstantSubscript SubscriptsToOffset(const ConstantSubscripts &) const;
96 
97 private:
98   ConstantSubscripts shape_;
99   ConstantSubscripts lbounds_;
100 };
101 
102 // Constant<> is specialized for Character kinds and SomeDerived.
103 // The non-Character intrinsic types, and SomeDerived, share enough
104 // common behavior that they use this common base class.
105 template <typename RESULT, typename ELEMENT = Scalar<RESULT>>
106 class ConstantBase : public ConstantBounds {
107   static_assert(RESULT::category != TypeCategory::Character);
108 
109 public:
110   using Result = RESULT;
111   using Element = ELEMENT;
112 
113   template <typename A>
114   ConstantBase(const A &x, Result res = Result{}) : result_{res}, values_{x} {}
115   ConstantBase(ELEMENT &&x, Result res = Result{})
116       : result_{res}, values_{std::move(x)} {}
117   ConstantBase(
118       std::vector<Element> &&, ConstantSubscripts &&, Result = Result{});
119 
120   DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ConstantBase)
121   ~ConstantBase();
122 
123   bool operator==(const ConstantBase &) const;
124   bool empty() const { return values_.empty(); }
125   std::size_t size() const { return values_.size(); }
126   const std::vector<Element> &values() const { return values_; }
127   constexpr Result result() const { return result_; }
128 
129   constexpr DynamicType GetType() const { return result_.GetType(); }
130   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
131 
132 protected:
133   std::vector<Element> Reshape(const ConstantSubscripts &) const;
134   std::size_t CopyFrom(const ConstantBase &source, std::size_t count,
135       ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
136 
137   Result result_;
138   std::vector<Element> values_;
139 };
140 
141 template <typename T> class Constant : public ConstantBase<T> {
142 public:
143   using Result = T;
144   using Base = ConstantBase<T>;
145   using Element = Scalar<T>;
146 
147   using Base::Base;
148   CLASS_BOILERPLATE(Constant)
149 
150   std::optional<Scalar<T>> GetScalarValue() const {
151     if (ConstantBounds::Rank() == 0) {
152       return Base::values_.at(0);
153     } else {
154       return std::nullopt;
155     }
156   }
157 
158   // Apply subscripts.  Excess subscripts are ignored, including the
159   // case of a scalar.
160   Element At(const ConstantSubscripts &) const;
161 
162   Constant Reshape(ConstantSubscripts &&) const;
163   std::size_t CopyFrom(const Constant &source, std::size_t count,
164       ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
165 };
166 
167 template <int KIND>
168 class Constant<Type<TypeCategory::Character, KIND>> : public ConstantBounds {
169 public:
170   using Result = Type<TypeCategory::Character, KIND>;
171   using Element = Scalar<Result>;
172 
173   CLASS_BOILERPLATE(Constant)
174   explicit Constant(const Scalar<Result> &);
175   explicit Constant(Scalar<Result> &&);
176   Constant(
177       ConstantSubscript length, std::vector<Element> &&, ConstantSubscripts &&);
178   ~Constant();
179 
180   bool operator==(const Constant &that) const {
181     return LEN() == that.LEN() && shape() == that.shape() &&
182         values_ == that.values_;
183   }
184   bool empty() const;
185   std::size_t size() const;
186 
187   const Scalar<Result> &values() const { return values_; }
188   ConstantSubscript LEN() const { return length_; }
189   bool wasHollerith() const { return wasHollerith_; }
190   void set_wasHollerith(bool yes = true) { wasHollerith_ = yes; }
191 
192   std::optional<Scalar<Result>> GetScalarValue() const {
193     if (Rank() == 0) {
194       return values_;
195     } else {
196       return std::nullopt;
197     }
198   }
199 
200   // Apply subscripts, if any.
201   Scalar<Result> At(const ConstantSubscripts &) const;
202 
203   // Extract substring(s); returns nullopt for errors.
204   std::optional<Constant> Substring(ConstantSubscript, ConstantSubscript) const;
205 
206   Constant Reshape(ConstantSubscripts &&) const;
207   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
208   DynamicType GetType() const { return {KIND, length_}; }
209   std::size_t CopyFrom(const Constant &source, std::size_t count,
210       ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
211 
212 private:
213   Scalar<Result> values_; // one contiguous string
214   ConstantSubscript length_;
215   bool wasHollerith_{false};
216 };
217 
218 class StructureConstructor;
219 struct ComponentCompare {
220   bool operator()(SymbolRef x, SymbolRef y) const;
221 };
222 using StructureConstructorValues = std::map<SymbolRef,
223     common::CopyableIndirection<Expr<SomeType>>, ComponentCompare>;
224 
225 template <>
226 class Constant<SomeDerived>
227     : public ConstantBase<SomeDerived, StructureConstructorValues> {
228 public:
229   using Result = SomeDerived;
230   using Element = StructureConstructorValues;
231   using Base = ConstantBase<SomeDerived, StructureConstructorValues>;
232 
233   Constant(const StructureConstructor &);
234   Constant(StructureConstructor &&);
235   Constant(const semantics::DerivedTypeSpec &,
236       std::vector<StructureConstructorValues> &&, ConstantSubscripts &&);
237   Constant(const semantics::DerivedTypeSpec &,
238       std::vector<StructureConstructor> &&, ConstantSubscripts &&);
239   CLASS_BOILERPLATE(Constant)
240 
241   std::optional<StructureConstructor> GetScalarValue() const;
242   StructureConstructor At(const ConstantSubscripts &) const;
243 
244   bool operator==(const Constant &) const;
245   Constant Reshape(ConstantSubscripts &&) const;
246   std::size_t CopyFrom(const Constant &source, std::size_t count,
247       ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
248 };
249 
250 FOR_EACH_LENGTHLESS_INTRINSIC_KIND(extern template class ConstantBase, )
251 extern template class ConstantBase<SomeDerived, StructureConstructorValues>;
252 FOR_EACH_INTRINSIC_KIND(extern template class Constant, )
253 
254 #define INSTANTIATE_CONSTANT_TEMPLATES \
255   FOR_EACH_LENGTHLESS_INTRINSIC_KIND(template class ConstantBase, ) \
256   template class ConstantBase<SomeDerived, StructureConstructorValues>; \
257   FOR_EACH_INTRINSIC_KIND(template class Constant, )
258 } // namespace Fortran::evaluate
259 #endif // FORTRAN_EVALUATE_CONSTANT_H_
260