FLANG
SymbolMap.h
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/Lower/Support/Utils.h"
18#include "flang/Optimizer/Builder/BoxValue.h"
19#include "flang/Optimizer/Dialect/FIRType.h"
20#include "flang/Optimizer/Dialect/FortranVariableInterface.h"
21#include "flang/Optimizer/Support/Matcher.h"
22#include "flang/Semantics/symbol.h"
23#include "mlir/IR/Value.h"
24#include "llvm/ADT/ArrayRef.h"
25#include "llvm/ADT/DenseMap.h"
26#include "llvm/ADT/SmallVector.h"
27#include "llvm/Support/Compiler.h"
28#include <optional>
29
30namespace Fortran::lower {
31
32struct SymbolBox;
33class SymMap;
34llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const SymbolBox &symMap);
35llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const SymMap &symMap);
36
37//===----------------------------------------------------------------------===//
38// Symbol information
39//===----------------------------------------------------------------------===//
40
53struct SymbolBox : public fir::details::matcher<SymbolBox> {
54 // For lookups that fail, have a monostate
55 using None = std::monostate;
56
57 // Trivial intrinsic type
58 using Intrinsic = fir::AbstractBox;
59
60 // Array variable that uses bounds notation
61 using FullDim = fir::ArrayBoxValue;
62
63 // CHARACTER type variable with its dependent type LEN parameter
64 using Char = fir::CharBoxValue;
65
66 // CHARACTER array variable using bounds notation
67 using CharFullDim = fir::CharArrayBoxValue;
68
69 // Pointer or allocatable variable
70 using PointerOrAllocatable = fir::MutableBoxValue;
71
72 // Non pointer/allocatable variable that must be tracked with
73 // a fir.box (either because it is not contiguous, or assumed rank, or assumed
74 // type, or polymorphic, or because the fir.box is describing an optional
75 // value and cannot be read into one of the other category when lowering the
76 // symbol).
77 using Box = fir::BoxValue;
78
79 using VT =
80 std::variant<Intrinsic, FullDim, Char, CharFullDim, PointerOrAllocatable,
81 Box, fir::FortranVariableOpInterface, None>;
82
83 //===--------------------------------------------------------------------===//
84 // Constructors
85 //===--------------------------------------------------------------------===//
86
87 SymbolBox() : box{None{}} {}
88 template <typename A>
89 SymbolBox(const A &x) : box{x} {}
90
91 explicit operator bool() const { return !std::holds_alternative<None>(box); }
92
93 //===--------------------------------------------------------------------===//
94 // Accessors
95 //===--------------------------------------------------------------------===//
96
100 mlir::Value getAddr() const {
101 return match([](const None &) { return mlir::Value{}; },
102 [](const fir::FortranVariableOpInterface &x) {
103 return fir::FortranVariableOpInterface(x).getBase();
104 },
105 [](const auto &x) { return x.getAddr(); });
106 }
107
108 std::optional<fir::FortranVariableOpInterface>
109 getIfFortranVariableOpInterface() {
110 return match(
111 [](const fir::FortranVariableOpInterface &x)
112 -> std::optional<fir::FortranVariableOpInterface> { return x; },
113 [](const auto &x) -> std::optional<fir::FortranVariableOpInterface> {
114 return std::nullopt;
115 });
116 }
117
119 template <typename ON, typename RT>
120 constexpr RT apply(RT (&&func)(const ON &)) const {
121 if (auto *x = std::get_if<ON>(&box))
122 return func(*x);
123 return RT{};
124 }
125
126 const VT &matchee() const { return box; }
127
128 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
129 const SymbolBox &symBox);
130
132 LLVM_DUMP_METHOD void dump() const;
133
134private:
135 VT box;
136};
137
142public:
143 void insert(const Fortran::evaluate::Component &component,
144 fir::FortranVariableOpInterface definingOp) {
145 auto iter = componentMap.find(&component);
146 if (iter != componentMap.end()) {
147 iter->second = definingOp;
148 return;
149 }
150 componentStorage.push_back(
151 std::make_unique<Fortran::evaluate::Component>(component));
152 componentMap.insert({componentStorage.back().get(), definingOp});
153 }
154
155 std::optional<fir::FortranVariableOpInterface>
156 lookup(const Fortran::evaluate::Component *component) const {
157 auto iter = componentMap.find(component);
158 if (iter != componentMap.end())
159 return iter->second;
160 return std::nullopt;
161 }
162
163 LLVM_DUMP_METHOD void dump() const;
164
165private:
166 llvm::DenseMap<const Fortran::evaluate::Component *,
167 fir::FortranVariableOpInterface>
168 componentMap;
170 componentStorage;
171};
172
173//===----------------------------------------------------------------------===//
174// Map of symbol information
175//===----------------------------------------------------------------------===//
176
182class SymMap {
183public:
184 using AcDoVar = llvm::StringRef;
187 using StorageDesc = std::pair<mlir::Value, std::uint64_t>;
188
189 SymMap() { pushScope(); }
190 SymMap(const SymMap &) = delete;
191
192 void pushScope() {
193 symbolMapStack.emplace_back();
194 storageMapStack.emplace_back();
195 componentMapStack.emplace_back();
196 }
197 void popScope() {
198 symbolMapStack.pop_back();
199 assert(symbolMapStack.size() >= 1);
200 storageMapStack.pop_back();
201 assert(storageMapStack.size() >= 1);
202 componentMapStack.pop_back();
203 assert(componentMapStack.size() >= 1);
204 }
205
207 void addSymbol(semantics::SymbolRef sym, const fir::ExtendedValue &ext,
208 bool force = false);
209
211 void addSymbol(semantics::SymbolRef sym, mlir::Value value,
212 bool force = false) {
213 makeSym(sym, SymbolBox::Intrinsic(value), force);
214 }
215
217 void addCharSymbol(semantics::SymbolRef sym, mlir::Value value,
218 mlir::Value len, bool force = false) {
219 makeSym(sym, SymbolBox::Char(value, len), force);
220 }
221 void addCharSymbol(semantics::SymbolRef sym, const SymbolBox::Char &value,
222 bool force = false) {
223 makeSym(sym, value, force);
224 }
225
227 void addSymbolWithShape(semantics::SymbolRef sym, mlir::Value value,
229 bool force = false) {
230 makeSym(sym, SymbolBox::FullDim(value, shape), force);
231 }
232 void addSymbolWithShape(semantics::SymbolRef sym,
233 const SymbolBox::FullDim &value, bool force = false) {
234 makeSym(sym, value, force);
235 }
236
238 void addCharSymbolWithShape(semantics::SymbolRef sym, mlir::Value value,
239 mlir::Value len,
241 bool force = false) {
242 makeSym(sym, SymbolBox::CharFullDim(value, len, shape), force);
243 }
244 void addCharSymbolWithShape(semantics::SymbolRef sym,
245 const SymbolBox::CharFullDim &value,
246 bool force = false) {
247 makeSym(sym, value, force);
248 }
249
251 void addSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value,
254 bool force = false) {
255 makeSym(sym, SymbolBox::FullDim(value, extents, lbounds), force);
256 }
257 void addSymbolWithBounds(semantics::SymbolRef sym,
258 const SymbolBox::FullDim &value,
259 bool force = false) {
260 makeSym(sym, value, force);
261 }
262
264 void addCharSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value,
265 mlir::Value len,
268 bool force = false) {
269 makeSym(sym, SymbolBox::CharFullDim(value, len, extents, lbounds), force);
270 }
271 void addCharSymbolWithBounds(semantics::SymbolRef sym,
272 const SymbolBox::CharFullDim &value,
273 bool force = false) {
274 makeSym(sym, value, force);
275 }
276
277 void addAllocatableOrPointer(semantics::SymbolRef sym,
278 fir::MutableBoxValue box, bool force = false) {
279 makeSym(sym, box, force);
280 }
281
282 void addBoxSymbol(semantics::SymbolRef sym, mlir::Value irBox,
284 llvm::ArrayRef<mlir::Value> explicitParams,
285 llvm::ArrayRef<mlir::Value> explicitExtents,
286 bool force = false) {
287 makeSym(sym,
288 SymbolBox::Box(irBox, lbounds, explicitParams, explicitExtents),
289 force);
290 }
291 void addBoxSymbol(semantics::SymbolRef sym, const SymbolBox::Box &value,
292 bool force = false) {
293 makeSym(sym, value, force);
294 }
295
297 SymbolBox lookupSymbol(semantics::SymbolRef sym);
298 SymbolBox lookupSymbol(const semantics::Symbol *sym) {
299 return lookupSymbol(*sym);
300 }
301
304 const semantics::Symbol *lookupSymbolByName(llvm::StringRef symName);
305
308 SymbolBox shallowLookupSymbol(semantics::SymbolRef sym);
309 SymbolBox shallowLookupSymbol(const semantics::Symbol *sym) {
310 return shallowLookupSymbol(*sym);
311 }
312
315 SymbolBox lookupOneLevelUpSymbol(semantics::SymbolRef sym);
316 SymbolBox lookupOneLevelUpSymbol(const semantics::Symbol *sym) {
317 return lookupOneLevelUpSymbol(*sym);
318 }
319
321 void pushImpliedDoBinding(AcDoVar var, mlir::Value value) {
322 impliedDoStack.emplace_back(var, value);
323 }
324
327 assert(!impliedDoStack.empty());
328 impliedDoStack.pop_back();
329 }
330
333 mlir::Value lookupImpliedDo(AcDoVar var);
334
336 void clear() {
337 symbolMapStack.clear();
338 symbolMapStack.emplace_back();
339 assert(symbolMapStack.size() == 1);
340 impliedDoStack.clear();
341 storageMapStack.clear();
342 storageMapStack.emplace_back();
343 componentMapStack.clear();
344 componentMapStack.emplace_back();
345 }
346
347 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
348 const SymMap &symMap);
349
351 LLVM_DUMP_METHOD void dump() const;
352
353 void addVariableDefinition(semantics::SymbolRef symRef,
354 fir::FortranVariableOpInterface definingOp,
355 bool force = false) {
356 makeSym(symRef, SymbolBox(definingOp), force);
357 }
358
359 void copySymbolBinding(semantics::SymbolRef src,
360 semantics::SymbolRef target) {
361 auto symBox = lookupSymbol(src);
362 assert(symBox && "source binding does not exists");
363 makeSym(target, symBox, /*force=*/false);
364 }
365
366 std::optional<fir::FortranVariableOpInterface>
367 lookupVariableDefinition(semantics::SymbolRef sym) {
368 if (auto symBox = lookupSymbol(sym))
369 return symBox.getIfFortranVariableOpInterface();
370 return std::nullopt;
371 }
372
377 fir::FortranVariableOpInterface definingOp) {
378 assert(!componentMapStack.empty() && "component map stack is empty");
379 if (!componentMapStack.back())
380 componentMapStack.back() = std::make_unique<ComponentMap>();
381 componentMapStack.back().value()->insert(component, definingOp);
382 }
383
386 std::optional<fir::FortranVariableOpInterface>
388 for (auto jmap = componentMapStack.rbegin(),
389 jend = componentMapStack.rend();
390 jmap != jend; ++jmap) {
391 if (*jmap) {
392 auto iter = (**jmap)->lookup(&component);
393 if (iter != std::nullopt)
394 return iter;
395 }
396 }
397 return std::nullopt;
398 }
399
403 void registerStorage(semantics::SymbolRef sym, StorageDesc storage);
405 StorageDesc lookupStorage(semantics::SymbolRef sym);
407 return lookupStorage(*sym);
408 }
409
410private:
412 void makeSym(semantics::SymbolRef symRef, const SymbolBox &box,
413 bool force = false) {
414 auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate();
415 if (force)
416 symbolMapStack.back().erase(sym);
417 assert(box && "cannot add an undefined symbol box");
418 symbolMapStack.back().try_emplace(sym, box);
419 }
420
422 symbolMapStack;
423
424 // Implied DO induction variables are not represented as Se::Symbol in
425 // Ev::Expr. Keep the variable markers in their own stack.
427
428 // A stack of maps between the symbols and their storage descriptors.
430 storageMapStack;
431
432 // A stack of maps from front-end component references to the FIR variables
433 // that should be used to implement them. This allows overriding component
434 // references in specific lowering contexts.
436 componentMapStack;
437};
438
440class SymMapScope {
441public:
442 explicit SymMapScope(SymMap &map) : map(map) { map.pushScope(); }
443 ~SymMapScope() { map.popScope(); }
444
445private:
446 SymMap &map;
447};
448
449} // namespace Fortran::lower
450
451#endif // FORTRAN_LOWER_SYMBOLMAP_H
Definition variable.h:73
Definition SymbolMap.h:141
Definition SymbolMap.h:182
void addSymbolWithShape(semantics::SymbolRef sym, mlir::Value value, llvm::ArrayRef< mlir::Value > shape, bool force=false)
Add an array mapping with (address, shape).
Definition SymbolMap.h:227
void addComponentOverride(const Fortran::evaluate::Component &component, fir::FortranVariableOpInterface definingOp)
Definition SymbolMap.h:376
void pushImpliedDoBinding(AcDoVar var, mlir::Value value)
Add a new binding from the ac-do-variable var to value.
Definition SymbolMap.h:321
SymbolBox lookupSymbol(semantics::SymbolRef sym)
Find symbol and return its value if it appears in the current mappings.
Definition SymbolMap.cpp:37
void addSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value, llvm::ArrayRef< mlir::Value > extents, llvm::ArrayRef< mlir::Value > lbounds, bool force=false)
Add an array mapping with bounds notation.
Definition SymbolMap.h:251
mlir::Value lookupImpliedDo(AcDoVar var)
Definition SymbolMap.cpp:88
void addCharSymbolWithShape(semantics::SymbolRef sym, mlir::Value value, mlir::Value len, llvm::ArrayRef< mlir::Value > shape, bool force=false)
Add an array of CHARACTER mapping.
Definition SymbolMap.h:238
void popImpliedDoBinding()
Pop the most recent implied do binding off the stack.
Definition SymbolMap.h:326
void addSymbol(semantics::SymbolRef sym, mlir::Value value, bool force=false)
Add a trivial symbol mapping to an address.
Definition SymbolMap.h:211
std::pair< mlir::Value, std::uint64_t > StorageDesc
Definition SymbolMap.h:187
std::optional< fir::FortranVariableOpInterface > lookupComponentOverride(const Fortran::evaluate::Component &component) const
Definition SymbolMap.h:387
void addCharSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value, mlir::Value len, llvm::ArrayRef< mlir::Value > extents, llvm::ArrayRef< mlir::Value > lbounds, bool force=false)
Add an array of CHARACTER with bounds notation.
Definition SymbolMap.h:264
void registerStorage(semantics::SymbolRef sym, StorageDesc storage)
Definition SymbolMap.cpp:95
void clear()
Remove all symbols from the map.
Definition SymbolMap.h:336
SymbolBox lookupOneLevelUpSymbol(semantics::SymbolRef sym)
Definition SymbolMap.cpp:71
void addSymbol(semantics::SymbolRef sym, const fir::ExtendedValue &ext, bool force=false)
Add an extended value to the symbol table.
Definition SymbolMap.cpp:21
void addCharSymbol(semantics::SymbolRef sym, mlir::Value value, mlir::Value len, bool force=false)
Add a scalar CHARACTER mapping to an (address, len).
Definition SymbolMap.h:217
SymbolBox shallowLookupSymbol(semantics::SymbolRef sym)
Definition SymbolMap.cpp:58
StorageDesc lookupStorage(semantics::SymbolRef sym)
Lookup the symbol's storage at the innermost level of the symbol table.
Definition SymbolMap.cpp:103
LLVM_DUMP_METHOD void dump() const
Dump the map. For debugging.
Definition SymbolMap.cpp:124
const semantics::Symbol * lookupSymbolByName(llvm::StringRef symName)
Definition SymbolMap.cpp:49
Definition symbol.h:809
Abstract base class.
Definition BoxValue.h:61
Definition BoxValue.h:153
Definition BoxValue.h:291
Expressions of type CHARACTER and with rank > 0.
Definition BoxValue.h:170
Definition BoxValue.h:77
Definition BoxValue.h:478
Definition BoxValue.h:360
Definition FIRType.h:92
Definition OpenACC.h:20
Definition ParserActions.h:24
Definition SymbolMap.h:53
mlir::Value getAddr() const
Definition SymbolMap.h:100
constexpr RT apply(RT(&&func)(const ON &)) const
Apply the lambda func to this box value.
Definition SymbolMap.h:120
LLVM_DUMP_METHOD void dump() const
Dump the map. For debugging.
Definition SymbolMap.cpp:112
Definition Matcher.h:25