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 
size()34   std::size_t size() const { return data_.size(); }
35 
36   template <typename A>
Add(ConstantSubscript,std::size_t,const A &,FoldingContext &)37   Result Add(ConstantSubscript, std::size_t, const A &, FoldingContext &) {
38     return NotAConstant;
39   }
40   template <typename T>
Add(ConstantSubscript offset,std::size_t bytes,const Constant<T> & x,FoldingContext & context)41   Result Add(ConstantSubscript offset, std::size_t bytes, const Constant<T> &x,
42       FoldingContext &context) {
43     if (offset < 0 || offset + bytes > data_.size()) {
44       return OutOfRange;
45     } else {
46       auto elementBytes{ToInt64(x.GetType().MeasureSizeInBytes(context, true))};
47       if (!elementBytes ||
48           bytes !=
49               x.values().size() * static_cast<std::size_t>(*elementBytes)) {
50         return SizeMismatch;
51       } else {
52         std::memcpy(&data_.at(offset), &x.values().at(0), bytes);
53         return Ok;
54       }
55     }
56   }
57   template <int KIND>
Add(ConstantSubscript offset,std::size_t bytes,const Constant<Type<TypeCategory::Character,KIND>> & x,FoldingContext &)58   Result Add(ConstantSubscript offset, std::size_t bytes,
59       const Constant<Type<TypeCategory::Character, KIND>> &x,
60       FoldingContext &) {
61     if (offset < 0 || offset + bytes > data_.size()) {
62       return OutOfRange;
63     } else {
64       auto elements{TotalElementCount(x.shape())};
65       auto elementBytes{bytes > 0 ? bytes / elements : 0};
66       if (elements * elementBytes != bytes) {
67         return SizeMismatch;
68       } else {
69         for (auto at{x.lbounds()}; elements-- > 0; x.IncrementSubscripts(at)) {
70           auto scalar{x.At(at)}; // this is a std string; size() in chars
71           // Subtle: an initializer for a substring may have been
72           // expanded to the length of the entire string.
73           auto scalarBytes{scalar.size() * KIND};
74           if (scalarBytes < elementBytes ||
75               (scalarBytes > elementBytes && elements != 0)) {
76             return SizeMismatch;
77           }
78           std::memcpy(&data_[offset], scalar.data(), elementBytes);
79           offset += elementBytes;
80         }
81         return Ok;
82       }
83     }
84   }
85   Result Add(ConstantSubscript, std::size_t, const Constant<SomeDerived> &,
86       FoldingContext &);
87   template <typename T>
Add(ConstantSubscript offset,std::size_t bytes,const Expr<T> & x,FoldingContext & c)88   Result Add(ConstantSubscript offset, std::size_t bytes, const Expr<T> &x,
89       FoldingContext &c) {
90     return std::visit(
91         [&](const auto &y) { return Add(offset, bytes, y, c); }, x.u);
92   }
93 
94   void AddPointer(ConstantSubscript, const Expr<SomeType> &);
95 
96   void Incorporate(ConstantSubscript, const InitialImage &);
97 
98   // Conversions to constant initializers
99   std::optional<Expr<SomeType>> AsConstant(FoldingContext &,
100       const DynamicType &, const ConstantSubscripts &,
101       ConstantSubscript offset = 0) const;
102   std::optional<Expr<SomeType>> AsConstantDataPointer(
103       const DynamicType &, ConstantSubscript offset = 0) const;
104   const ProcedureDesignator &AsConstantProcPointer(
105       ConstantSubscript offset = 0) const;
106 
107   friend class AsConstantHelper;
108   friend class AsConstantDataPointerHelper;
109 
110 private:
111   std::vector<char> data_;
112   std::map<ConstantSubscript, Expr<SomeType>> pointers_;
113 };
114 
115 } // namespace Fortran::evaluate
116 #endif // FORTRAN_EVALUATE_INITIAL_IMAGE_H_
117