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/Lower/Support/Utils.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
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
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
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
131 LLVM_DUMP_METHOD void dump() const;
132
133private:
134 VT box;
135};
136
141public:
142 void insert(const Fortran::evaluate::Component &component,
143 fir::FortranVariableOpInterface definingOp) {
144 auto iter = componentMap.find(&component);
145 if (iter != componentMap.end()) {
146 iter->second = definingOp;
147 return;
148 }
149 componentStorage.push_back(
150 std::make_unique<Fortran::evaluate::Component>(component));
151 componentMap.insert({componentStorage.back().get(), definingOp});
152 }
153
154 std::optional<fir::FortranVariableOpInterface>
155 lookup(const Fortran::evaluate::Component *component) const {
156 auto iter = componentMap.find(component);
157 if (iter != componentMap.end())
158 return iter->second;
159 return std::nullopt;
160 }
161
162 LLVM_DUMP_METHOD void dump() const;
163
164private:
165 llvm::DenseMap<const Fortran::evaluate::Component *,
166 fir::FortranVariableOpInterface>
167 componentMap;
169 componentStorage;
170};
171
172//===----------------------------------------------------------------------===//
173// Map of symbol information
174//===----------------------------------------------------------------------===//
175
181class SymMap {
182public:
183 using AcDoVar = llvm::StringRef;
186 using StorageDesc = std::pair<mlir::Value, std::uint64_t>;
187
188 SymMap() { pushScope(); }
189 SymMap(const SymMap &) = delete;
190
197 static const semantics::Symbol &getKey(semantics::SymbolRef symRef) {
198 const semantics::Symbol *sym = &*symRef;
199 while (!sym->HasLocalLocality()) {
200 const auto *hostAssoc = sym->detailsIf<semantics::HostAssocDetails>();
201 if (!hostAssoc)
202 return sym->GetUltimate();
203 sym = &hostAssoc->symbol();
204 }
205 return *sym;
206 }
207
208 void pushScope() {
209 symbolMapStack.emplace_back();
210 deviceSymbolMapStack.emplace_back();
211 storageMapStack.emplace_back();
212 componentMapStack.emplace_back();
213 }
214 void popScope() {
215 symbolMapStack.pop_back();
216 assert(symbolMapStack.size() >= 1);
217 deviceSymbolMapStack.pop_back();
218 assert(deviceSymbolMapStack.size() >= 1);
219 storageMapStack.pop_back();
220 assert(storageMapStack.size() >= 1);
221 componentMapStack.pop_back();
222 assert(componentMapStack.size() >= 1);
223 }
224
226 void addSymbol(semantics::SymbolRef sym, const fir::ExtendedValue &ext,
227 bool force = false);
228
230 void addSymbol(semantics::SymbolRef sym, mlir::Value value,
231 bool force = false) {
232 makeSym(sym, SymbolBox::Intrinsic(value), force);
233 }
234
236 void addCharSymbol(semantics::SymbolRef sym, mlir::Value value,
237 mlir::Value len, bool force = false) {
238 makeSym(sym, SymbolBox::Char(value, len), force);
239 }
240 void addCharSymbol(semantics::SymbolRef sym, const SymbolBox::Char &value,
241 bool force = false) {
242 makeSym(sym, value, force);
243 }
244
246 void addSymbolWithShape(semantics::SymbolRef sym, mlir::Value value,
248 bool force = false) {
249 makeSym(sym, SymbolBox::FullDim(value, shape), force);
250 }
251 void addSymbolWithShape(semantics::SymbolRef sym,
252 const SymbolBox::FullDim &value, bool force = false) {
253 makeSym(sym, value, force);
254 }
255
257 void addCharSymbolWithShape(semantics::SymbolRef sym, mlir::Value value,
258 mlir::Value len,
260 bool force = false) {
261 makeSym(sym, SymbolBox::CharFullDim(value, len, shape), force);
262 }
263 void addCharSymbolWithShape(semantics::SymbolRef sym,
264 const SymbolBox::CharFullDim &value,
265 bool force = false) {
266 makeSym(sym, value, force);
267 }
268
270 void addSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value,
273 bool force = false) {
274 makeSym(sym, SymbolBox::FullDim(value, extents, lbounds), force);
275 }
276 void addSymbolWithBounds(semantics::SymbolRef sym,
277 const SymbolBox::FullDim &value,
278 bool force = false) {
279 makeSym(sym, value, force);
280 }
281
283 void addCharSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value,
284 mlir::Value len,
287 bool force = false) {
288 makeSym(sym, SymbolBox::CharFullDim(value, len, extents, lbounds), force);
289 }
290 void addCharSymbolWithBounds(semantics::SymbolRef sym,
291 const SymbolBox::CharFullDim &value,
292 bool force = false) {
293 makeSym(sym, value, force);
294 }
295
296 void addAllocatableOrPointer(semantics::SymbolRef sym,
297 fir::MutableBoxValue box, bool force = false) {
298 makeSym(sym, box, force);
299 }
300
301 void addBoxSymbol(semantics::SymbolRef sym, mlir::Value irBox,
303 llvm::ArrayRef<mlir::Value> explicitParams,
304 llvm::ArrayRef<mlir::Value> explicitExtents,
305 bool force = false) {
306 makeSym(sym,
307 SymbolBox::Box(irBox, lbounds, explicitParams, explicitExtents),
308 force);
309 }
310 void addBoxSymbol(semantics::SymbolRef sym, const SymbolBox::Box &value,
311 bool force = false) {
312 makeSym(sym, value, force);
313 }
314
316 SymbolBox lookupSymbol(semantics::SymbolRef sym);
317 SymbolBox lookupSymbol(const semantics::Symbol *sym) {
318 return lookupSymbol(*sym);
319 }
320
324 void addDeviceVariableDefinition(semantics::SymbolRef symRef,
325 fir::FortranVariableOpInterface definingOp,
326 bool force = false) {
327 makeDeviceSym(symRef, SymbolBox(definingOp), force);
328 }
329 SymbolBox lookupDeviceSymbol(semantics::SymbolRef);
330 bool copyDeviceBindingToCurrentScope(semantics::SymbolRef symRef) {
331 if (SymbolBox box{lookupDeviceSymbol(symRef)}) {
332 makeSym(symRef, box, /*force=*/true);
333 return true;
334 }
335 return false;
336 }
337
340 const semantics::Symbol *lookupSymbolByName(llvm::StringRef symName);
341
344 SymbolBox shallowLookupSymbol(semantics::SymbolRef sym);
345 SymbolBox shallowLookupSymbol(const semantics::Symbol *sym) {
346 return shallowLookupSymbol(*sym);
347 }
348
351 SymbolBox lookupOneLevelUpSymbol(semantics::SymbolRef sym);
352 SymbolBox lookupOneLevelUpSymbol(const semantics::Symbol *sym) {
353 return lookupOneLevelUpSymbol(*sym);
354 }
355
357 void pushImpliedDoBinding(AcDoVar var, mlir::Value value) {
358 impliedDoStack.emplace_back(var, value);
359 }
360
363 assert(!impliedDoStack.empty());
364 impliedDoStack.pop_back();
365 }
366
369 mlir::Value lookupImpliedDo(AcDoVar var);
370
372 void clear() {
373 symbolMapStack.clear();
374 symbolMapStack.emplace_back();
375 deviceSymbolMapStack.clear();
376 deviceSymbolMapStack.emplace_back();
377 assert(symbolMapStack.size() == 1);
378 impliedDoStack.clear();
379 storageMapStack.clear();
380 storageMapStack.emplace_back();
381 componentMapStack.clear();
382 componentMapStack.emplace_back();
383 }
384
385 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
386 const SymMap &symMap);
387
389 LLVM_DUMP_METHOD void dump() const;
390
391 void addVariableDefinition(semantics::SymbolRef symRef,
392 fir::FortranVariableOpInterface definingOp,
393 bool force = false) {
394 makeSym(symRef, SymbolBox(definingOp), force);
395 }
396
397 void copySymbolBinding(semantics::SymbolRef src,
398 semantics::SymbolRef target) {
399 auto symBox = lookupSymbol(src);
400 assert(symBox && "source binding does not exists");
401 makeSym(target, symBox, /*force=*/false);
402 }
403
404 std::optional<fir::FortranVariableOpInterface>
405 lookupVariableDefinition(semantics::SymbolRef sym) {
406 if (auto symBox = lookupSymbol(sym))
407 return symBox.getIfFortranVariableOpInterface();
408 return std::nullopt;
409 }
410
415 fir::FortranVariableOpInterface definingOp) {
416 assert(!componentMapStack.empty() && "component map stack is empty");
417 if (!componentMapStack.back())
418 componentMapStack.back() = std::make_unique<ComponentMap>();
419 componentMapStack.back().value()->insert(component, definingOp);
420 }
421
424 std::optional<fir::FortranVariableOpInterface>
426 for (auto jmap = componentMapStack.rbegin(),
427 jend = componentMapStack.rend();
428 jmap != jend; ++jmap) {
429 if (*jmap) {
430 auto iter = (**jmap)->lookup(&component);
431 if (iter != std::nullopt)
432 return iter;
433 }
434 }
435 return std::nullopt;
436 }
437
441 void registerStorage(semantics::SymbolRef sym, StorageDesc storage);
443 StorageDesc lookupStorage(semantics::SymbolRef sym);
445 return lookupStorage(*sym);
446 }
447
448private:
450 void makeSym(semantics::SymbolRef symRef, const SymbolBox &box,
451 bool force = false) {
452 auto *sym = &getKey(symRef);
453 if (force)
454 symbolMapStack.back().erase(sym);
455 assert(box && "cannot add an undefined symbol box");
456 symbolMapStack.back().try_emplace(sym, box);
457 }
458
459 void makeDeviceSym(semantics::SymbolRef symRef, const SymbolBox &box,
460 bool force = false) {
461 auto *sym = &getKey(symRef);
462 if (force)
463 deviceSymbolMapStack.back().erase(sym);
464 assert(box && "cannot add an undefined device symbol box");
465 deviceSymbolMapStack.back().try_emplace(sym, box);
466 }
467
468 llvm::SmallVector<llvm::DenseMap<const semantics::Symbol *, SymbolBox>>
469 symbolMapStack;
470 llvm::SmallVector<llvm::DenseMap<const semantics::Symbol *, SymbolBox>>
471 deviceSymbolMapStack;
472
473 // Implied DO induction variables are not represented as Se::Symbol in
474 // Ev::Expr. Keep the variable markers in their own stack.
475 llvm::SmallVector<std::pair<AcDoVar, mlir::Value>> impliedDoStack;
476
477 // A stack of maps between the symbols and their storage descriptors.
478 llvm::SmallVector<llvm::DenseMap<const semantics::Symbol *, StorageDesc>>
479 storageMapStack;
480
481 // A stack of maps from front-end component references to the FIR variables
482 // that should be used to implement them. This allows overriding component
483 // references in specific lowering contexts.
484 llvm::SmallVector<std::optional<std::unique_ptr<ComponentMap>>>
485 componentMapStack;
486};
487
489class SymMapScope {
490public:
491 explicit SymMapScope(SymMap &map) : map(map) { map.pushScope(); }
492 ~SymMapScope() { map.popScope(); }
493
494private:
495 SymMap &map;
496};
497
498} // namespace Fortran::lower
499
500#endif // FORTRAN_LOWER_SYMBOLMAP_H
Definition variable.h:73
Definition SymbolMap.h:140
Definition SymbolMap.h:181
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:246
void addComponentOverride(const Fortran::evaluate::Component &component, fir::FortranVariableOpInterface definingOp)
Definition SymbolMap.h:414
void pushImpliedDoBinding(AcDoVar var, mlir::Value value)
Add a new binding from the ac-do-variable var to value.
Definition SymbolMap.h:357
SymbolBox lookupSymbol(semantics::SymbolRef sym)
Find symbol and return its value if it appears in the current mappings.
Definition SymbolMap.cpp:35
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:270
mlir::Value lookupImpliedDo(AcDoVar var)
Definition SymbolMap.cpp:99
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:257
void addDeviceVariableDefinition(semantics::SymbolRef symRef, fir::FortranVariableOpInterface definingOp, bool force=false)
Definition SymbolMap.h:324
void popImpliedDoBinding()
Pop the most recent implied do binding off the stack.
Definition SymbolMap.h:362
void addSymbol(semantics::SymbolRef sym, mlir::Value value, bool force=false)
Add a trivial symbol mapping to an address.
Definition SymbolMap.h:230
std::pair< mlir::Value, std::uint64_t > StorageDesc
Definition SymbolMap.h:186
std::optional< fir::FortranVariableOpInterface > lookupComponentOverride(const Fortran::evaluate::Component &component) const
Definition SymbolMap.h:425
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:283
void registerStorage(semantics::SymbolRef sym, StorageDesc storage)
Definition SymbolMap.cpp:106
void clear()
Remove all symbols from the map.
Definition SymbolMap.h:372
SymbolBox lookupOneLevelUpSymbol(semantics::SymbolRef sym)
Definition SymbolMap.cpp:82
void addSymbol(semantics::SymbolRef sym, const fir::ExtendedValue &ext, bool force=false)
Add an extended value to the symbol table.
Definition SymbolMap.cpp:19
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:236
static const semantics::Symbol & getKey(semantics::SymbolRef symRef)
Definition SymbolMap.h:197
SymbolBox shallowLookupSymbol(semantics::SymbolRef sym)
Definition SymbolMap.cpp:69
StorageDesc lookupStorage(semantics::SymbolRef sym)
Lookup the symbol's storage at the innermost level of the symbol table.
Definition SymbolMap.cpp:114
LLVM_DUMP_METHOD void dump() const
Dump the map. For debugging.
Definition SymbolMap.cpp:135
const semantics::Symbol * lookupSymbolByName(llvm::StringRef symName)
Definition SymbolMap.cpp:60
Definition symbol.h:918
Abstract base class.
Definition BoxValue.h:60
Definition BoxValue.h:152
Definition BoxValue.h:292
Expressions of type CHARACTER and with rank > 0.
Definition BoxValue.h:169
Definition BoxValue.h:76
Definition BoxValue.h:469
Definition BoxValue.h:361
Definition FIRType.h:106
Definition OpenACC.h:20
Definition ParserActions.h:24
Definition SymbolMap.h:52
mlir::Value getAddr() const
Definition SymbolMap.h:99
constexpr RT apply(RT(&&func)(const ON &)) const
Apply the lambda func to this box value.
Definition SymbolMap.h:119
LLVM_DUMP_METHOD void dump() const
Dump the map. For debugging.
Definition SymbolMap.cpp:123
Definition Matcher.h:25