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
191 void pushScope() {
192 symbolMapStack.emplace_back();
193 deviceSymbolMapStack.emplace_back();
194 storageMapStack.emplace_back();
195 componentMapStack.emplace_back();
196 }
197 void popScope() {
198 symbolMapStack.pop_back();
199 assert(symbolMapStack.size() >= 1);
200 deviceSymbolMapStack.pop_back();
201 assert(deviceSymbolMapStack.size() >= 1);
202 storageMapStack.pop_back();
203 assert(storageMapStack.size() >= 1);
204 componentMapStack.pop_back();
205 assert(componentMapStack.size() >= 1);
206 }
207
209 void addSymbol(semantics::SymbolRef sym, const fir::ExtendedValue &ext,
210 bool force = false);
211
213 void addSymbol(semantics::SymbolRef sym, mlir::Value value,
214 bool force = false) {
215 makeSym(sym, SymbolBox::Intrinsic(value), force);
216 }
217
219 void addCharSymbol(semantics::SymbolRef sym, mlir::Value value,
220 mlir::Value len, bool force = false) {
221 makeSym(sym, SymbolBox::Char(value, len), force);
222 }
223 void addCharSymbol(semantics::SymbolRef sym, const SymbolBox::Char &value,
224 bool force = false) {
225 makeSym(sym, value, force);
226 }
227
229 void addSymbolWithShape(semantics::SymbolRef sym, mlir::Value value,
231 bool force = false) {
232 makeSym(sym, SymbolBox::FullDim(value, shape), force);
233 }
234 void addSymbolWithShape(semantics::SymbolRef sym,
235 const SymbolBox::FullDim &value, bool force = false) {
236 makeSym(sym, value, force);
237 }
238
240 void addCharSymbolWithShape(semantics::SymbolRef sym, mlir::Value value,
241 mlir::Value len,
243 bool force = false) {
244 makeSym(sym, SymbolBox::CharFullDim(value, len, shape), force);
245 }
246 void addCharSymbolWithShape(semantics::SymbolRef sym,
247 const SymbolBox::CharFullDim &value,
248 bool force = false) {
249 makeSym(sym, value, force);
250 }
251
253 void addSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value,
256 bool force = false) {
257 makeSym(sym, SymbolBox::FullDim(value, extents, lbounds), force);
258 }
259 void addSymbolWithBounds(semantics::SymbolRef sym,
260 const SymbolBox::FullDim &value,
261 bool force = false) {
262 makeSym(sym, value, force);
263 }
264
266 void addCharSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value,
267 mlir::Value len,
270 bool force = false) {
271 makeSym(sym, SymbolBox::CharFullDim(value, len, extents, lbounds), force);
272 }
273 void addCharSymbolWithBounds(semantics::SymbolRef sym,
274 const SymbolBox::CharFullDim &value,
275 bool force = false) {
276 makeSym(sym, value, force);
277 }
278
279 void addAllocatableOrPointer(semantics::SymbolRef sym,
280 fir::MutableBoxValue box, bool force = false) {
281 makeSym(sym, box, force);
282 }
283
284 void addBoxSymbol(semantics::SymbolRef sym, mlir::Value irBox,
286 llvm::ArrayRef<mlir::Value> explicitParams,
287 llvm::ArrayRef<mlir::Value> explicitExtents,
288 bool force = false) {
289 makeSym(sym,
290 SymbolBox::Box(irBox, lbounds, explicitParams, explicitExtents),
291 force);
292 }
293 void addBoxSymbol(semantics::SymbolRef sym, const SymbolBox::Box &value,
294 bool force = false) {
295 makeSym(sym, value, force);
296 }
297
299 SymbolBox lookupSymbol(semantics::SymbolRef sym);
300 SymbolBox lookupSymbol(const semantics::Symbol *sym) {
301 return lookupSymbol(*sym);
302 }
303
307 void addDeviceVariableDefinition(semantics::SymbolRef symRef,
308 fir::FortranVariableOpInterface definingOp,
309 bool force = false) {
310 makeDeviceSym(symRef, SymbolBox(definingOp), force);
311 }
312 SymbolBox lookupDeviceSymbol(semantics::SymbolRef);
313 bool copyDeviceBindingToCurrentScope(semantics::SymbolRef symRef) {
314 if (SymbolBox box{lookupDeviceSymbol(symRef)}) {
315 makeSym(symRef, box, /*force=*/true);
316 return true;
317 }
318 return false;
319 }
320
323 const semantics::Symbol *lookupSymbolByName(llvm::StringRef symName);
324
327 SymbolBox shallowLookupSymbol(semantics::SymbolRef sym);
328 SymbolBox shallowLookupSymbol(const semantics::Symbol *sym) {
329 return shallowLookupSymbol(*sym);
330 }
331
334 SymbolBox lookupOneLevelUpSymbol(semantics::SymbolRef sym);
335 SymbolBox lookupOneLevelUpSymbol(const semantics::Symbol *sym) {
336 return lookupOneLevelUpSymbol(*sym);
337 }
338
340 void pushImpliedDoBinding(AcDoVar var, mlir::Value value) {
341 impliedDoStack.emplace_back(var, value);
342 }
343
346 assert(!impliedDoStack.empty());
347 impliedDoStack.pop_back();
348 }
349
352 mlir::Value lookupImpliedDo(AcDoVar var);
353
355 void clear() {
356 symbolMapStack.clear();
357 symbolMapStack.emplace_back();
358 deviceSymbolMapStack.clear();
359 deviceSymbolMapStack.emplace_back();
360 assert(symbolMapStack.size() == 1);
361 impliedDoStack.clear();
362 storageMapStack.clear();
363 storageMapStack.emplace_back();
364 componentMapStack.clear();
365 componentMapStack.emplace_back();
366 }
367
368 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
369 const SymMap &symMap);
370
372 LLVM_DUMP_METHOD void dump() const;
373
374 void addVariableDefinition(semantics::SymbolRef symRef,
375 fir::FortranVariableOpInterface definingOp,
376 bool force = false) {
377 makeSym(symRef, SymbolBox(definingOp), force);
378 }
379
380 void copySymbolBinding(semantics::SymbolRef src,
381 semantics::SymbolRef target) {
382 auto symBox = lookupSymbol(src);
383 assert(symBox && "source binding does not exists");
384 makeSym(target, symBox, /*force=*/false);
385 }
386
387 std::optional<fir::FortranVariableOpInterface>
388 lookupVariableDefinition(semantics::SymbolRef sym) {
389 if (auto symBox = lookupSymbol(sym))
390 return symBox.getIfFortranVariableOpInterface();
391 return std::nullopt;
392 }
393
398 fir::FortranVariableOpInterface definingOp) {
399 assert(!componentMapStack.empty() && "component map stack is empty");
400 if (!componentMapStack.back())
401 componentMapStack.back() = std::make_unique<ComponentMap>();
402 componentMapStack.back().value()->insert(component, definingOp);
403 }
404
407 std::optional<fir::FortranVariableOpInterface>
409 for (auto jmap = componentMapStack.rbegin(),
410 jend = componentMapStack.rend();
411 jmap != jend; ++jmap) {
412 if (*jmap) {
413 auto iter = (**jmap)->lookup(&component);
414 if (iter != std::nullopt)
415 return iter;
416 }
417 }
418 return std::nullopt;
419 }
420
424 void registerStorage(semantics::SymbolRef sym, StorageDesc storage);
426 StorageDesc lookupStorage(semantics::SymbolRef sym);
428 return lookupStorage(*sym);
429 }
430
431private:
433 void makeSym(semantics::SymbolRef symRef, const SymbolBox &box,
434 bool force = false) {
435 auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate();
436 if (force)
437 symbolMapStack.back().erase(sym);
438 assert(box && "cannot add an undefined symbol box");
439 symbolMapStack.back().try_emplace(sym, box);
440 }
441
442 void makeDeviceSym(semantics::SymbolRef symRef, const SymbolBox &box,
443 bool force = false) {
444 auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate();
445 if (force)
446 deviceSymbolMapStack.back().erase(sym);
447 assert(box && "cannot add an undefined device symbol box");
448 deviceSymbolMapStack.back().try_emplace(sym, box);
449 }
450
451 llvm::SmallVector<llvm::DenseMap<const semantics::Symbol *, SymbolBox>>
452 symbolMapStack;
453 llvm::SmallVector<llvm::DenseMap<const semantics::Symbol *, SymbolBox>>
454 deviceSymbolMapStack;
455
456 // Implied DO induction variables are not represented as Se::Symbol in
457 // Ev::Expr. Keep the variable markers in their own stack.
458 llvm::SmallVector<std::pair<AcDoVar, mlir::Value>> impliedDoStack;
459
460 // A stack of maps between the symbols and their storage descriptors.
461 llvm::SmallVector<llvm::DenseMap<const semantics::Symbol *, StorageDesc>>
462 storageMapStack;
463
464 // A stack of maps from front-end component references to the FIR variables
465 // that should be used to implement them. This allows overriding component
466 // references in specific lowering contexts.
467 llvm::SmallVector<std::optional<std::unique_ptr<ComponentMap>>>
468 componentMapStack;
469};
470
472class SymMapScope {
473public:
474 explicit SymMapScope(SymMap &map) : map(map) { map.pushScope(); }
475 ~SymMapScope() { map.popScope(); }
476
477private:
478 SymMap &map;
479};
480
481} // namespace Fortran::lower
482
483#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:229
void addComponentOverride(const Fortran::evaluate::Component &component, fir::FortranVariableOpInterface definingOp)
Definition SymbolMap.h:397
void pushImpliedDoBinding(AcDoVar var, mlir::Value value)
Add a new binding from the ac-do-variable var to value.
Definition SymbolMap.h:340
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:253
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:240
void addDeviceVariableDefinition(semantics::SymbolRef symRef, fir::FortranVariableOpInterface definingOp, bool force=false)
Definition SymbolMap.h:307
void popImpliedDoBinding()
Pop the most recent implied do binding off the stack.
Definition SymbolMap.h:345
void addSymbol(semantics::SymbolRef sym, mlir::Value value, bool force=false)
Add a trivial symbol mapping to an address.
Definition SymbolMap.h:213
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:408
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:266
void registerStorage(semantics::SymbolRef sym, StorageDesc storage)
Definition SymbolMap.cpp:106
void clear()
Remove all symbols from the map.
Definition SymbolMap.h:355
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:219
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:916
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