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
29namespace Fortran::lower {
30
31struct SymbolBox;
32class SymMap;
33llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const SymbolBox &symMap);
34llvm::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.
52struct 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
133private:
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.
146class SymMap {
147public:
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
318private:
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.

source code of flang/include/flang/Lower/SymbolMap.h