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 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 52 void InitialImage::AddPointer( 53 ConstantSubscript offset, const Expr<SomeType> &pointer) { 54 pointers_.emplace(offset, pointer); 55 } 56 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; 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 } 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 155 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; 166 AsConstantDataPointerHelper(const DynamicType &type, 167 const InitialImage &image, ConstantSubscript offset = 0) 168 : type_{type}, image_{image}, offset_{offset} {} 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 191 std::optional<Expr<SomeType>> InitialImage::AsConstantDataPointer( 192 const DynamicType &type, ConstantSubscript offset) const { 193 return common::SearchTypes(AsConstantDataPointerHelper{type, *this, offset}); 194 } 195 196 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