1 //===-- lib/Evaluate/constant.cpp -----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Evaluate/constant.h"
10 #include "flang/Evaluate/expression.h"
11 #include "flang/Evaluate/shape.h"
12 #include "flang/Evaluate/type.h"
15 namespace Fortran::evaluate
{
17 ConstantBounds::ConstantBounds(const ConstantSubscripts
&shape
)
18 : shape_(shape
), lbounds_(shape_
.size(), 1) {}
20 ConstantBounds::ConstantBounds(ConstantSubscripts
&&shape
)
21 : shape_(std::move(shape
)), lbounds_(shape_
.size(), 1) {}
23 ConstantBounds::~ConstantBounds() = default;
25 void ConstantBounds::set_lbounds(ConstantSubscripts
&&lb
) {
26 CHECK(lb
.size() == shape_
.size());
27 lbounds_
= std::move(lb
);
28 for (std::size_t j
{0}; j
< shape_
.size(); ++j
) {
35 ConstantSubscripts
ConstantBounds::ComputeUbounds(
36 std::optional
<int> dim
) const {
39 return {lbounds_
[*dim
] + (shape_
[*dim
] - 1)};
41 ConstantSubscripts
ubounds(Rank());
42 for (int i
{0}; i
< Rank(); ++i
) {
43 ubounds
[i
] = lbounds_
[i
] + (shape_
[i
] - 1);
49 void ConstantBounds::SetLowerBoundsToOne() {
50 for (auto &n
: lbounds_
) {
55 Constant
<SubscriptInteger
> ConstantBounds::SHAPE() const {
56 return AsConstantShape(shape_
);
59 bool ConstantBounds::HasNonDefaultLowerBound() const {
60 for (auto n
: lbounds_
) {
68 ConstantSubscript
ConstantBounds::SubscriptsToOffset(
69 const ConstantSubscripts
&index
) const {
70 CHECK(GetRank(index
) == GetRank(shape_
));
71 ConstantSubscript stride
{1}, offset
{0};
73 for (auto j
: index
) {
74 auto lb
{lbounds_
[dim
]};
75 auto extent
{shape_
[dim
++]};
76 CHECK(j
>= lb
&& j
- lb
< extent
);
77 offset
+= stride
* (j
- lb
);
83 std::optional
<uint64_t> TotalElementCount(const ConstantSubscripts
&shape
) {
85 for (auto dim
: shape
) {
89 if (size
> std::numeric_limits
<decltype(dim
)>::max() ||
90 (dim
!= 0 && size
/ dim
!= osize
)) {
94 return static_cast<uint64_t>(GetSize(shape
));
97 bool ConstantBounds::IncrementSubscripts(
98 ConstantSubscripts
&indices
, const std::vector
<int> *dimOrder
) const {
99 int rank
{GetRank(shape_
)};
100 CHECK(GetRank(indices
) == rank
);
101 CHECK(!dimOrder
|| static_cast<int>(dimOrder
->size()) == rank
);
102 for (int j
{0}; j
< rank
; ++j
) {
103 ConstantSubscript k
{dimOrder
? (*dimOrder
)[j
] : j
};
104 auto lb
{lbounds_
[k
]};
105 CHECK(indices
[k
] >= lb
);
106 if (++indices
[k
] - lb
< shape_
[k
]) {
109 CHECK(indices
[k
] - lb
== std::max
<ConstantSubscript
>(shape_
[k
], 1));
113 return false; // all done
116 std::optional
<std::vector
<int>> ValidateDimensionOrder(
117 int rank
, const std::vector
<int> &order
) {
118 std::vector
<int> dimOrder(rank
);
119 if (static_cast<int>(order
.size()) == rank
) {
120 std::bitset
<common::maxRank
> seenDimensions
;
121 for (int j
{0}; j
< rank
; ++j
) {
123 if (dim
< 1 || dim
> rank
|| seenDimensions
.test(dim
- 1)) {
126 dimOrder
[j
] = dim
- 1;
127 seenDimensions
.set(dim
- 1);
135 bool HasNegativeExtent(const ConstantSubscripts
&shape
) {
136 for (ConstantSubscript extent
: shape
) {
144 template <typename RESULT
, typename ELEMENT
>
145 ConstantBase
<RESULT
, ELEMENT
>::ConstantBase(
146 std::vector
<Element
> &&x
, ConstantSubscripts
&&sh
, Result res
)
147 : ConstantBounds(std::move(sh
)), result_
{res
}, values_(std::move(x
)) {
148 CHECK(TotalElementCount(shape()) && size() == *TotalElementCount(shape()));
151 template <typename RESULT
, typename ELEMENT
>
152 ConstantBase
<RESULT
, ELEMENT
>::~ConstantBase() {}
154 template <typename RESULT
, typename ELEMENT
>
155 bool ConstantBase
<RESULT
, ELEMENT
>::operator==(const ConstantBase
&that
) const {
156 return shape() == that
.shape() && values_
== that
.values_
;
159 template <typename RESULT
, typename ELEMENT
>
160 auto ConstantBase
<RESULT
, ELEMENT
>::Reshape(
161 const ConstantSubscripts
&dims
) const -> std::vector
<Element
> {
162 std::optional
<uint64_t> optN
{TotalElementCount(dims
)};
163 CHECK_MSG(optN
, "Overflow in TotalElementCount");
165 CHECK(!empty() || n
== 0);
166 std::vector
<Element
> elements
;
167 auto iter
{values().cbegin()};
169 elements
.push_back(*iter
);
170 if (++iter
== values().cend()) {
171 iter
= values().cbegin();
177 template <typename RESULT
, typename ELEMENT
>
178 std::size_t ConstantBase
<RESULT
, ELEMENT
>::CopyFrom(
179 const ConstantBase
<RESULT
, ELEMENT
> &source
, std::size_t count
,
180 ConstantSubscripts
&resultSubscripts
, const std::vector
<int> *dimOrder
) {
181 std::size_t copied
{0};
182 ConstantSubscripts sourceSubscripts
{source
.lbounds()};
183 while (copied
< count
) {
184 values_
.at(SubscriptsToOffset(resultSubscripts
)) =
185 source
.values_
.at(source
.SubscriptsToOffset(sourceSubscripts
));
187 source
.IncrementSubscripts(sourceSubscripts
);
188 IncrementSubscripts(resultSubscripts
, dimOrder
);
193 template <typename T
>
194 auto Constant
<T
>::At(const ConstantSubscripts
&index
) const -> Element
{
195 return Base::values_
.at(Base::SubscriptsToOffset(index
));
198 template <typename T
>
199 auto Constant
<T
>::Reshape(ConstantSubscripts
&&dims
) const -> Constant
{
200 return {Base::Reshape(dims
), std::move(dims
)};
203 template <typename T
>
204 std::size_t Constant
<T
>::CopyFrom(const Constant
<T
> &source
, std::size_t count
,
205 ConstantSubscripts
&resultSubscripts
, const std::vector
<int> *dimOrder
) {
206 return Base::CopyFrom(source
, count
, resultSubscripts
, dimOrder
);
209 // Constant<Type<TypeCategory::Character, KIND> specializations
211 Constant
<Type
<TypeCategory::Character
, KIND
>>::Constant(
212 const Scalar
<Result
> &str
)
213 : values_
{str
}, length_
{static_cast<ConstantSubscript
>(values_
.size())} {}
216 Constant
<Type
<TypeCategory::Character
, KIND
>>::Constant(Scalar
<Result
> &&str
)
217 : values_
{std::move(str
)}, length_
{static_cast<ConstantSubscript
>(
221 Constant
<Type
<TypeCategory::Character
, KIND
>>::Constant(ConstantSubscript len
,
222 std::vector
<Scalar
<Result
>> &&strings
, ConstantSubscripts
&&sh
)
223 : ConstantBounds(std::move(sh
)), length_
{len
} {
224 CHECK(TotalElementCount(shape()) &&
225 strings
.size() == *TotalElementCount(shape()));
226 values_
.assign(strings
.size() * length_
,
227 static_cast<typename Scalar
<Result
>::value_type
>(' '));
228 ConstantSubscript at
{0};
229 for (const auto &str
: strings
) {
230 auto strLen
{static_cast<ConstantSubscript
>(str
.size())};
231 if (strLen
> length_
) {
232 values_
.replace(at
, length_
, str
.substr(0, length_
));
234 values_
.replace(at
, strLen
, str
);
238 CHECK(at
== static_cast<ConstantSubscript
>(values_
.size()));
242 Constant
<Type
<TypeCategory::Character
, KIND
>>::~Constant() {}
245 bool Constant
<Type
<TypeCategory::Character
, KIND
>>::empty() const {
250 std::size_t Constant
<Type
<TypeCategory::Character
, KIND
>>::size() const {
252 std::optional
<uint64_t> n
{TotalElementCount(shape())};
256 return static_cast<ConstantSubscript
>(values_
.size()) / length_
;
261 auto Constant
<Type
<TypeCategory::Character
, KIND
>>::At(
262 const ConstantSubscripts
&index
) const -> Scalar
<Result
> {
263 auto offset
{SubscriptsToOffset(index
)};
264 return values_
.substr(offset
* length_
, length_
);
268 auto Constant
<Type
<TypeCategory::Character
, KIND
>>::Substring(
269 ConstantSubscript lo
, ConstantSubscript hi
) const
270 -> std::optional
<Constant
> {
271 std::vector
<Element
> elements
;
272 ConstantSubscript n
{GetSize(shape())};
273 ConstantSubscript newLength
{0};
274 if (lo
> hi
) { // zero-length results
276 elements
.emplace_back(); // ""
278 } else if (lo
< 1 || hi
> length_
) {
281 newLength
= hi
- lo
+ 1;
282 for (ConstantSubscripts at
{lbounds()}; n
-- > 0; IncrementSubscripts(at
)) {
283 elements
.emplace_back(At(at
).substr(lo
- 1, newLength
));
286 return Constant
{newLength
, std::move(elements
), ConstantSubscripts
{shape()}};
290 auto Constant
<Type
<TypeCategory::Character
, KIND
>>::Reshape(
291 ConstantSubscripts
&&dims
) const -> Constant
<Result
> {
292 std::optional
<uint64_t> optN
{TotalElementCount(dims
)};
295 CHECK(!empty() || n
== 0);
296 std::vector
<Element
> elements
;
297 ConstantSubscript at
{0},
298 limit
{static_cast<ConstantSubscript
>(values_
.size())};
300 elements
.push_back(values_
.substr(at
, length_
));
302 if (at
== limit
) { // subtle: at > limit somehow? substr() will catch it
306 return {length_
, std::move(elements
), std::move(dims
)};
310 std::size_t Constant
<Type
<TypeCategory::Character
, KIND
>>::CopyFrom(
311 const Constant
<Type
<TypeCategory::Character
, KIND
>> &source
,
312 std::size_t count
, ConstantSubscripts
&resultSubscripts
,
313 const std::vector
<int> *dimOrder
) {
314 CHECK(length_
== source
.length_
);
316 // It's possible that the array of strings consists of all empty strings.
317 // If so, constant folding will result in a string that's completely empty
318 // and the length_ will be zero, and there's nothing to do.
321 std::size_t copied
{0};
322 std::size_t elementBytes
{length_
* sizeof(decltype(values_
[0]))};
323 ConstantSubscripts sourceSubscripts
{source
.lbounds()};
324 while (copied
< count
) {
325 auto *dest
{&values_
.at(SubscriptsToOffset(resultSubscripts
) * length_
)};
326 const auto *src
{&source
.values_
.at(
327 source
.SubscriptsToOffset(sourceSubscripts
) * length_
)};
328 std::memcpy(dest
, src
, elementBytes
);
330 source
.IncrementSubscripts(sourceSubscripts
);
331 IncrementSubscripts(resultSubscripts
, dimOrder
);
337 // Constant<SomeDerived> specialization
338 Constant
<SomeDerived
>::Constant(const StructureConstructor
&x
)
339 : Base
{x
.values(), Result
{x
.derivedTypeSpec()}} {}
341 Constant
<SomeDerived
>::Constant(StructureConstructor
&&x
)
342 : Base
{std::move(x
.values()), Result
{x
.derivedTypeSpec()}} {}
344 Constant
<SomeDerived
>::Constant(const semantics::DerivedTypeSpec
&spec
,
345 std::vector
<StructureConstructorValues
> &&x
, ConstantSubscripts
&&s
)
346 : Base
{std::move(x
), std::move(s
), Result
{spec
}} {}
348 static std::vector
<StructureConstructorValues
> AcquireValues(
349 std::vector
<StructureConstructor
> &&x
) {
350 std::vector
<StructureConstructorValues
> result
;
351 for (auto &&structure
: std::move(x
)) {
352 result
.emplace_back(std::move(structure
.values()));
357 Constant
<SomeDerived
>::Constant(const semantics::DerivedTypeSpec
&spec
,
358 std::vector
<StructureConstructor
> &&x
, ConstantSubscripts
&&shape
)
359 : Base
{AcquireValues(std::move(x
)), std::move(shape
), Result
{spec
}} {}
361 std::optional
<StructureConstructor
>
362 Constant
<SomeDerived
>::GetScalarValue() const {
364 return StructureConstructor
{result().derivedTypeSpec(), values_
.at(0)};
370 StructureConstructor Constant
<SomeDerived
>::At(
371 const ConstantSubscripts
&index
) const {
372 return {result().derivedTypeSpec(), values_
.at(SubscriptsToOffset(index
))};
375 bool Constant
<SomeDerived
>::operator==(
376 const Constant
<SomeDerived
> &that
) const {
377 return result().derivedTypeSpec() == that
.result().derivedTypeSpec() &&
378 shape() == that
.shape() && values_
== that
.values_
;
381 auto Constant
<SomeDerived
>::Reshape(ConstantSubscripts
&&dims
) const
383 return {result().derivedTypeSpec(), Base::Reshape(dims
), std::move(dims
)};
386 std::size_t Constant
<SomeDerived
>::CopyFrom(const Constant
<SomeDerived
> &source
,
387 std::size_t count
, ConstantSubscripts
&resultSubscripts
,
388 const std::vector
<int> *dimOrder
) {
389 return Base::CopyFrom(source
, count
, resultSubscripts
, dimOrder
);
392 bool ComponentCompare::operator()(SymbolRef x
, SymbolRef y
) const {
393 return semantics::SymbolSourcePositionCompare
{}(x
, y
);
396 #ifdef _MSC_VER // disable bogus warning about missing definitions
397 #pragma warning(disable : 4661)
399 INSTANTIATE_CONSTANT_TEMPLATES
400 } // namespace Fortran::evaluate