FLANG
constant.h
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/reference.h"
15#include "flang/Support/default-kinds.h"
16#include <map>
17#include <vector>
18
19namespace llvm {
20class raw_ostream;
21}
22
23namespace Fortran::semantics {
24class Symbol;
25}
26
27namespace Fortran::evaluate {
28
29using semantics::Symbol;
30using 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
40template <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.
44using ConstantSubscripts = std::vector<ConstantSubscript>;
45inline 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.
50std::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().
55std::optional<std::vector<int>> ValidateDimensionOrder(
56 int rank, const std::vector<int> &order);
57
58bool HasNegativeExtent(const ConstantSubscripts &);
59
60class ConstantBounds {
61public:
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
94protected:
95 ConstantSubscript SubscriptsToOffset(const ConstantSubscripts &) const;
96
97private:
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.
105template <typename RESULT, typename ELEMENT = Scalar<RESULT>>
106class ConstantBase : public ConstantBounds {
107 static_assert(RESULT::category != TypeCategory::Character);
108
109public:
110 using Result = RESULT;
111 using Element = ELEMENT;
112
113 // Constructor for creating ConstantBase from an actual value (i.e.
114 // literals, etc.)
115 template <typename A,
116 typename = std::enable_if_t<std::is_convertible_v<A, Element>>>
117 ConstantBase(const A &x, Result res = Result{}) : result_{res}, values_{x} {}
118
119 ConstantBase(ELEMENT &&x, Result res = Result{})
120 : result_{res}, values_{std::move(x)} {}
121 ConstantBase(
122 std::vector<Element> &&, ConstantSubscripts &&, Result = Result{});
123
124 DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ConstantBase)
125 ~ConstantBase();
126
127 bool operator==(const ConstantBase &) const;
128 bool empty() const { return values_.empty(); }
129 std::size_t size() const { return values_.size(); }
130 const std::vector<Element> &values() const { return values_; }
131 Result &result() { return result_; }
132 const Result &result() const { return result_; }
133
134 constexpr DynamicType GetType() const { return result_.GetType(); }
135 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
136 std::string AsFortran() const;
137
138protected:
139 std::vector<Element> Reshape(const ConstantSubscripts &) const;
140 std::size_t CopyFrom(const ConstantBase &source, std::size_t count,
141 ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
142
143 Result result_; // usually empty except for Real & Complex
144 std::vector<Element> values_;
145};
146
147template <typename T> class Constant : public ConstantBase<T> {
148public:
149 using Result = T;
150 using Base = ConstantBase<T>;
151 using Element = Scalar<T>;
152
153 using Base::Base;
154 CLASS_BOILERPLATE(Constant)
155
156 std::optional<Scalar<T>> GetScalarValue() const {
157 if (ConstantBounds::Rank() == 0) {
158 return Base::values_.at(0);
159 } else {
160 return std::nullopt;
161 }
162 }
163
164 // Apply subscripts. Excess subscripts are ignored, including the
165 // case of a scalar.
166 Element At(const ConstantSubscripts &) const;
167
168 Constant Reshape(ConstantSubscripts &&) const;
169 std::size_t CopyFrom(const Constant &source, std::size_t count,
170 ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
171};
172
173template <int KIND>
174class Constant<Type<TypeCategory::Character, KIND>> : public ConstantBounds {
175public:
177 using Element = Scalar<Result>;
178
179 CLASS_BOILERPLATE(Constant)
180 explicit Constant(const Scalar<Result> &);
181 explicit Constant(Scalar<Result> &&);
182 Constant(
183 ConstantSubscript length, std::vector<Element> &&, ConstantSubscripts &&);
184 ~Constant();
185
186 bool operator==(const Constant &that) const {
187 return LEN() == that.LEN() && shape() == that.shape() &&
188 values_ == that.values_;
189 }
190 bool empty() const;
191 std::size_t size() const;
192
193 const Scalar<Result> &values() const { return values_; }
194 ConstantSubscript LEN() const { return length_; }
195 bool wasHollerith() const { return wasHollerith_; }
196 void set_wasHollerith(bool yes = true) { wasHollerith_ = yes; }
197
198 std::optional<Scalar<Result>> GetScalarValue() const {
199 if (Rank() == 0) {
200 return values_;
201 } else {
202 return std::nullopt;
203 }
204 }
205
206 // Apply subscripts, if any.
207 Scalar<Result> At(const ConstantSubscripts &) const;
208
209 // Extract substring(s); returns nullopt for errors.
210 std::optional<Constant> Substring(ConstantSubscript, ConstantSubscript) const;
211
212 Constant Reshape(ConstantSubscripts &&) const;
213 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
214 std::string AsFortran() const;
215 DynamicType GetType() const { return {KIND, length_}; }
216 std::size_t CopyFrom(const Constant &source, std::size_t count,
217 ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
218
219private:
220 Scalar<Result> values_; // one contiguous string
221 ConstantSubscript length_;
222 bool wasHollerith_{false};
223};
224
227 bool operator()(SymbolRef x, SymbolRef y) const;
228};
229using StructureConstructorValues = std::map<SymbolRef,
230 common::CopyableIndirection<Expr<SomeType>>, ComponentCompare>;
231
232template <>
233class Constant<SomeDerived>
234 : public ConstantBase<SomeDerived, StructureConstructorValues> {
235public:
236 using Result = SomeDerived;
237 using Element = StructureConstructorValues;
238 using Base = ConstantBase<SomeDerived, StructureConstructorValues>;
239
240 Constant(const StructureConstructor &);
241 Constant(StructureConstructor &&);
242 Constant(const semantics::DerivedTypeSpec &,
243 std::vector<StructureConstructorValues> &&, ConstantSubscripts &&);
244 Constant(const semantics::DerivedTypeSpec &,
245 std::vector<StructureConstructor> &&, ConstantSubscripts &&);
246 CLASS_BOILERPLATE(Constant)
247
248 std::optional<StructureConstructor> GetScalarValue() const;
249 StructureConstructor At(const ConstantSubscripts &) const;
250
251 bool operator==(const Constant &) const;
252 Constant Reshape(ConstantSubscripts &&) const;
253 std::size_t CopyFrom(const Constant &source, std::size_t count,
254 ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
255};
256
257FOR_EACH_LENGTHLESS_INTRINSIC_KIND(extern template class ConstantBase, )
258extern template class ConstantBase<SomeDerived, StructureConstructorValues>;
259FOR_EACH_INTRINSIC_KIND(extern template class Constant, )
260
261#define INSTANTIATE_CONSTANT_TEMPLATES \
262 FOR_EACH_LENGTHLESS_INTRINSIC_KIND(template class ConstantBase, ) \
263 template class ConstantBase<SomeDerived, StructureConstructorValues>; \
264 FOR_EACH_INTRINSIC_KIND(template class Constant, )
265} // namespace Fortran::evaluate
266#endif // FORTRAN_EVALUATE_CONSTANT_H_
Definition constant.h:106
Definition constant.h:147
Definition type.h:74
Definition expression.h:740
Definition type.h:57
Definition symbol.h:778
Definition call.h:34
Definition constant.h:226