1 //===-- lib/Evaluate/initial-image.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/initial-image.h"
10 #include "flang/Semantics/scope.h"
11 #include "flang/Semantics/tools.h"
14 namespace Fortran::evaluate
{
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()) {
21 auto elements
{TotalElementCount(x
.shape())};
22 auto elementBytes
{bytes
> 0 ? bytes
/ elements
: 0};
23 if (elements
* elementBytes
!= bytes
) {
27 for (; elements
-- > 0; x
.IncrementSubscripts(at
)) {
28 auto scalar
{x
.At(at
)};
29 // TODO: length type parameter values?
30 for (const auto &[symbolRef
, indExpr
] : scalar
) {
31 const Symbol
&component
{*symbolRef
};
32 if (component
.offset() + component
.size() > elementBytes
) {
34 } else if (IsPointer(component
)) {
35 AddPointer(offset
+ component
.offset(), indExpr
.value());
36 } else if (IsAllocatable(component
) || IsAutomatic(component
)) {
39 Result added
{Add(offset
+ component
.offset(), component
.size(),
40 indExpr
.value(), context
)};
46 offset
+= elementBytes
;
53 void InitialImage::AddPointer(
54 ConstantSubscript offset
, const Expr
<SomeType
> &pointer
) {
55 pointers_
.emplace(offset
, pointer
);
58 void InitialImage::Incorporate(ConstantSubscript toOffset
,
59 const InitialImage
&from
, ConstantSubscript fromOffset
,
60 ConstantSubscript bytes
) {
61 CHECK(from
.pointers_
.empty()); // pointers are not allowed in EQUIVALENCE
62 CHECK(fromOffset
>= 0 && bytes
>= 0 &&
63 static_cast<std::size_t>(fromOffset
+ bytes
) <= from
.size());
64 CHECK(static_cast<std::size_t>(toOffset
+ bytes
) <= size());
65 std::memcpy(&data_
[toOffset
], &from
.data_
[fromOffset
], bytes
);
68 // Classes used with common::SearchTypes() to (re)construct Constant<> values
69 // of the right type to initialize each symbol from the values that have
70 // been placed into its initialization image by DATA statements.
71 class AsConstantHelper
{
73 using Result
= std::optional
<Expr
<SomeType
>>;
74 using Types
= AllTypes
;
75 AsConstantHelper(FoldingContext
&context
, const DynamicType
&type
,
76 const ConstantSubscripts
&extents
, const InitialImage
&image
,
77 bool padWithZero
= false, ConstantSubscript offset
= 0)
78 : context_
{context
}, type_
{type
}, image_
{image
}, extents_
{extents
},
79 padWithZero_
{padWithZero
}, offset_
{offset
} {
80 CHECK(!type
.IsPolymorphic());
82 template <typename T
> Result
Test() {
83 if (T::category
!= type_
.category()) {
86 if constexpr (T::category
!= TypeCategory::Derived
) {
87 if (T::kind
!= type_
.kind()) {
91 using Const
= Constant
<T
>;
92 using Scalar
= typename
Const::Element
;
93 std::size_t elements
{TotalElementCount(extents_
)};
94 std::vector
<Scalar
> typedValue(elements
);
96 ToInt64(type_
.MeasureSizeInBytes(context_
, GetRank(extents_
) > 0))};
97 CHECK(elemBytes
&& *elemBytes
>= 0);
98 std::size_t stride
{static_cast<std::size_t>(*elemBytes
)};
99 CHECK(offset_
+ elements
* stride
<= image_
.data_
.size() || padWithZero_
);
100 if constexpr (T::category
== TypeCategory::Derived
) {
101 const semantics::DerivedTypeSpec
&derived
{type_
.GetDerivedTypeSpec()};
102 for (auto iter
: DEREF(derived
.scope())) {
103 const Symbol
&component
{*iter
.second
};
104 bool isProcPtr
{IsProcedurePointer(component
)};
105 if (isProcPtr
|| component
.has
<semantics::ObjectEntityDetails
>()) {
106 auto at
{offset_
+ component
.offset()};
108 for (std::size_t j
{0}; j
< elements
; ++j
, at
+= stride
) {
109 if (Result value
{image_
.AsConstantPointer(at
)}) {
110 typedValue
[j
].emplace(component
, std::move(*value
));
113 } else if (IsPointer(component
)) {
114 for (std::size_t j
{0}; j
< elements
; ++j
, at
+= stride
) {
115 if (Result value
{image_
.AsConstantPointer(at
)}) {
116 typedValue
[j
].emplace(component
, std::move(*value
));
119 } else if (!IsAllocatable(component
)) {
120 auto componentType
{DynamicType::From(component
)};
121 CHECK(componentType
.has_value());
122 auto componentExtents
{GetConstantExtents(context_
, component
)};
123 CHECK(componentExtents
.has_value());
124 for (std::size_t j
{0}; j
< elements
; ++j
, at
+= stride
) {
125 if (Result value
{image_
.AsConstant(context_
, *componentType
,
126 *componentExtents
, padWithZero_
, at
)}) {
127 typedValue
[j
].emplace(component
, std::move(*value
));
133 return AsGenericExpr(
134 Const
{derived
, std::move(typedValue
), std::move(extents_
)});
135 } else if constexpr (T::category
== TypeCategory::Character
) {
136 auto length
{static_cast<ConstantSubscript
>(stride
) / T::kind
};
137 for (std::size_t j
{0}; j
< elements
; ++j
) {
138 using Char
= typename
Scalar::value_type
;
139 auto at
{static_cast<std::size_t>(offset_
+ j
* stride
)};
141 if (at
+ chunk
> image_
.data_
.size()) {
143 if (at
>= image_
.data_
.size()) {
146 chunk
= image_
.data_
.size() - at
;
150 const Char
*data
{reinterpret_cast<const Char
*>(&image_
.data_
[at
])};
151 typedValue
[j
].assign(data
, chunk
);
153 if (chunk
< length
&& padWithZero_
) {
154 typedValue
[j
].append(length
- chunk
, Char
{});
157 return AsGenericExpr(
158 Const
{length
, std::move(typedValue
), std::move(extents_
)});
160 // Lengthless intrinsic type
161 CHECK(sizeof(Scalar
) <= stride
);
162 for (std::size_t j
{0}; j
< elements
; ++j
) {
163 auto at
{static_cast<std::size_t>(offset_
+ j
* stride
)};
164 std::size_t chunk
{sizeof(Scalar
)};
165 if (at
+ chunk
> image_
.data_
.size()) {
167 if (at
>= image_
.data_
.size()) {
170 chunk
= image_
.data_
.size() - at
;
175 std::memcpy(&typedValue
[j
], &image_
.data_
[at
], chunk
);
178 return AsGenericExpr(Const
{std::move(typedValue
), std::move(extents_
)});
183 FoldingContext
&context_
;
184 const DynamicType
&type_
;
185 const InitialImage
&image_
;
186 ConstantSubscripts extents_
; // a copy
188 ConstantSubscript offset_
;
191 std::optional
<Expr
<SomeType
>> InitialImage::AsConstant(FoldingContext
&context
,
192 const DynamicType
&type
, const ConstantSubscripts
&extents
,
193 bool padWithZero
, ConstantSubscript offset
) const {
194 return common::SearchTypes(
195 AsConstantHelper
{context
, type
, extents
, *this, padWithZero
, offset
});
198 std::optional
<Expr
<SomeType
>> InitialImage::AsConstantPointer(
199 ConstantSubscript offset
) const {
200 auto iter
{pointers_
.find(offset
)};
201 return iter
== pointers_
.end() ? std::optional
<Expr
<SomeType
>>{}
205 } // namespace Fortran::evaluate