Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- include/flang/Evaluate/fold-designator.h ----------------*- C++ -*-===// |
---|---|
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_FOLD_DESIGNATOR_H_ |
10 | #define FORTRAN_EVALUATE_FOLD_DESIGNATOR_H_ |
11 | |
12 | // Resolves a designator at compilation time to a base symbol, a byte offset |
13 | // from that symbol, and a byte size. Also resolves in the reverse direction, |
14 | // reconstructing a designator from a symbol, byte offset, and size. |
15 | // Used for resolving variables in DATA statements to ranges in their |
16 | // initial images. |
17 | // Some designators can also be folded into constant pointer descriptors, |
18 | // which also have per-dimension extent and stride information suitable |
19 | // for initializing a descriptor. |
20 | // (The designators that cannot be folded are those with vector-valued |
21 | // subscripts; they are allowed as DATA statement objects, but are not valid |
22 | // initial pointer targets.) |
23 | |
24 | #include "common.h" |
25 | #include "expression.h" |
26 | #include "fold.h" |
27 | #include "shape.h" |
28 | #include "type.h" |
29 | #include "variable.h" |
30 | #include <optional> |
31 | #include <variant> |
32 | |
33 | namespace Fortran::evaluate { |
34 | |
35 | using common::ConstantSubscript; |
36 | |
37 | // Identifies a single contiguous interval of bytes at a fixed offset |
38 | // from a known symbol. |
39 | class OffsetSymbol { |
40 | public: |
41 | OffsetSymbol(const Symbol &symbol, std::size_t bytes) |
42 | : symbol_{symbol}, size_{bytes} {} |
43 | DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(OffsetSymbol) |
44 | |
45 | const Symbol &symbol() const { return *symbol_; } |
46 | void set_symbol(const Symbol &symbol) { symbol_ = symbol; }; |
47 | ConstantSubscript offset() const { return offset_; } |
48 | void Augment(ConstantSubscript n) { offset_ += n; } |
49 | std::size_t size() const { return size_; } |
50 | void set_size(std::size_t bytes) { size_ = bytes; } |
51 | |
52 | private: |
53 | SymbolRef symbol_; |
54 | ConstantSubscript offset_{0}; |
55 | std::size_t size_; |
56 | }; |
57 | |
58 | // Folds a Designator<T> into a sequence of OffsetSymbols, if it can |
59 | // be so folded. Array sections yield multiple results, each |
60 | // corresponding to an element in array element order. |
61 | class DesignatorFolder { |
62 | public: |
63 | explicit DesignatorFolder(FoldingContext &c, bool getLastComponent = false) |
64 | : context_{c}, getLastComponent_{getLastComponent} {} |
65 | |
66 | bool isEmpty() const { return isEmpty_; } |
67 | bool isOutOfRange() const { return isOutOfRange_; } |
68 | |
69 | template <typename T> |
70 | std::optional<OffsetSymbol> FoldDesignator(const Expr<T> &expr) { |
71 | return common::visit( |
72 | [&](const auto &x) { return FoldDesignator(x, elementNumber_++); }, |
73 | expr.u); |
74 | } |
75 | |
76 | private: |
77 | std::optional<OffsetSymbol> FoldDesignator(const Symbol &, ConstantSubscript); |
78 | std::optional<OffsetSymbol> FoldDesignator( |
79 | const SymbolRef &x, ConstantSubscript which) { |
80 | return FoldDesignator(*x, which); |
81 | } |
82 | std::optional<OffsetSymbol> FoldDesignator( |
83 | const ArrayRef &, ConstantSubscript); |
84 | std::optional<OffsetSymbol> FoldDesignator( |
85 | const Component &, ConstantSubscript); |
86 | std::optional<OffsetSymbol> FoldDesignator( |
87 | const ComplexPart &, ConstantSubscript); |
88 | std::optional<OffsetSymbol> FoldDesignator( |
89 | const Substring &, ConstantSubscript); |
90 | std::optional<OffsetSymbol> FoldDesignator( |
91 | const DataRef &, ConstantSubscript); |
92 | std::optional<OffsetSymbol> FoldDesignator( |
93 | const NamedEntity &, ConstantSubscript); |
94 | std::optional<OffsetSymbol> FoldDesignator( |
95 | const CoarrayRef &, ConstantSubscript); |
96 | std::optional<OffsetSymbol> FoldDesignator( |
97 | const ProcedureDesignator &, ConstantSubscript); |
98 | |
99 | template <typename T> |
100 | std::optional<OffsetSymbol> FoldDesignator( |
101 | const Expr<T> &expr, ConstantSubscript which) { |
102 | return common::visit( |
103 | [&](const auto &x) { return FoldDesignator(x, which); }, expr.u); |
104 | } |
105 | |
106 | template <typename A> |
107 | std::optional<OffsetSymbol> FoldDesignator(const A &, ConstantSubscript) { |
108 | return std::nullopt; |
109 | } |
110 | |
111 | template <typename T> |
112 | std::optional<OffsetSymbol> FoldDesignator( |
113 | const Designator<T> &designator, ConstantSubscript which) { |
114 | return common::visit( |
115 | [&](const auto &x) { return FoldDesignator(x, which); }, designator.u); |
116 | } |
117 | template <int KIND> |
118 | std::optional<OffsetSymbol> FoldDesignator( |
119 | const Designator<Type<TypeCategory::Character, KIND>> &designator, |
120 | ConstantSubscript which) { |
121 | return common::visit( |
122 | common::visitors{ |
123 | [&](const Substring &ss) { |
124 | if (const auto *dataRef{ss.GetParentIf<DataRef>()}) { |
125 | if (auto result{FoldDesignator(*dataRef, which)}) { |
126 | if (auto start{ToInt64(ss.lower())}) { |
127 | std::optional<ConstantSubscript> end; |
128 | auto len{dataRef->LEN()}; |
129 | if (ss.upper()) { |
130 | end = ToInt64(*ss.upper()); |
131 | } else if (len) { |
132 | end = ToInt64(*len); |
133 | } |
134 | if (end) { |
135 | if (*start < 1) { |
136 | isOutOfRange_ = true; |
137 | } |
138 | result->Augment(KIND * (*start - 1)); |
139 | result->set_size( |
140 | *end >= *start ? KIND * (*end - *start + 1) : 0); |
141 | if (len) { |
142 | if (auto lenVal{ToInt64(*len)}) { |
143 | if (*end > *lenVal) { |
144 | isOutOfRange_ = true; |
145 | } |
146 | } |
147 | } |
148 | return result; |
149 | } |
150 | } |
151 | } |
152 | } |
153 | return std::optional<OffsetSymbol>{}; |
154 | }, |
155 | [&](const auto &x) { return FoldDesignator(x, which); }, |
156 | }, |
157 | designator.u); |
158 | } |
159 | |
160 | FoldingContext &context_; |
161 | bool getLastComponent_{false}; |
162 | ConstantSubscript elementNumber_{0}; // zero-based |
163 | bool isEmpty_{false}; |
164 | bool isOutOfRange_{false}; |
165 | }; |
166 | |
167 | // Reconstructs a Designator<> from a symbol and an offset. |
168 | std::optional<Expr<SomeType>> OffsetToDesignator( |
169 | FoldingContext &, const Symbol &, ConstantSubscript offset, std::size_t); |
170 | std::optional<Expr<SomeType>> OffsetToDesignator( |
171 | FoldingContext &, const OffsetSymbol &); |
172 | |
173 | // Represents a compile-time constant Descriptor suitable for use |
174 | // as a pointer initializer. Lower bounds are always 1. |
175 | struct ConstantObjectPointer : public OffsetSymbol { |
176 | struct Dimension { |
177 | ConstantSubscript byteStride; |
178 | ConstantSubscript extent; |
179 | }; |
180 | using Dimensions = std::vector<Dimension>; |
181 | |
182 | ConstantObjectPointer( |
183 | const Symbol &symbol, std::size_t size, Dimensions &&dims) |
184 | : OffsetSymbol{symbol, size}, dimensions{std::move(dims)} {} |
185 | |
186 | // Folds a designator to a constant pointer. Crashes on failure. |
187 | // Use IsInitialDataTarget() to validate the expression beforehand. |
188 | static ConstantObjectPointer From(FoldingContext &, const Expr<SomeType> &); |
189 | |
190 | Dimensions dimensions; |
191 | }; |
192 | |
193 | } // namespace Fortran::evaluate |
194 | #endif // FORTRAN_EVALUATE_FOLD_DESIGNATOR_H_ |
195 |
Warning: This file is not a C or C++ file. It does not have highlighting.