xref: /llvm-project/flang/include/flang/Evaluate/initial-image.h (revision 7358c26d6acaa6c393623fde7cbc70372d0c67a8)
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     LengthMismatch,
31     TooManyElems
32   };
33 
InitialImage(std::size_t bytes)34   explicit InitialImage(std::size_t bytes) : data_(bytes) {}
35   InitialImage(InitialImage &&that) = default;
36 
size()37   std::size_t size() const { return data_.size(); }
38 
39   template <typename A>
Add(ConstantSubscript,std::size_t,const A &,FoldingContext &)40   Result Add(ConstantSubscript, std::size_t, const A &, FoldingContext &) {
41     return NotAConstant;
42   }
43   template <typename T>
Add(ConstantSubscript offset,std::size_t bytes,const Constant<T> & x,FoldingContext & context)44   Result Add(ConstantSubscript offset, std::size_t bytes, const Constant<T> &x,
45       FoldingContext &context) {
46     if (offset < 0 || offset + bytes > data_.size()) {
47       return OutOfRange;
48     } else {
49       auto elementBytes{ToInt64(x.GetType().MeasureSizeInBytes(context, true))};
50       if (!elementBytes ||
51           bytes !=
52               x.values().size() * static_cast<std::size_t>(*elementBytes)) {
53         return SizeMismatch;
54       } else if (bytes == 0) {
55         return Ok;
56       } else {
57         // TODO endianness
58         std::memcpy(&data_.at(offset), &x.values().at(0), bytes);
59         return Ok;
60       }
61     }
62   }
63   template <int KIND>
Add(ConstantSubscript offset,std::size_t bytes,const Constant<Type<TypeCategory::Character,KIND>> & x,FoldingContext &)64   Result Add(ConstantSubscript offset, std::size_t bytes,
65       const Constant<Type<TypeCategory::Character, KIND>> &x,
66       FoldingContext &) {
67     if (offset < 0 || offset + bytes > data_.size()) {
68       return OutOfRange;
69     } else {
70       auto optElements{TotalElementCount(x.shape())};
71       if (!optElements) {
72         return TooManyElems;
73       }
74       auto elements{*optElements};
75       auto elementBytes{bytes > 0 ? bytes / elements : 0};
76       if (elements * elementBytes != bytes) {
77         return SizeMismatch;
78       } else if (bytes == 0) {
79         return Ok;
80       } else {
81         Result result{Ok};
82         for (auto at{x.lbounds()}; elements-- > 0; x.IncrementSubscripts(at)) {
83           auto scalar{x.At(at)}; // this is a std string; size() in chars
84           auto scalarBytes{scalar.size() * KIND};
85           if (scalarBytes != elementBytes) {
86             result = LengthMismatch;
87           }
88           // Blank padding when short
89           for (; scalarBytes < elementBytes; scalarBytes += KIND) {
90             scalar += ' ';
91           }
92           // TODO endianness
93           std::memcpy(&data_.at(offset), scalar.data(), elementBytes);
94           offset += elementBytes;
95         }
96         return result;
97       }
98     }
99   }
100   Result Add(ConstantSubscript, std::size_t, const Constant<SomeDerived> &,
101       FoldingContext &);
102   template <typename T>
Add(ConstantSubscript offset,std::size_t bytes,const Expr<T> & x,FoldingContext & c)103   Result Add(ConstantSubscript offset, std::size_t bytes, const Expr<T> &x,
104       FoldingContext &c) {
105     return common::visit(
106         [&](const auto &y) { return Add(offset, bytes, y, c); }, x.u);
107   }
108 
109   void AddPointer(ConstantSubscript, const Expr<SomeType> &);
110 
111   void Incorporate(ConstantSubscript toOffset, const InitialImage &from,
112       ConstantSubscript fromOffset, ConstantSubscript bytes);
113 
114   // Conversions to constant initializers
115   std::optional<Expr<SomeType>> AsConstant(FoldingContext &,
116       const DynamicType &, std::optional<std::int64_t> charLength,
117       const ConstantSubscripts &, bool padWithZero = false,
118       ConstantSubscript offset = 0) const;
119   std::optional<Expr<SomeType>> AsConstantPointer(
120       ConstantSubscript offset = 0) const;
121 
122   friend class AsConstantHelper;
123 
124 private:
125   std::vector<char> data_;
126   std::map<ConstantSubscript, Expr<SomeType>> pointers_;
127 };
128 
129 } // namespace Fortran::evaluate
130 #endif // FORTRAN_EVALUATE_INITIAL_IMAGE_H_
131