1 //===-- SymbolMap.h -- lowering internal symbol map -------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef FORTRAN_LOWER_SYMBOLMAP_H
10 #define FORTRAN_LOWER_SYMBOLMAP_H
12 #include "flang/Common/idioms.h"
13 #include "flang/Common/reference.h"
14 #include "flang/Lower/Support/BoxValue.h"
15 #include "flang/Optimizer/Dialect/FIRType.h"
16 #include "flang/Semantics/symbol.h"
17 #include "mlir/IR/Value.h"
18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/DenseMap.h"
20 #include "llvm/ADT/Optional.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/Support/Compiler.h"
24 namespace Fortran::lower
{
26 //===----------------------------------------------------------------------===//
28 //===----------------------------------------------------------------------===//
30 /// A dictionary entry of ssa-values that together compose a variable referenced
31 /// by a Symbol. For example, the declaration
33 /// CHARACTER(LEN=i) :: c(j1,j2)
35 /// is a single variable `c`. This variable is a two-dimensional array of
36 /// CHARACTER. It has a starting address and three dynamic properties: the LEN
37 /// parameter `i` a runtime value describing the length of the CHARACTER, and
38 /// the `j1` and `j2` runtime values, which describe the shape of the array.
40 /// The lowering bridge needs to be able to record all four of these ssa-values
41 /// in the lookup table to be able to correctly lower Fortran to FIR.
43 // For lookups that fail, have a monostate
44 using None
= std::monostate
;
46 // Trivial intrinsic type
47 using Intrinsic
= fir::AbstractBox
;
49 // Array variable that uses bounds notation
50 using FullDim
= fir::ArrayBoxValue
;
52 // CHARACTER type variable with its dependent type LEN parameter
53 using Char
= fir::CharBoxValue
;
55 // CHARACTER array variable using bounds notation
56 using CharFullDim
= fir::CharArrayBoxValue
;
58 // Generalized derived type variable
59 using Derived
= fir::BoxValue
;
61 //===--------------------------------------------------------------------===//
63 //===--------------------------------------------------------------------===//
65 SymbolBox() : box
{None
{}} {}
67 SymbolBox(const A
&x
) : box
{x
} {}
69 operator bool() const { return !std::holds_alternative
<None
>(box
); }
71 // This operator returns the address of the boxed value. TODO: consider
72 // eliminating this in favor of explicit conversion.
73 operator mlir::Value() const { return getAddr(); }
75 //===--------------------------------------------------------------------===//
77 //===--------------------------------------------------------------------===//
79 /// Get address of the boxed value. For a scalar, this is the address of the
80 /// scalar. For an array, this is the address of the first element in the
82 mlir::Value
getAddr() const {
83 return std::visit(common::visitors
{
84 [](const None
&) { return mlir::Value
{}; },
85 [](const auto &x
) { return x
.getAddr(); },
90 /// Get the LEN type parameter of a CHARACTER boxed value.
91 llvm::Optional
<mlir::Value
> getCharLen() const {
92 using T
= llvm::Optional
<mlir::Value
>;
93 return std::visit(common::visitors
{
94 [](const Char
&x
) { return T
{x
.getLen()}; },
95 [](const CharFullDim
&x
) { return T
{x
.getLen()}; },
96 [](const auto &) { return T
{}; },
101 /// Does the boxed value have an intrinsic type?
102 bool isIntrinsic() const {
103 return std::visit(common::visitors
{
104 [](const Intrinsic
&) { return true; },
105 [](const Char
&) { return true; },
106 [](const auto &x
) { return false; },
111 /// Does the boxed value have a rank greater than zero?
112 bool hasRank() const {
115 [](const Intrinsic
&) { return false; },
116 [](const Char
&) { return false; },
117 [](const None
&) { return false; },
118 [](const auto &x
) { return x
.getExtents().size() > 0; },
123 /// Does the boxed value have trivial lower bounds (== 1)?
124 bool hasSimpleLBounds() const {
125 if (auto *arr
= std::get_if
<FullDim
>(&box
))
126 return arr
->getLBounds().empty();
127 if (auto *arr
= std::get_if
<CharFullDim
>(&box
))
128 return arr
->getLBounds().empty();
129 if (auto *arr
= std::get_if
<Derived
>(&box
))
130 return (arr
->getExtents().size() > 0) && arr
->getLBounds().empty();
134 /// Does the boxed value have a constant shape?
135 bool hasConstantShape() const {
136 if (auto eleTy
= fir::dyn_cast_ptrEleTy(getAddr().getType()))
137 if (auto arrTy
= eleTy
.dyn_cast
<fir::SequenceType
>())
138 return arrTy
.hasConstantShape();
142 /// Get the lbound if the box explicitly contains it.
143 mlir::Value
getLBound(unsigned dim
) const {
146 [&](const FullDim
&box
) { return box
.getLBounds()[dim
]; },
147 [&](const CharFullDim
&box
) { return box
.getLBounds()[dim
]; },
148 [&](const Derived
&box
) { return box
.getLBounds()[dim
]; },
149 [](const auto &) { return mlir::Value
{}; }},
153 /// Apply the lambda `func` to this box value.
154 template <typename ON
, typename RT
>
155 constexpr RT
apply(RT(&&func
)(const ON
&)) const {
156 if (auto *x
= std::get_if
<ON
>(&box
))
161 std::variant
<Intrinsic
, FullDim
, Char
, CharFullDim
, Derived
, None
> box
;
164 //===----------------------------------------------------------------------===//
165 // Map of symbol information
166 //===----------------------------------------------------------------------===//
168 /// Helper class to map front-end symbols to their MLIR representation. This
169 /// provides a way to lookup the ssa-values that comprise a Fortran symbol's
170 /// runtime attributes. These attributes include its address, its dynamic size,
171 /// dynamic bounds information for non-scalar entities, dynamic type parameters,
175 /// Add a trivial symbol mapping to an address.
176 void addSymbol(semantics::SymbolRef sym
, mlir::Value value
,
177 bool force
= false) {
178 makeSym(sym
, SymbolBox::Intrinsic(value
), force
);
181 /// Add a scalar CHARACTER mapping to an (address, len).
182 void addCharSymbol(semantics::SymbolRef sym
, mlir::Value value
,
183 mlir::Value len
, bool force
= false) {
184 makeSym(sym
, SymbolBox::Char(value
, len
), force
);
187 /// Add an array mapping with (address, shape).
188 void addSymbolWithShape(semantics::SymbolRef sym
, mlir::Value value
,
189 llvm::ArrayRef
<mlir::Value
> shape
,
190 bool force
= false) {
191 makeSym(sym
, SymbolBox::FullDim(value
, shape
), force
);
194 /// Add an array of CHARACTER mapping.
195 void addCharSymbolWithShape(semantics::SymbolRef sym
, mlir::Value value
,
197 llvm::ArrayRef
<mlir::Value
> shape
,
198 bool force
= false) {
199 makeSym(sym
, SymbolBox::CharFullDim(value
, len
, shape
), force
);
202 /// Add an array mapping with bounds notation.
203 void addSymbolWithBounds(semantics::SymbolRef sym
, mlir::Value value
,
204 llvm::ArrayRef
<mlir::Value
> extents
,
205 llvm::ArrayRef
<mlir::Value
> lbounds
,
206 bool force
= false) {
207 makeSym(sym
, SymbolBox::FullDim(value
, extents
, lbounds
), force
);
210 /// Add an array of CHARACTER with bounds notation.
211 void addCharSymbolWithBounds(semantics::SymbolRef sym
, mlir::Value value
,
213 llvm::ArrayRef
<mlir::Value
> extents
,
214 llvm::ArrayRef
<mlir::Value
> lbounds
,
215 bool force
= false) {
216 makeSym(sym
, SymbolBox::CharFullDim(value
, len
, extents
, lbounds
), force
);
219 /// Generalized derived type mapping.
220 void addDerivedSymbol(semantics::SymbolRef sym
, mlir::Value value
,
221 mlir::Value size
, llvm::ArrayRef
<mlir::Value
> extents
,
222 llvm::ArrayRef
<mlir::Value
> lbounds
,
223 llvm::ArrayRef
<mlir::Value
> params
,
224 bool force
= false) {
225 makeSym(sym
, SymbolBox::Derived(value
, size
, params
, extents
, lbounds
),
229 /// Find `symbol` and return its value if it appears in the current mappings.
230 SymbolBox
lookupSymbol(semantics::SymbolRef sym
) {
231 auto iter
= symbolMap
.find(&*sym
);
232 return (iter
== symbolMap
.end()) ? SymbolBox() : iter
->second
;
235 /// Remove `sym` from the map.
236 void erase(semantics::SymbolRef sym
) { symbolMap
.erase(&*sym
); }
238 /// Remove all symbols from the map.
239 void clear() { symbolMap
.clear(); }
241 /// Dump the map. For debugging.
242 LLVM_DUMP_METHOD
void dump() const;
245 /// Add `symbol` to the current map and bind a `box`.
246 void makeSym(semantics::SymbolRef sym
, const SymbolBox
&box
,
247 bool force
= false) {
250 assert(box
&& "cannot add an undefined symbol box");
251 symbolMap
.try_emplace(&*sym
, box
);
254 llvm::DenseMap
<const semantics::Symbol
*, SymbolBox
> symbolMap
;
257 } // namespace Fortran::lower
259 #endif // FORTRAN_LOWER_SYMBOLMAP_H