Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- SymbolMap.h -- lowering internal symbol map -------------*- 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 | // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef FORTRAN_LOWER_SYMBOLMAP_H |
14 | #define FORTRAN_LOWER_SYMBOLMAP_H |
15 | |
16 | #include "flang/Common/reference.h" |
17 | #include "flang/Optimizer/Builder/BoxValue.h" |
18 | #include "flang/Optimizer/Dialect/FIRType.h" |
19 | #include "flang/Optimizer/Dialect/FortranVariableInterface.h" |
20 | #include "flang/Optimizer/Support/Matcher.h" |
21 | #include "flang/Semantics/symbol.h" |
22 | #include "mlir/IR/Value.h" |
23 | #include "llvm/ADT/ArrayRef.h" |
24 | #include "llvm/ADT/DenseMap.h" |
25 | #include "llvm/ADT/SmallVector.h" |
26 | #include "llvm/Support/Compiler.h" |
27 | #include <optional> |
28 | |
29 | namespace Fortran::lower { |
30 | |
31 | struct SymbolBox; |
32 | class SymMap; |
33 | llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const SymbolBox &symMap); |
34 | llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const SymMap &symMap); |
35 | |
36 | //===----------------------------------------------------------------------===// |
37 | // Symbol information |
38 | //===----------------------------------------------------------------------===// |
39 | |
40 | /// A dictionary entry of ssa-values that together compose a variable referenced |
41 | /// by a Symbol. For example, the declaration |
42 | /// |
43 | /// CHARACTER(LEN=i) :: c(j1,j2) |
44 | /// |
45 | /// is a single variable `c`. This variable is a two-dimensional array of |
46 | /// CHARACTER. It has a starting address and three dynamic properties: the LEN |
47 | /// parameter `i` a runtime value describing the length of the CHARACTER, and |
48 | /// the `j1` and `j2` runtime values, which describe the shape of the array. |
49 | /// |
50 | /// The lowering bridge needs to be able to record all four of these ssa-values |
51 | /// in the lookup table to be able to correctly lower Fortran to FIR. |
52 | struct SymbolBox : public fir::details::matcher<SymbolBox> { |
53 | // For lookups that fail, have a monostate |
54 | using None = std::monostate; |
55 | |
56 | // Trivial intrinsic type |
57 | using Intrinsic = fir::AbstractBox; |
58 | |
59 | // Array variable that uses bounds notation |
60 | using FullDim = fir::ArrayBoxValue; |
61 | |
62 | // CHARACTER type variable with its dependent type LEN parameter |
63 | using Char = fir::CharBoxValue; |
64 | |
65 | // CHARACTER array variable using bounds notation |
66 | using CharFullDim = fir::CharArrayBoxValue; |
67 | |
68 | // Pointer or allocatable variable |
69 | using PointerOrAllocatable = fir::MutableBoxValue; |
70 | |
71 | // Non pointer/allocatable variable that must be tracked with |
72 | // a fir.box (either because it is not contiguous, or assumed rank, or assumed |
73 | // type, or polymorphic, or because the fir.box is describing an optional |
74 | // value and cannot be read into one of the other category when lowering the |
75 | // symbol). |
76 | using Box = fir::BoxValue; |
77 | |
78 | using VT = |
79 | std::variant<Intrinsic, FullDim, Char, CharFullDim, PointerOrAllocatable, |
80 | Box, fir::FortranVariableOpInterface, None>; |
81 | |
82 | //===--------------------------------------------------------------------===// |
83 | // Constructors |
84 | //===--------------------------------------------------------------------===// |
85 | |
86 | SymbolBox() : box{None{}} {} |
87 | template <typename A> |
88 | SymbolBox(const A &x) : box{x} {} |
89 | |
90 | explicit operator bool() const { return !std::holds_alternative<None>(box); } |
91 | |
92 | //===--------------------------------------------------------------------===// |
93 | // Accessors |
94 | //===--------------------------------------------------------------------===// |
95 | |
96 | /// Get address of the boxed value. For a scalar, this is the address of the |
97 | /// scalar. For an array, this is the address of the first element in the |
98 | /// array, etc. |
99 | mlir::Value getAddr() const { |
100 | return match([](const None &) { return mlir::Value{}; }, |
101 | [](const fir::FortranVariableOpInterface &x) { |
102 | return fir::FortranVariableOpInterface(x).getBase(); |
103 | }, |
104 | [](const auto &x) { return x.getAddr(); }); |
105 | } |
106 | |
107 | std::optional<fir::FortranVariableOpInterface> |
108 | getIfFortranVariableOpInterface() { |
109 | return match( |
110 | [](const fir::FortranVariableOpInterface &x) |
111 | -> std::optional<fir::FortranVariableOpInterface> { return x; }, |
112 | [](const auto &x) -> std::optional<fir::FortranVariableOpInterface> { |
113 | return std::nullopt; |
114 | }); |
115 | } |
116 | |
117 | /// Apply the lambda `func` to this box value. |
118 | template <typename ON, typename RT> |
119 | constexpr RT apply(RT (&&func)(const ON &)) const { |
120 | if (auto *x = std::get_if<ON>(&box)) |
121 | return func(*x); |
122 | return RT{}; |
123 | } |
124 | |
125 | const VT &matchee() const { return box; } |
126 | |
127 | friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, |
128 | const SymbolBox &symBox); |
129 | |
130 | /// Dump the map. For debugging. |
131 | LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this << '\n'; } |
132 | |
133 | private: |
134 | VT box; |
135 | }; |
136 | |
137 | //===----------------------------------------------------------------------===// |
138 | // Map of symbol information |
139 | //===----------------------------------------------------------------------===// |
140 | |
141 | /// Helper class to map front-end symbols to their MLIR representation. This |
142 | /// provides a way to lookup the ssa-values that comprise a Fortran symbol's |
143 | /// runtime attributes. These attributes include its address, its dynamic size, |
144 | /// dynamic bounds information for non-scalar entities, dynamic type parameters, |
145 | /// etc. |
146 | class SymMap { |
147 | public: |
148 | using AcDoVar = llvm::StringRef; |
149 | |
150 | SymMap() { pushScope(); } |
151 | SymMap(const SymMap &) = delete; |
152 | |
153 | void pushScope() { symbolMapStack.emplace_back(); } |
154 | void popScope() { |
155 | symbolMapStack.pop_back(); |
156 | assert(symbolMapStack.size() >= 1); |
157 | } |
158 | |
159 | /// Add an extended value to the symbol table. |
160 | void addSymbol(semantics::SymbolRef sym, const fir::ExtendedValue &ext, |
161 | bool force = false); |
162 | |
163 | /// Add a trivial symbol mapping to an address. |
164 | void addSymbol(semantics::SymbolRef sym, mlir::Value value, |
165 | bool force = false) { |
166 | makeSym(sym, SymbolBox::Intrinsic(value), force); |
167 | } |
168 | |
169 | /// Add a scalar CHARACTER mapping to an (address, len). |
170 | void addCharSymbol(semantics::SymbolRef sym, mlir::Value value, |
171 | mlir::Value len, bool force = false) { |
172 | makeSym(sym, SymbolBox::Char(value, len), force); |
173 | } |
174 | void addCharSymbol(semantics::SymbolRef sym, const SymbolBox::Char &value, |
175 | bool force = false) { |
176 | makeSym(sym, value, force); |
177 | } |
178 | |
179 | /// Add an array mapping with (address, shape). |
180 | void addSymbolWithShape(semantics::SymbolRef sym, mlir::Value value, |
181 | llvm::ArrayRef<mlir::Value> shape, |
182 | bool force = false) { |
183 | makeSym(sym, SymbolBox::FullDim(value, shape), force); |
184 | } |
185 | void addSymbolWithShape(semantics::SymbolRef sym, |
186 | const SymbolBox::FullDim &value, bool force = false) { |
187 | makeSym(sym, value, force); |
188 | } |
189 | |
190 | /// Add an array of CHARACTER mapping. |
191 | void addCharSymbolWithShape(semantics::SymbolRef sym, mlir::Value value, |
192 | mlir::Value len, |
193 | llvm::ArrayRef<mlir::Value> shape, |
194 | bool force = false) { |
195 | makeSym(sym, SymbolBox::CharFullDim(value, len, shape), force); |
196 | } |
197 | void addCharSymbolWithShape(semantics::SymbolRef sym, |
198 | const SymbolBox::CharFullDim &value, |
199 | bool force = false) { |
200 | makeSym(sym, value, force); |
201 | } |
202 | |
203 | /// Add an array mapping with bounds notation. |
204 | void addSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value, |
205 | llvm::ArrayRef<mlir::Value> extents, |
206 | llvm::ArrayRef<mlir::Value> lbounds, |
207 | bool force = false) { |
208 | makeSym(sym, SymbolBox::FullDim(value, extents, lbounds), force); |
209 | } |
210 | void addSymbolWithBounds(semantics::SymbolRef sym, |
211 | const SymbolBox::FullDim &value, |
212 | bool force = false) { |
213 | makeSym(sym, value, force); |
214 | } |
215 | |
216 | /// Add an array of CHARACTER with bounds notation. |
217 | void addCharSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value, |
218 | mlir::Value len, |
219 | llvm::ArrayRef<mlir::Value> extents, |
220 | llvm::ArrayRef<mlir::Value> lbounds, |
221 | bool force = false) { |
222 | makeSym(sym, SymbolBox::CharFullDim(value, len, extents, lbounds), force); |
223 | } |
224 | void addCharSymbolWithBounds(semantics::SymbolRef sym, |
225 | const SymbolBox::CharFullDim &value, |
226 | bool force = false) { |
227 | makeSym(sym, value, force); |
228 | } |
229 | |
230 | void addAllocatableOrPointer(semantics::SymbolRef sym, |
231 | fir::MutableBoxValue box, bool force = false) { |
232 | makeSym(sym, box, force); |
233 | } |
234 | |
235 | void addBoxSymbol(semantics::SymbolRef sym, mlir::Value irBox, |
236 | llvm::ArrayRef<mlir::Value> lbounds, |
237 | llvm::ArrayRef<mlir::Value> explicitParams, |
238 | llvm::ArrayRef<mlir::Value> explicitExtents, |
239 | bool force = false) { |
240 | makeSym(sym, |
241 | SymbolBox::Box(irBox, lbounds, explicitParams, explicitExtents), |
242 | force); |
243 | } |
244 | void addBoxSymbol(semantics::SymbolRef sym, const SymbolBox::Box &value, |
245 | bool force = false) { |
246 | makeSym(sym, value, force); |
247 | } |
248 | |
249 | /// Find `symbol` and return its value if it appears in the current mappings. |
250 | SymbolBox lookupSymbol(semantics::SymbolRef sym); |
251 | SymbolBox lookupSymbol(const semantics::Symbol *sym) { |
252 | return lookupSymbol(*sym); |
253 | } |
254 | |
255 | /// Find `symbol` and return its value if it appears in the inner-most level |
256 | /// map. |
257 | SymbolBox shallowLookupSymbol(semantics::SymbolRef sym); |
258 | SymbolBox shallowLookupSymbol(const semantics::Symbol *sym) { |
259 | return shallowLookupSymbol(*sym); |
260 | } |
261 | |
262 | /// Find `symbol` and return its value if it appears in the one level up map |
263 | /// such as for the host variable in host-association in OpenMP code. |
264 | SymbolBox lookupOneLevelUpSymbol(semantics::SymbolRef sym); |
265 | SymbolBox lookupOneLevelUpSymbol(const semantics::Symbol *sym) { |
266 | return lookupOneLevelUpSymbol(*sym); |
267 | } |
268 | |
269 | /// Add a new binding from the ac-do-variable `var` to `value`. |
270 | void pushImpliedDoBinding(AcDoVar var, mlir::Value value) { |
271 | impliedDoStack.emplace_back(var, value); |
272 | } |
273 | |
274 | /// Pop the most recent implied do binding off the stack. |
275 | void popImpliedDoBinding() { |
276 | assert(!impliedDoStack.empty()); |
277 | impliedDoStack.pop_back(); |
278 | } |
279 | |
280 | /// Lookup the ac-do-variable and return the Value it is bound to. |
281 | /// If the variable is not found, returns a null Value. |
282 | mlir::Value lookupImpliedDo(AcDoVar var); |
283 | |
284 | /// Remove all symbols from the map. |
285 | void clear() { |
286 | symbolMapStack.clear(); |
287 | symbolMapStack.emplace_back(); |
288 | assert(symbolMapStack.size() == 1); |
289 | impliedDoStack.clear(); |
290 | } |
291 | |
292 | friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, |
293 | const SymMap &symMap); |
294 | |
295 | /// Dump the map. For debugging. |
296 | LLVM_DUMP_METHOD void dump() const { llvm::errs() << *this << '\n'; } |
297 | |
298 | void addVariableDefinition(semantics::SymbolRef symRef, |
299 | fir::FortranVariableOpInterface definingOp, |
300 | bool force = false) { |
301 | makeSym(symRef, SymbolBox(definingOp), force); |
302 | } |
303 | |
304 | void copySymbolBinding(semantics::SymbolRef src, |
305 | semantics::SymbolRef target) { |
306 | auto symBox = lookupSymbol(src); |
307 | assert(symBox && "source binding does not exists"); |
308 | makeSym(target, symBox, /*force=*/false); |
309 | } |
310 | |
311 | std::optional<fir::FortranVariableOpInterface> |
312 | lookupVariableDefinition(semantics::SymbolRef sym) { |
313 | if (auto symBox = lookupSymbol(sym)) |
314 | return symBox.getIfFortranVariableOpInterface(); |
315 | return std::nullopt; |
316 | } |
317 | |
318 | private: |
319 | /// Bind `box` to `symRef` in the symbol map. |
320 | void makeSym(semantics::SymbolRef symRef, const SymbolBox &box, |
321 | bool force = false) { |
322 | auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate(); |
323 | if (force) |
324 | symbolMapStack.back().erase(sym); |
325 | assert(box && "cannot add an undefined symbol box"); |
326 | symbolMapStack.back().try_emplace(sym, box); |
327 | } |
328 | |
329 | llvm::SmallVector<llvm::DenseMap<const semantics::Symbol *, SymbolBox>> |
330 | symbolMapStack; |
331 | |
332 | // Implied DO induction variables are not represented as Se::Symbol in |
333 | // Ev::Expr. Keep the variable markers in their own stack. |
334 | llvm::SmallVector<std::pair<AcDoVar, mlir::Value>> impliedDoStack; |
335 | }; |
336 | |
337 | } // namespace Fortran::lower |
338 | |
339 | #endif // FORTRAN_LOWER_SYMBOLMAP_H |
340 |
Warning: This file is not a C or C++ file. It does not have highlighting.