1 //===-- lib/Evaluate/initial-image.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/initial-image.h"
10 #include "flang/Semantics/scope.h"
11 #include "flang/Semantics/tools.h"
12 #include <cstring>
13 
14 namespace Fortran::evaluate {
15 
Add(ConstantSubscript offset,std::size_t bytes,const Constant<SomeDerived> & x,FoldingContext & context)16 auto InitialImage::Add(ConstantSubscript offset, std::size_t bytes,
17     const Constant<SomeDerived> &x, FoldingContext &context) -> Result {
18   if (offset < 0 || offset + bytes > data_.size()) {
19     return OutOfRange;
20   } else {
21     auto elements{TotalElementCount(x.shape())};
22     auto elementBytes{bytes > 0 ? bytes / elements : 0};
23     if (elements * elementBytes != bytes) {
24       return SizeMismatch;
25     } else {
26       auto at{x.lbounds()};
27       for (auto elements{TotalElementCount(x.shape())}; elements-- > 0;
28            x.IncrementSubscripts(at)) {
29         auto scalar{x.At(at)};
30         // TODO: length type parameter values?
31         for (const auto &[symbolRef, indExpr] : scalar) {
32           const Symbol &component{*symbolRef};
33           if (component.offset() + component.size() > elementBytes) {
34             return SizeMismatch;
35           } else if (IsPointer(component)) {
36             AddPointer(offset + component.offset(), indExpr.value());
37           } else {
38             Result added{Add(offset + component.offset(), component.size(),
39                 indExpr.value(), context)};
40             if (added != Ok) {
41               return Ok;
42             }
43           }
44         }
45         offset += elementBytes;
46       }
47     }
48     return Ok;
49   }
50 }
51 
AddPointer(ConstantSubscript offset,const Expr<SomeType> & pointer)52 void InitialImage::AddPointer(
53     ConstantSubscript offset, const Expr<SomeType> &pointer) {
54   pointers_.emplace(offset, pointer);
55 }
56 
Incorporate(ConstantSubscript offset,const InitialImage & that)57 void InitialImage::Incorporate(
58     ConstantSubscript offset, const InitialImage &that) {
59   CHECK(that.pointers_.empty()); // pointers are not allowed in EQUIVALENCE
60   CHECK(offset + that.size() <= size());
61   std::memcpy(&data_[offset], &that.data_[0], that.size());
62 }
63 
64 // Classes used with common::SearchTypes() to (re)construct Constant<> values
65 // of the right type to initialize each symbol from the values that have
66 // been placed into its initialization image by DATA statements.
67 class AsConstantHelper {
68 public:
69   using Result = std::optional<Expr<SomeType>>;
70   using Types = AllTypes;
AsConstantHelper(FoldingContext & context,const DynamicType & type,const ConstantSubscripts & extents,const InitialImage & image,ConstantSubscript offset=0)71   AsConstantHelper(FoldingContext &context, const DynamicType &type,
72       const ConstantSubscripts &extents, const InitialImage &image,
73       ConstantSubscript offset = 0)
74       : context_{context}, type_{type}, image_{image}, extents_{extents},
75         offset_{offset} {
76     CHECK(!type.IsPolymorphic());
77   }
Test()78   template <typename T> Result Test() {
79     if (T::category != type_.category()) {
80       return std::nullopt;
81     }
82     if constexpr (T::category != TypeCategory::Derived) {
83       if (T::kind != type_.kind()) {
84         return std::nullopt;
85       }
86     }
87     using Const = Constant<T>;
88     using Scalar = typename Const::Element;
89     std::size_t elements{TotalElementCount(extents_)};
90     std::vector<Scalar> typedValue(elements);
91     auto elemBytes{
92         ToInt64(type_.MeasureSizeInBytes(context_, GetRank(extents_) > 0))};
93     CHECK(elemBytes && *elemBytes >= 0);
94     std::size_t stride{static_cast<std::size_t>(*elemBytes)};
95     CHECK(offset_ + elements * stride <= image_.data_.size());
96     if constexpr (T::category == TypeCategory::Derived) {
97       const semantics::DerivedTypeSpec &derived{type_.GetDerivedTypeSpec()};
98       for (auto iter : DEREF(derived.scope())) {
99         const Symbol &component{*iter.second};
100         bool isPointer{IsPointer(component)};
101         if (component.has<semantics::ObjectEntityDetails>() ||
102             component.has<semantics::ProcEntityDetails>()) {
103           auto componentType{DynamicType::From(component)};
104           CHECK(componentType);
105           auto at{offset_ + component.offset()};
106           if (isPointer) {
107             for (std::size_t j{0}; j < elements; ++j, at += stride) {
108               Result value{image_.AsConstantDataPointer(*componentType, at)};
109               CHECK(value);
110               typedValue[j].emplace(component, std::move(*value));
111             }
112           } else {
113             auto componentExtents{GetConstantExtents(context_, component)};
114             CHECK(componentExtents);
115             for (std::size_t j{0}; j < elements; ++j, at += stride) {
116               Result value{image_.AsConstant(
117                   context_, *componentType, *componentExtents, at)};
118               CHECK(value);
119               typedValue[j].emplace(component, std::move(*value));
120             }
121           }
122         }
123       }
124       return AsGenericExpr(
125           Const{derived, std::move(typedValue), std::move(extents_)});
126     } else if constexpr (T::category == TypeCategory::Character) {
127       auto length{static_cast<ConstantSubscript>(stride) / T::kind};
128       for (std::size_t j{0}; j < elements; ++j) {
129         using Char = typename Scalar::value_type;
130         const Char *data{reinterpret_cast<const Char *>(
131             &image_.data_[offset_ + j * stride])};
132         typedValue[j].assign(data, length);
133       }
134       return AsGenericExpr(
135           Const{length, std::move(typedValue), std::move(extents_)});
136     } else {
137       // Lengthless intrinsic type
138       CHECK(sizeof(Scalar) <= stride);
139       for (std::size_t j{0}; j < elements; ++j) {
140         std::memcpy(&typedValue[j], &image_.data_[offset_ + j * stride],
141             sizeof(Scalar));
142       }
143       return AsGenericExpr(Const{std::move(typedValue), std::move(extents_)});
144     }
145   }
146 
147 private:
148   FoldingContext &context_;
149   const DynamicType &type_;
150   const InitialImage &image_;
151   ConstantSubscripts extents_; // a copy
152   ConstantSubscript offset_;
153 };
154 
AsConstant(FoldingContext & context,const DynamicType & type,const ConstantSubscripts & extents,ConstantSubscript offset) const155 std::optional<Expr<SomeType>> InitialImage::AsConstant(FoldingContext &context,
156     const DynamicType &type, const ConstantSubscripts &extents,
157     ConstantSubscript offset) const {
158   return common::SearchTypes(
159       AsConstantHelper{context, type, extents, *this, offset});
160 }
161 
162 class AsConstantDataPointerHelper {
163 public:
164   using Result = std::optional<Expr<SomeType>>;
165   using Types = AllTypes;
AsConstantDataPointerHelper(const DynamicType & type,const InitialImage & image,ConstantSubscript offset=0)166   AsConstantDataPointerHelper(const DynamicType &type,
167       const InitialImage &image, ConstantSubscript offset = 0)
168       : type_{type}, image_{image}, offset_{offset} {}
Test()169   template <typename T> Result Test() {
170     if (T::category != type_.category()) {
171       return std::nullopt;
172     }
173     if constexpr (T::category != TypeCategory::Derived) {
174       if (T::kind != type_.kind()) {
175         return std::nullopt;
176       }
177     }
178     auto iter{image_.pointers_.find(offset_)};
179     if (iter == image_.pointers_.end()) {
180       return AsGenericExpr(NullPointer{});
181     }
182     return iter->second;
183   }
184 
185 private:
186   const DynamicType &type_;
187   const InitialImage &image_;
188   ConstantSubscript offset_;
189 };
190 
AsConstantDataPointer(const DynamicType & type,ConstantSubscript offset) const191 std::optional<Expr<SomeType>> InitialImage::AsConstantDataPointer(
192     const DynamicType &type, ConstantSubscript offset) const {
193   return common::SearchTypes(AsConstantDataPointerHelper{type, *this, offset});
194 }
195 
AsConstantProcPointer(ConstantSubscript offset) const196 const ProcedureDesignator &InitialImage::AsConstantProcPointer(
197     ConstantSubscript offset) const {
198   auto iter{pointers_.find(0)};
199   CHECK(iter != pointers_.end());
200   return DEREF(std::get_if<ProcedureDesignator>(&iter->second.u));
201 }
202 
203 } // namespace Fortran::evaluate
204