xref: /llvm-project/flang/include/flang/Lower/SymbolMap.h (revision 433ca3ebbef50002bec716ef2c6d6a82db71048d)
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 /// RAII wrapper for SymMap.
338 class SymMapScope {
339 public:
340   explicit SymMapScope(SymMap &map) : map(map) { map.pushScope(); }
341   ~SymMapScope() { map.popScope(); }
342 
343 private:
344   SymMap &map;
345 };
346 
347 } // namespace Fortran::lower
348 
349 #endif // FORTRAN_LOWER_SYMBOLMAP_H
350