1 //===-------include/flang/Evaluate/initial-image.h ------------------------===//
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 #ifndef FORTRAN_EVALUATE_INITIAL_IMAGE_H_
10 #define FORTRAN_EVALUATE_INITIAL_IMAGE_H_
11 
12 // Represents the initialized storage of an object during DATA statement
13 // processing, including the conversion of that image to a constant
14 // initializer for a symbol.
15 
16 #include "expression.h"
17 #include <map>
18 #include <optional>
19 #include <vector>
20 
21 namespace Fortran::evaluate {
22 
23 class InitialImage {
24 public:
25   enum Result {
26     Ok,
27     NotAConstant,
28     OutOfRange,
29     SizeMismatch,
30   };
31 
InitialImage(std::size_t bytes)32   explicit InitialImage(std::size_t bytes) : data_(bytes) {}
33   InitialImage(InitialImage &&that) = default;
34 
size()35   std::size_t size() const { return data_.size(); }
36 
37   template <typename A>
Add(ConstantSubscript,std::size_t,const A &,FoldingContext &)38   Result Add(ConstantSubscript, std::size_t, const A &, FoldingContext &) {
39     return NotAConstant;
40   }
41   template <typename T>
Add(ConstantSubscript offset,std::size_t bytes,const Constant<T> & x,FoldingContext & context)42   Result Add(ConstantSubscript offset, std::size_t bytes, const Constant<T> &x,
43       FoldingContext &context) {
44     if (offset < 0 || offset + bytes > data_.size()) {
45       return OutOfRange;
46     } else {
47       auto elementBytes{ToInt64(x.GetType().MeasureSizeInBytes(context, true))};
48       if (!elementBytes ||
49           bytes !=
50               x.values().size() * static_cast<std::size_t>(*elementBytes)) {
51         return SizeMismatch;
52       } else if (bytes == 0) {
53         return Ok;
54       } else {
55         // TODO endianness
56         std::memcpy(&data_.at(offset), &x.values().at(0), bytes);
57         return Ok;
58       }
59     }
60   }
61   template <int KIND>
Add(ConstantSubscript offset,std::size_t bytes,const Constant<Type<TypeCategory::Character,KIND>> & x,FoldingContext &)62   Result Add(ConstantSubscript offset, std::size_t bytes,
63       const Constant<Type<TypeCategory::Character, KIND>> &x,
64       FoldingContext &) {
65     if (offset < 0 || offset + bytes > data_.size()) {
66       return OutOfRange;
67     } else {
68       auto elements{TotalElementCount(x.shape())};
69       auto elementBytes{bytes > 0 ? bytes / elements : 0};
70       if (elements * elementBytes != bytes) {
71         return SizeMismatch;
72       } else if (bytes == 0) {
73         return Ok;
74       } else {
75         for (auto at{x.lbounds()}; elements-- > 0; x.IncrementSubscripts(at)) {
76           auto scalar{x.At(at)}; // this is a std string; size() in chars
77           // Subtle: an initializer for a substring may have been
78           // expanded to the length of the entire string.
79           auto scalarBytes{scalar.size() * KIND};
80           if (scalarBytes < elementBytes ||
81               (scalarBytes > elementBytes && elements != 0)) {
82             return SizeMismatch;
83           }
84           // TODO endianness
85           std::memcpy(&data_.at(offset), scalar.data(), elementBytes);
86           offset += elementBytes;
87         }
88         return Ok;
89       }
90     }
91   }
92   Result Add(ConstantSubscript, std::size_t, const Constant<SomeDerived> &,
93       FoldingContext &);
94   template <typename T>
Add(ConstantSubscript offset,std::size_t bytes,const Expr<T> & x,FoldingContext & c)95   Result Add(ConstantSubscript offset, std::size_t bytes, const Expr<T> &x,
96       FoldingContext &c) {
97     return common::visit(
98         [&](const auto &y) { return Add(offset, bytes, y, c); }, x.u);
99   }
100 
101   void AddPointer(ConstantSubscript, const Expr<SomeType> &);
102 
103   void Incorporate(ConstantSubscript toOffset, const InitialImage &from,
104       ConstantSubscript fromOffset, ConstantSubscript bytes);
105 
106   // Conversions to constant initializers
107   std::optional<Expr<SomeType>> AsConstant(FoldingContext &,
108       const DynamicType &, const ConstantSubscripts &, bool padWithZero = false,
109       ConstantSubscript offset = 0) const;
110   std::optional<Expr<SomeType>> AsConstantPointer(
111       ConstantSubscript offset = 0) const;
112 
113   friend class AsConstantHelper;
114 
115 private:
116   std::vector<char> data_;
117   std::map<ConstantSubscript, Expr<SomeType>> pointers_;
118 };
119 
120 } // namespace Fortran::evaluate
121 #endif // FORTRAN_EVALUATE_INITIAL_IMAGE_H_
122