SymbolMap.h
9.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
//===-- SymbolMap.h -- lowering internal symbol map -------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef FORTRAN_LOWER_SYMBOLMAP_H
#define FORTRAN_LOWER_SYMBOLMAP_H
#include "flang/Common/idioms.h"
#include "flang/Common/reference.h"
#include "flang/Lower/Support/BoxValue.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Semantics/symbol.h"
#include "mlir/IR/Value.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
namespace Fortran::lower {
//===----------------------------------------------------------------------===//
// Symbol information
//===----------------------------------------------------------------------===//
/// A dictionary entry of ssa-values that together compose a variable referenced
/// by a Symbol. For example, the declaration
///
/// CHARACTER(LEN=i) :: c(j1,j2)
///
/// is a single variable `c`. This variable is a two-dimensional array of
/// CHARACTER. It has a starting address and three dynamic properties: the LEN
/// parameter `i` a runtime value describing the length of the CHARACTER, and
/// the `j1` and `j2` runtime values, which describe the shape of the array.
///
/// The lowering bridge needs to be able to record all four of these ssa-values
/// in the lookup table to be able to correctly lower Fortran to FIR.
struct SymbolBox {
// For lookups that fail, have a monostate
using None = std::monostate;
// Trivial intrinsic type
using Intrinsic = fir::AbstractBox;
// Array variable that uses bounds notation
using FullDim = fir::ArrayBoxValue;
// CHARACTER type variable with its dependent type LEN parameter
using Char = fir::CharBoxValue;
// CHARACTER array variable using bounds notation
using CharFullDim = fir::CharArrayBoxValue;
// Generalized derived type variable
using Derived = fir::BoxValue;
//===--------------------------------------------------------------------===//
// Constructors
//===--------------------------------------------------------------------===//
SymbolBox() : box{None{}} {}
template <typename A>
SymbolBox(const A &x) : box{x} {}
operator bool() const { return !std::holds_alternative<None>(box); }
// This operator returns the address of the boxed value. TODO: consider
// eliminating this in favor of explicit conversion.
operator mlir::Value() const { return getAddr(); }
//===--------------------------------------------------------------------===//
// Accessors
//===--------------------------------------------------------------------===//
/// Get address of the boxed value. For a scalar, this is the address of the
/// scalar. For an array, this is the address of the first element in the
/// array, etc.
mlir::Value getAddr() const {
return std::visit(common::visitors{
[](const None &) { return mlir::Value{}; },
[](const auto &x) { return x.getAddr(); },
},
box);
}
/// Get the LEN type parameter of a CHARACTER boxed value.
llvm::Optional<mlir::Value> getCharLen() const {
using T = llvm::Optional<mlir::Value>;
return std::visit(common::visitors{
[](const Char &x) { return T{x.getLen()}; },
[](const CharFullDim &x) { return T{x.getLen()}; },
[](const auto &) { return T{}; },
},
box);
}
/// Does the boxed value have an intrinsic type?
bool isIntrinsic() const {
return std::visit(common::visitors{
[](const Intrinsic &) { return true; },
[](const Char &) { return true; },
[](const auto &x) { return false; },
},
box);
}
/// Does the boxed value have a rank greater than zero?
bool hasRank() const {
return std::visit(
common::visitors{
[](const Intrinsic &) { return false; },
[](const Char &) { return false; },
[](const None &) { return false; },
[](const auto &x) { return x.getExtents().size() > 0; },
},
box);
}
/// Does the boxed value have trivial lower bounds (== 1)?
bool hasSimpleLBounds() const {
if (auto *arr = std::get_if<FullDim>(&box))
return arr->getLBounds().empty();
if (auto *arr = std::get_if<CharFullDim>(&box))
return arr->getLBounds().empty();
if (auto *arr = std::get_if<Derived>(&box))
return (arr->getExtents().size() > 0) && arr->getLBounds().empty();
return false;
}
/// Does the boxed value have a constant shape?
bool hasConstantShape() const {
if (auto eleTy = fir::dyn_cast_ptrEleTy(getAddr().getType()))
if (auto arrTy = eleTy.dyn_cast<fir::SequenceType>())
return arrTy.hasConstantShape();
return false;
}
/// Get the lbound if the box explicitly contains it.
mlir::Value getLBound(unsigned dim) const {
return std::visit(
common::visitors{
[&](const FullDim &box) { return box.getLBounds()[dim]; },
[&](const CharFullDim &box) { return box.getLBounds()[dim]; },
[&](const Derived &box) { return box.getLBounds()[dim]; },
[](const auto &) { return mlir::Value{}; }},
box);
}
/// Apply the lambda `func` to this box value.
template <typename ON, typename RT>
constexpr RT apply(RT(&&func)(const ON &)) const {
if (auto *x = std::get_if<ON>(&box))
return func(*x);
return RT{};
}
std::variant<Intrinsic, FullDim, Char, CharFullDim, Derived, None> box;
};
//===----------------------------------------------------------------------===//
// Map of symbol information
//===----------------------------------------------------------------------===//
/// Helper class to map front-end symbols to their MLIR representation. This
/// provides a way to lookup the ssa-values that comprise a Fortran symbol's
/// runtime attributes. These attributes include its address, its dynamic size,
/// dynamic bounds information for non-scalar entities, dynamic type parameters,
/// etc.
class SymMap {
public:
/// Add a trivial symbol mapping to an address.
void addSymbol(semantics::SymbolRef sym, mlir::Value value,
bool force = false) {
makeSym(sym, SymbolBox::Intrinsic(value), force);
}
/// Add a scalar CHARACTER mapping to an (address, len).
void addCharSymbol(semantics::SymbolRef sym, mlir::Value value,
mlir::Value len, bool force = false) {
makeSym(sym, SymbolBox::Char(value, len), force);
}
/// Add an array mapping with (address, shape).
void addSymbolWithShape(semantics::SymbolRef sym, mlir::Value value,
llvm::ArrayRef<mlir::Value> shape,
bool force = false) {
makeSym(sym, SymbolBox::FullDim(value, shape), force);
}
/// Add an array of CHARACTER mapping.
void addCharSymbolWithShape(semantics::SymbolRef sym, mlir::Value value,
mlir::Value len,
llvm::ArrayRef<mlir::Value> shape,
bool force = false) {
makeSym(sym, SymbolBox::CharFullDim(value, len, shape), force);
}
/// Add an array mapping with bounds notation.
void addSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value,
llvm::ArrayRef<mlir::Value> extents,
llvm::ArrayRef<mlir::Value> lbounds,
bool force = false) {
makeSym(sym, SymbolBox::FullDim(value, extents, lbounds), force);
}
/// Add an array of CHARACTER with bounds notation.
void addCharSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value,
mlir::Value len,
llvm::ArrayRef<mlir::Value> extents,
llvm::ArrayRef<mlir::Value> lbounds,
bool force = false) {
makeSym(sym, SymbolBox::CharFullDim(value, len, extents, lbounds), force);
}
/// Generalized derived type mapping.
void addDerivedSymbol(semantics::SymbolRef sym, mlir::Value value,
mlir::Value size, llvm::ArrayRef<mlir::Value> extents,
llvm::ArrayRef<mlir::Value> lbounds,
llvm::ArrayRef<mlir::Value> params,
bool force = false) {
makeSym(sym, SymbolBox::Derived(value, size, params, extents, lbounds),
force);
}
/// Find `symbol` and return its value if it appears in the current mappings.
SymbolBox lookupSymbol(semantics::SymbolRef sym) {
auto iter = symbolMap.find(&*sym);
return (iter == symbolMap.end()) ? SymbolBox() : iter->second;
}
/// Remove `sym` from the map.
void erase(semantics::SymbolRef sym) { symbolMap.erase(&*sym); }
/// Remove all symbols from the map.
void clear() { symbolMap.clear(); }
/// Dump the map. For debugging.
LLVM_DUMP_METHOD void dump() const;
private:
/// Add `symbol` to the current map and bind a `box`.
void makeSym(semantics::SymbolRef sym, const SymbolBox &box,
bool force = false) {
if (force)
erase(sym);
assert(box && "cannot add an undefined symbol box");
symbolMap.try_emplace(&*sym, box);
}
llvm::DenseMap<const semantics::Symbol *, SymbolBox> symbolMap;
};
} // namespace Fortran::lower
#endif // FORTRAN_LOWER_SYMBOLMAP_H