1286d7a21Speter klausler //===-- lib/Evaluate/initial-image.cpp ------------------------------------===//
2286d7a21Speter klausler //
3286d7a21Speter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4286d7a21Speter klausler // See https://llvm.org/LICENSE.txt for license information.
5286d7a21Speter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6286d7a21Speter klausler //
7286d7a21Speter klausler //===----------------------------------------------------------------------===//
8286d7a21Speter klausler
9286d7a21Speter klausler #include "flang/Evaluate/initial-image.h"
10286d7a21Speter klausler #include "flang/Semantics/scope.h"
11286d7a21Speter klausler #include "flang/Semantics/tools.h"
124ac617f4Speter klausler #include <cstring>
13286d7a21Speter klausler
14286d7a21Speter klausler namespace Fortran::evaluate {
15286d7a21Speter klausler
Add(ConstantSubscript offset,std::size_t bytes,const Constant<SomeDerived> & x,FoldingContext & context)16a20d48d7Speter klausler auto InitialImage::Add(ConstantSubscript offset, std::size_t bytes,
176aa3591eSpeter klausler const Constant<SomeDerived> &x, FoldingContext &context) -> Result {
18a20d48d7Speter klausler if (offset < 0 || offset + bytes > data_.size()) {
19a20d48d7Speter klausler return OutOfRange;
20a20d48d7Speter klausler } else {
217358c26dSLeandro Lupori auto optElements{TotalElementCount(x.shape())};
227358c26dSLeandro Lupori if (!optElements) {
237358c26dSLeandro Lupori return TooManyElems;
247358c26dSLeandro Lupori }
257358c26dSLeandro Lupori auto elements{*optElements};
26286d7a21Speter klausler auto elementBytes{bytes > 0 ? bytes / elements : 0};
27a20d48d7Speter klausler if (elements * elementBytes != bytes) {
28a20d48d7Speter klausler return SizeMismatch;
29a20d48d7Speter klausler } else {
30286d7a21Speter klausler auto at{x.lbounds()};
31d484fe93SPeter Klausler for (; elements-- > 0; x.IncrementSubscripts(at)) {
32286d7a21Speter klausler auto scalar{x.At(at)};
33286d7a21Speter klausler // TODO: length type parameter values?
34286d7a21Speter klausler for (const auto &[symbolRef, indExpr] : scalar) {
35286d7a21Speter klausler const Symbol &component{*symbolRef};
36a20d48d7Speter klausler if (component.offset() + component.size() > elementBytes) {
37a20d48d7Speter klausler return SizeMismatch;
38a20d48d7Speter klausler } else if (IsPointer(component)) {
39286d7a21Speter klausler AddPointer(offset + component.offset(), indExpr.value());
4012ec5b20SPeter Klausler } else if (IsAllocatable(component) || IsAutomatic(component)) {
4112ec5b20SPeter Klausler return NotAConstant;
42beb437edSPeter Klausler } else if (auto result{Add(offset + component.offset(),
43beb437edSPeter Klausler component.size(), indExpr.value(), context)};
44beb437edSPeter Klausler result != Ok) {
45beb437edSPeter Klausler return result;
46286d7a21Speter klausler }
47286d7a21Speter klausler }
48286d7a21Speter klausler offset += elementBytes;
49286d7a21Speter klausler }
50a20d48d7Speter klausler }
51a20d48d7Speter klausler return Ok;
52a20d48d7Speter klausler }
53286d7a21Speter klausler }
54286d7a21Speter klausler
AddPointer(ConstantSubscript offset,const Expr<SomeType> & pointer)55286d7a21Speter klausler void InitialImage::AddPointer(
56286d7a21Speter klausler ConstantSubscript offset, const Expr<SomeType> &pointer) {
57286d7a21Speter klausler pointers_.emplace(offset, pointer);
58286d7a21Speter klausler }
59286d7a21Speter klausler
Incorporate(ConstantSubscript toOffset,const InitialImage & from,ConstantSubscript fromOffset,ConstantSubscript bytes)60d60a0220Speter klausler void InitialImage::Incorporate(ConstantSubscript toOffset,
61d60a0220Speter klausler const InitialImage &from, ConstantSubscript fromOffset,
62d60a0220Speter klausler ConstantSubscript bytes) {
63d60a0220Speter klausler CHECK(from.pointers_.empty()); // pointers are not allowed in EQUIVALENCE
64d60a0220Speter klausler CHECK(fromOffset >= 0 && bytes >= 0 &&
65d60a0220Speter klausler static_cast<std::size_t>(fromOffset + bytes) <= from.size());
66d60a0220Speter klausler CHECK(static_cast<std::size_t>(toOffset + bytes) <= size());
67d60a0220Speter klausler std::memcpy(&data_[toOffset], &from.data_[fromOffset], bytes);
684ac617f4Speter klausler }
694ac617f4Speter klausler
70286d7a21Speter klausler // Classes used with common::SearchTypes() to (re)construct Constant<> values
71286d7a21Speter klausler // of the right type to initialize each symbol from the values that have
72286d7a21Speter klausler // been placed into its initialization image by DATA statements.
73286d7a21Speter klausler class AsConstantHelper {
74286d7a21Speter klausler public:
75286d7a21Speter klausler using Result = std::optional<Expr<SomeType>>;
76286d7a21Speter klausler using Types = AllTypes;
AsConstantHelper(FoldingContext & context,const DynamicType & type,std::optional<std::int64_t> charLength,const ConstantSubscripts & extents,const InitialImage & image,bool padWithZero=false,ConstantSubscript offset=0)77286d7a21Speter klausler AsConstantHelper(FoldingContext &context, const DynamicType &type,
78e6be8da1SPeter Klausler std::optional<std::int64_t> charLength, const ConstantSubscripts &extents,
79e6be8da1SPeter Klausler const InitialImage &image, bool padWithZero = false,
80e6be8da1SPeter Klausler ConstantSubscript offset = 0)
81e6be8da1SPeter Klausler : context_{context}, type_{type}, charLength_{charLength}, image_{image},
82e6be8da1SPeter Klausler extents_{extents}, padWithZero_{padWithZero}, offset_{offset} {
83286d7a21Speter klausler CHECK(!type.IsPolymorphic());
84286d7a21Speter klausler }
Test()85286d7a21Speter klausler template <typename T> Result Test() {
86286d7a21Speter klausler if (T::category != type_.category()) {
87286d7a21Speter klausler return std::nullopt;
88286d7a21Speter klausler }
89286d7a21Speter klausler if constexpr (T::category != TypeCategory::Derived) {
90286d7a21Speter klausler if (T::kind != type_.kind()) {
91286d7a21Speter klausler return std::nullopt;
92286d7a21Speter klausler }
93286d7a21Speter klausler }
94286d7a21Speter klausler using Const = Constant<T>;
95286d7a21Speter klausler using Scalar = typename Const::Element;
967358c26dSLeandro Lupori std::optional<uint64_t> optElements{TotalElementCount(extents_)};
977358c26dSLeandro Lupori CHECK(optElements);
987358c26dSLeandro Lupori uint64_t elements{*optElements};
99286d7a21Speter klausler std::vector<Scalar> typedValue(elements);
100e6be8da1SPeter Klausler auto elemBytes{ToInt64(type_.MeasureSizeInBytes(
101e6be8da1SPeter Klausler context_, GetRank(extents_) > 0, charLength_))};
102fad31d60Speter klausler CHECK(elemBytes && *elemBytes >= 0);
103fad31d60Speter klausler std::size_t stride{static_cast<std::size_t>(*elemBytes)};
104ae93d8eaSPeter Klausler CHECK(offset_ + elements * stride <= image_.data_.size() || padWithZero_);
105286d7a21Speter klausler if constexpr (T::category == TypeCategory::Derived) {
106286d7a21Speter klausler const semantics::DerivedTypeSpec &derived{type_.GetDerivedTypeSpec()};
107286d7a21Speter klausler for (auto iter : DEREF(derived.scope())) {
108286d7a21Speter klausler const Symbol &component{*iter.second};
109d60a0220Speter klausler bool isProcPtr{IsProcedurePointer(component)};
110d60a0220Speter klausler if (isProcPtr || component.has<semantics::ObjectEntityDetails>()) {
111286d7a21Speter klausler auto at{offset_ + component.offset()};
112d60a0220Speter klausler if (isProcPtr) {
113fad31d60Speter klausler for (std::size_t j{0}; j < elements; ++j, at += stride) {
114d60a0220Speter klausler if (Result value{image_.AsConstantPointer(at)}) {
115286d7a21Speter klausler typedValue[j].emplace(component, std::move(*value));
116286d7a21Speter klausler }
117d60a0220Speter klausler }
118d60a0220Speter klausler } else if (IsPointer(component)) {
119fad31d60Speter klausler for (std::size_t j{0}; j < elements; ++j, at += stride) {
120d60a0220Speter klausler if (Result value{image_.AsConstantPointer(at)}) {
121286d7a21Speter klausler typedValue[j].emplace(component, std::move(*value));
122*4739c883SPeter Klausler } else {
123*4739c883SPeter Klausler typedValue[j].emplace(component, Expr<SomeType>{NullPointer{}});
124286d7a21Speter klausler }
125286d7a21Speter klausler }
126*4739c883SPeter Klausler } else if (IsAllocatable(component)) {
127*4739c883SPeter Klausler // Lowering needs an explicit NULL() for allocatables
128*4739c883SPeter Klausler for (std::size_t j{0}; j < elements; ++j, at += stride) {
129*4739c883SPeter Klausler typedValue[j].emplace(component, Expr<SomeType>{NullPointer{}});
130*4739c883SPeter Klausler }
131*4739c883SPeter Klausler } else {
132d60a0220Speter klausler auto componentType{DynamicType::From(component)};
133d60a0220Speter klausler CHECK(componentType.has_value());
134d60a0220Speter klausler auto componentExtents{GetConstantExtents(context_, component)};
135d60a0220Speter klausler CHECK(componentExtents.has_value());
136d60a0220Speter klausler for (std::size_t j{0}; j < elements; ++j, at += stride) {
137ae93d8eaSPeter Klausler if (Result value{image_.AsConstant(context_, *componentType,
138e6be8da1SPeter Klausler std::nullopt, *componentExtents, padWithZero_, at)}) {
139d60a0220Speter klausler typedValue[j].emplace(component, std::move(*value));
140d60a0220Speter klausler }
141d60a0220Speter klausler }
142d60a0220Speter klausler }
143286d7a21Speter klausler }
144286d7a21Speter klausler }
145286d7a21Speter klausler return AsGenericExpr(
146286d7a21Speter klausler Const{derived, std::move(typedValue), std::move(extents_)});
147286d7a21Speter klausler } else if constexpr (T::category == TypeCategory::Character) {
148fad31d60Speter klausler auto length{static_cast<ConstantSubscript>(stride) / T::kind};
149286d7a21Speter klausler for (std::size_t j{0}; j < elements; ++j) {
150286d7a21Speter klausler using Char = typename Scalar::value_type;
151ae93d8eaSPeter Klausler auto at{static_cast<std::size_t>(offset_ + j * stride)};
15260b1fcb1SPeter Klausler auto chunk{length};
15360b1fcb1SPeter Klausler if (at + chunk > image_.data_.size()) {
154ae93d8eaSPeter Klausler CHECK(padWithZero_);
15560b1fcb1SPeter Klausler if (at >= image_.data_.size()) {
15660b1fcb1SPeter Klausler chunk = 0;
15760b1fcb1SPeter Klausler } else {
15860b1fcb1SPeter Klausler chunk = image_.data_.size() - at;
159ae93d8eaSPeter Klausler }
16060b1fcb1SPeter Klausler }
16160b1fcb1SPeter Klausler if (chunk > 0) {
162ae93d8eaSPeter Klausler const Char *data{reinterpret_cast<const Char *>(&image_.data_[at])};
16360b1fcb1SPeter Klausler typedValue[j].assign(data, chunk);
16460b1fcb1SPeter Klausler }
16560b1fcb1SPeter Klausler if (chunk < length && padWithZero_) {
16660b1fcb1SPeter Klausler typedValue[j].append(length - chunk, Char{});
16760b1fcb1SPeter Klausler }
168286d7a21Speter klausler }
169286d7a21Speter klausler return AsGenericExpr(
170286d7a21Speter klausler Const{length, std::move(typedValue), std::move(extents_)});
171286d7a21Speter klausler } else {
172286d7a21Speter klausler // Lengthless intrinsic type
173fad31d60Speter klausler CHECK(sizeof(Scalar) <= stride);
174286d7a21Speter klausler for (std::size_t j{0}; j < elements; ++j) {
175ae93d8eaSPeter Klausler auto at{static_cast<std::size_t>(offset_ + j * stride)};
176ae93d8eaSPeter Klausler std::size_t chunk{sizeof(Scalar)};
177ae93d8eaSPeter Klausler if (at + chunk > image_.data_.size()) {
178ae93d8eaSPeter Klausler CHECK(padWithZero_);
179ae93d8eaSPeter Klausler if (at >= image_.data_.size()) {
18060b1fcb1SPeter Klausler chunk = 0;
18160b1fcb1SPeter Klausler } else {
182ae93d8eaSPeter Klausler chunk = image_.data_.size() - at;
183ae93d8eaSPeter Klausler }
18460b1fcb1SPeter Klausler }
185ae93d8eaSPeter Klausler // TODO endianness
18660b1fcb1SPeter Klausler if (chunk > 0) {
187ae93d8eaSPeter Klausler std::memcpy(&typedValue[j], &image_.data_[at], chunk);
188286d7a21Speter klausler }
18960b1fcb1SPeter Klausler }
190286d7a21Speter klausler return AsGenericExpr(Const{std::move(typedValue), std::move(extents_)});
191286d7a21Speter klausler }
192286d7a21Speter klausler }
193286d7a21Speter klausler
194286d7a21Speter klausler private:
195286d7a21Speter klausler FoldingContext &context_;
196286d7a21Speter klausler const DynamicType &type_;
197e6be8da1SPeter Klausler std::optional<std::int64_t> charLength_;
198286d7a21Speter klausler const InitialImage &image_;
199286d7a21Speter klausler ConstantSubscripts extents_; // a copy
200ae93d8eaSPeter Klausler bool padWithZero_;
201286d7a21Speter klausler ConstantSubscript offset_;
202286d7a21Speter klausler };
203286d7a21Speter klausler
AsConstant(FoldingContext & context,const DynamicType & type,std::optional<std::int64_t> charLength,const ConstantSubscripts & extents,bool padWithZero,ConstantSubscript offset) const204286d7a21Speter klausler std::optional<Expr<SomeType>> InitialImage::AsConstant(FoldingContext &context,
205e6be8da1SPeter Klausler const DynamicType &type, std::optional<std::int64_t> charLength,
206e6be8da1SPeter Klausler const ConstantSubscripts &extents, bool padWithZero,
207e6be8da1SPeter Klausler ConstantSubscript offset) const {
208e6be8da1SPeter Klausler return common::SearchTypes(AsConstantHelper{
209e6be8da1SPeter Klausler context, type, charLength, extents, *this, padWithZero, offset});
210286d7a21Speter klausler }
211286d7a21Speter klausler
AsConstantPointer(ConstantSubscript offset) const212d60a0220Speter klausler std::optional<Expr<SomeType>> InitialImage::AsConstantPointer(
213286d7a21Speter klausler ConstantSubscript offset) const {
214d60a0220Speter klausler auto iter{pointers_.find(offset)};
215d60a0220Speter klausler return iter == pointers_.end() ? std::optional<Expr<SomeType>>{}
216d60a0220Speter klausler : iter->second;
217286d7a21Speter klausler }
218286d7a21Speter klausler
219286d7a21Speter klausler } // namespace Fortran::evaluate
220