1 //===-- lib/Evaluate/constant.cpp -----------------------------------------===//
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 #include "flang/Evaluate/constant.h"
10 #include "flang/Evaluate/expression.h"
11 #include "flang/Evaluate/shape.h"
12 #include "flang/Evaluate/type.h"
13 #include <string>
14
15 namespace Fortran::evaluate {
16
ConstantBounds(const ConstantSubscripts & shape)17 ConstantBounds::ConstantBounds(const ConstantSubscripts &shape)
18 : shape_(shape), lbounds_(shape_.size(), 1) {}
19
ConstantBounds(ConstantSubscripts && shape)20 ConstantBounds::ConstantBounds(ConstantSubscripts &&shape)
21 : shape_(std::move(shape)), lbounds_(shape_.size(), 1) {}
22
23 ConstantBounds::~ConstantBounds() = default;
24
set_lbounds(ConstantSubscripts && lb)25 void ConstantBounds::set_lbounds(ConstantSubscripts &&lb) {
26 CHECK(lb.size() == shape_.size());
27 lbounds_ = std::move(lb);
28 }
29
SetLowerBoundsToOne()30 void ConstantBounds::SetLowerBoundsToOne() {
31 for (auto &n : lbounds_) {
32 n = 1;
33 }
34 }
35
SHAPE() const36 Constant<SubscriptInteger> ConstantBounds::SHAPE() const {
37 return AsConstantShape(shape_);
38 }
39
SubscriptsToOffset(const ConstantSubscripts & index) const40 ConstantSubscript ConstantBounds::SubscriptsToOffset(
41 const ConstantSubscripts &index) const {
42 CHECK(GetRank(index) == GetRank(shape_));
43 ConstantSubscript stride{1}, offset{0};
44 int dim{0};
45 for (auto j : index) {
46 auto lb{lbounds_[dim]};
47 auto extent{shape_[dim++]};
48 CHECK(j >= lb && j < lb + extent);
49 offset += stride * (j - lb);
50 stride *= extent;
51 }
52 return offset;
53 }
54
TotalElementCount(const ConstantSubscripts & shape)55 std::size_t TotalElementCount(const ConstantSubscripts &shape) {
56 return static_cast<std::size_t>(GetSize(shape));
57 }
58
IncrementSubscripts(ConstantSubscripts & indices,const std::vector<int> * dimOrder) const59 bool ConstantBounds::IncrementSubscripts(
60 ConstantSubscripts &indices, const std::vector<int> *dimOrder) const {
61 int rank{GetRank(shape_)};
62 CHECK(GetRank(indices) == rank);
63 CHECK(!dimOrder || static_cast<int>(dimOrder->size()) == rank);
64 for (int j{0}; j < rank; ++j) {
65 ConstantSubscript k{dimOrder ? (*dimOrder)[j] : j};
66 auto lb{lbounds_[k]};
67 CHECK(indices[k] >= lb);
68 if (++indices[k] < lb + shape_[k]) {
69 return true;
70 } else {
71 CHECK(indices[k] == lb + shape_[k]);
72 indices[k] = lb;
73 }
74 }
75 return false; // all done
76 }
77
ValidateDimensionOrder(int rank,const std::vector<int> & order)78 std::optional<std::vector<int>> ValidateDimensionOrder(
79 int rank, const std::vector<int> &order) {
80 std::vector<int> dimOrder(rank);
81 if (static_cast<int>(order.size()) == rank) {
82 std::bitset<common::maxRank> seenDimensions;
83 for (int j{0}; j < rank; ++j) {
84 int dim{order[j]};
85 if (dim < 1 || dim > rank || seenDimensions.test(dim - 1)) {
86 return std::nullopt;
87 }
88 dimOrder[dim - 1] = j;
89 seenDimensions.set(dim - 1);
90 }
91 return dimOrder;
92 } else {
93 return std::nullopt;
94 }
95 }
96
HasNegativeExtent(const ConstantSubscripts & shape)97 bool HasNegativeExtent(const ConstantSubscripts &shape) {
98 for (ConstantSubscript extent : shape) {
99 if (extent < 0) {
100 return true;
101 }
102 }
103 return false;
104 }
105
106 template <typename RESULT, typename ELEMENT>
ConstantBase(std::vector<Element> && x,ConstantSubscripts && sh,Result res)107 ConstantBase<RESULT, ELEMENT>::ConstantBase(
108 std::vector<Element> &&x, ConstantSubscripts &&sh, Result res)
109 : ConstantBounds(std::move(sh)), result_{res}, values_(std::move(x)) {
110 CHECK(size() == TotalElementCount(shape()));
111 }
112
113 template <typename RESULT, typename ELEMENT>
~ConstantBase()114 ConstantBase<RESULT, ELEMENT>::~ConstantBase() {}
115
116 template <typename RESULT, typename ELEMENT>
operator ==(const ConstantBase & that) const117 bool ConstantBase<RESULT, ELEMENT>::operator==(const ConstantBase &that) const {
118 return shape() == that.shape() && values_ == that.values_;
119 }
120
121 template <typename RESULT, typename ELEMENT>
Reshape(const ConstantSubscripts & dims) const122 auto ConstantBase<RESULT, ELEMENT>::Reshape(
123 const ConstantSubscripts &dims) const -> std::vector<Element> {
124 std::size_t n{TotalElementCount(dims)};
125 CHECK(!empty() || n == 0);
126 std::vector<Element> elements;
127 auto iter{values().cbegin()};
128 while (n-- > 0) {
129 elements.push_back(*iter);
130 if (++iter == values().cend()) {
131 iter = values().cbegin();
132 }
133 }
134 return elements;
135 }
136
137 template <typename RESULT, typename ELEMENT>
CopyFrom(const ConstantBase<RESULT,ELEMENT> & source,std::size_t count,ConstantSubscripts & resultSubscripts,const std::vector<int> * dimOrder)138 std::size_t ConstantBase<RESULT, ELEMENT>::CopyFrom(
139 const ConstantBase<RESULT, ELEMENT> &source, std::size_t count,
140 ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder) {
141 std::size_t copied{0};
142 ConstantSubscripts sourceSubscripts{source.lbounds()};
143 while (copied < count) {
144 values_.at(SubscriptsToOffset(resultSubscripts)) =
145 source.values_.at(source.SubscriptsToOffset(sourceSubscripts));
146 copied++;
147 source.IncrementSubscripts(sourceSubscripts);
148 IncrementSubscripts(resultSubscripts, dimOrder);
149 }
150 return copied;
151 }
152
153 template <typename T>
At(const ConstantSubscripts & index) const154 auto Constant<T>::At(const ConstantSubscripts &index) const -> Element {
155 return Base::values_.at(Base::SubscriptsToOffset(index));
156 }
157
158 template <typename T>
Reshape(ConstantSubscripts && dims) const159 auto Constant<T>::Reshape(ConstantSubscripts &&dims) const -> Constant {
160 return {Base::Reshape(dims), std::move(dims)};
161 }
162
163 template <typename T>
CopyFrom(const Constant<T> & source,std::size_t count,ConstantSubscripts & resultSubscripts,const std::vector<int> * dimOrder)164 std::size_t Constant<T>::CopyFrom(const Constant<T> &source, std::size_t count,
165 ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder) {
166 return Base::CopyFrom(source, count, resultSubscripts, dimOrder);
167 }
168
169 // Constant<Type<TypeCategory::Character, KIND> specializations
170 template <int KIND>
Constant(const Scalar<Result> & str)171 Constant<Type<TypeCategory::Character, KIND>>::Constant(
172 const Scalar<Result> &str)
173 : values_{str}, length_{static_cast<ConstantSubscript>(values_.size())} {}
174
175 template <int KIND>
Constant(Scalar<Result> && str)176 Constant<Type<TypeCategory::Character, KIND>>::Constant(Scalar<Result> &&str)
177 : values_{std::move(str)}, length_{static_cast<ConstantSubscript>(
178 values_.size())} {}
179
180 template <int KIND>
Constant(ConstantSubscript len,std::vector<Scalar<Result>> && strings,ConstantSubscripts && sh)181 Constant<Type<TypeCategory::Character, KIND>>::Constant(ConstantSubscript len,
182 std::vector<Scalar<Result>> &&strings, ConstantSubscripts &&sh)
183 : ConstantBounds(std::move(sh)), length_{len} {
184 CHECK(strings.size() == TotalElementCount(shape()));
185 values_.assign(strings.size() * length_,
186 static_cast<typename Scalar<Result>::value_type>(' '));
187 ConstantSubscript at{0};
188 for (const auto &str : strings) {
189 auto strLen{static_cast<ConstantSubscript>(str.size())};
190 if (strLen > length_) {
191 values_.replace(at, length_, str.substr(0, length_));
192 } else {
193 values_.replace(at, strLen, str);
194 }
195 at += length_;
196 }
197 CHECK(at == static_cast<ConstantSubscript>(values_.size()));
198 }
199
200 template <int KIND>
~Constant()201 Constant<Type<TypeCategory::Character, KIND>>::~Constant() {}
202
203 template <int KIND>
empty() const204 bool Constant<Type<TypeCategory::Character, KIND>>::empty() const {
205 return size() == 0;
206 }
207
208 template <int KIND>
size() const209 std::size_t Constant<Type<TypeCategory::Character, KIND>>::size() const {
210 if (length_ == 0) {
211 return TotalElementCount(shape());
212 } else {
213 return static_cast<ConstantSubscript>(values_.size()) / length_;
214 }
215 }
216
217 template <int KIND>
At(const ConstantSubscripts & index) const218 auto Constant<Type<TypeCategory::Character, KIND>>::At(
219 const ConstantSubscripts &index) const -> Scalar<Result> {
220 auto offset{SubscriptsToOffset(index)};
221 return values_.substr(offset * length_, length_);
222 }
223
224 template <int KIND>
Reshape(ConstantSubscripts && dims) const225 auto Constant<Type<TypeCategory::Character, KIND>>::Reshape(
226 ConstantSubscripts &&dims) const -> Constant<Result> {
227 std::size_t n{TotalElementCount(dims)};
228 CHECK(!empty() || n == 0);
229 std::vector<Element> elements;
230 ConstantSubscript at{0},
231 limit{static_cast<ConstantSubscript>(values_.size())};
232 while (n-- > 0) {
233 elements.push_back(values_.substr(at, length_));
234 at += length_;
235 if (at == limit) { // subtle: at > limit somehow? substr() will catch it
236 at = 0;
237 }
238 }
239 return {length_, std::move(elements), std::move(dims)};
240 }
241
242 template <int KIND>
CopyFrom(const Constant<Type<TypeCategory::Character,KIND>> & source,std::size_t count,ConstantSubscripts & resultSubscripts,const std::vector<int> * dimOrder)243 std::size_t Constant<Type<TypeCategory::Character, KIND>>::CopyFrom(
244 const Constant<Type<TypeCategory::Character, KIND>> &source,
245 std::size_t count, ConstantSubscripts &resultSubscripts,
246 const std::vector<int> *dimOrder) {
247 CHECK(length_ == source.length_);
248 if (length_ == 0) {
249 // It's possible that the array of strings consists of all empty strings.
250 // If so, constant folding will result in a string that's completely empty
251 // and the length_ will be zero, and there's nothing to do.
252 return count;
253 } else {
254 std::size_t copied{0};
255 std::size_t elementBytes{length_ * sizeof(decltype(values_[0]))};
256 ConstantSubscripts sourceSubscripts{source.lbounds()};
257 while (copied < count) {
258 auto *dest{&values_.at(SubscriptsToOffset(resultSubscripts) * length_)};
259 const auto *src{&source.values_.at(
260 source.SubscriptsToOffset(sourceSubscripts) * length_)};
261 std::memcpy(dest, src, elementBytes);
262 copied++;
263 source.IncrementSubscripts(sourceSubscripts);
264 IncrementSubscripts(resultSubscripts, dimOrder);
265 }
266 return copied;
267 }
268 }
269
270 // Constant<SomeDerived> specialization
Constant(const StructureConstructor & x)271 Constant<SomeDerived>::Constant(const StructureConstructor &x)
272 : Base{x.values(), Result{x.derivedTypeSpec()}} {}
273
Constant(StructureConstructor && x)274 Constant<SomeDerived>::Constant(StructureConstructor &&x)
275 : Base{std::move(x.values()), Result{x.derivedTypeSpec()}} {}
276
Constant(const semantics::DerivedTypeSpec & spec,std::vector<StructureConstructorValues> && x,ConstantSubscripts && s)277 Constant<SomeDerived>::Constant(const semantics::DerivedTypeSpec &spec,
278 std::vector<StructureConstructorValues> &&x, ConstantSubscripts &&s)
279 : Base{std::move(x), std::move(s), Result{spec}} {}
280
AcquireValues(std::vector<StructureConstructor> && x)281 static std::vector<StructureConstructorValues> AcquireValues(
282 std::vector<StructureConstructor> &&x) {
283 std::vector<StructureConstructorValues> result;
284 for (auto &&structure : std::move(x)) {
285 result.emplace_back(std::move(structure.values()));
286 }
287 return result;
288 }
289
Constant(const semantics::DerivedTypeSpec & spec,std::vector<StructureConstructor> && x,ConstantSubscripts && shape)290 Constant<SomeDerived>::Constant(const semantics::DerivedTypeSpec &spec,
291 std::vector<StructureConstructor> &&x, ConstantSubscripts &&shape)
292 : Base{AcquireValues(std::move(x)), std::move(shape), Result{spec}} {}
293
294 std::optional<StructureConstructor>
GetScalarValue() const295 Constant<SomeDerived>::GetScalarValue() const {
296 if (Rank() == 0) {
297 return StructureConstructor{result().derivedTypeSpec(), values_.at(0)};
298 } else {
299 return std::nullopt;
300 }
301 }
302
At(const ConstantSubscripts & index) const303 StructureConstructor Constant<SomeDerived>::At(
304 const ConstantSubscripts &index) const {
305 return {result().derivedTypeSpec(), values_.at(SubscriptsToOffset(index))};
306 }
307
Reshape(ConstantSubscripts && dims) const308 auto Constant<SomeDerived>::Reshape(ConstantSubscripts &&dims) const
309 -> Constant {
310 return {result().derivedTypeSpec(), Base::Reshape(dims), std::move(dims)};
311 }
312
CopyFrom(const Constant<SomeDerived> & source,std::size_t count,ConstantSubscripts & resultSubscripts,const std::vector<int> * dimOrder)313 std::size_t Constant<SomeDerived>::CopyFrom(const Constant<SomeDerived> &source,
314 std::size_t count, ConstantSubscripts &resultSubscripts,
315 const std::vector<int> *dimOrder) {
316 return Base::CopyFrom(source, count, resultSubscripts, dimOrder);
317 }
318
operator ()(SymbolRef x,SymbolRef y) const319 bool ComponentCompare::operator()(SymbolRef x, SymbolRef y) const {
320 return semantics::SymbolSourcePositionCompare{}(x, y);
321 }
322
323 INSTANTIATE_CONSTANT_TEMPLATES
324 } // namespace Fortran::evaluate
325