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 #ifndef FORTRAN_LOWER_SYMBOLMAP_H 10 #define FORTRAN_LOWER_SYMBOLMAP_H 11 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" 23 24 namespace Fortran::lower { 25 26 //===----------------------------------------------------------------------===// 27 // Symbol information 28 //===----------------------------------------------------------------------===// 29 30 /// A dictionary entry of ssa-values that together compose a variable referenced 31 /// by a Symbol. For example, the declaration 32 /// 33 /// CHARACTER(LEN=i) :: c(j1,j2) 34 /// 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. 39 /// 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. 42 struct SymbolBox { 43 // For lookups that fail, have a monostate 44 using None = std::monostate; 45 46 // Trivial intrinsic type 47 using Intrinsic = fir::AbstractBox; 48 49 // Array variable that uses bounds notation 50 using FullDim = fir::ArrayBoxValue; 51 52 // CHARACTER type variable with its dependent type LEN parameter 53 using Char = fir::CharBoxValue; 54 55 // CHARACTER array variable using bounds notation 56 using CharFullDim = fir::CharArrayBoxValue; 57 58 // Generalized derived type variable 59 using Derived = fir::BoxValue; 60 61 //===--------------------------------------------------------------------===// 62 // Constructors 63 //===--------------------------------------------------------------------===// 64 SymbolBoxSymbolBox65 SymbolBox() : box{None{}} {} 66 template <typename A> SymbolBoxSymbolBox67 SymbolBox(const A &x) : box{x} {} 68 69 operator bool() const { return !std::holds_alternative<None>(box); } 70 71 // This operator returns the address of the boxed value. TODO: consider 72 // eliminating this in favor of explicit conversion. ValueSymbolBox73 operator mlir::Value() const { return getAddr(); } 74 75 //===--------------------------------------------------------------------===// 76 // Accessors 77 //===--------------------------------------------------------------------===// 78 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 81 /// array, etc. getAddrSymbolBox82 mlir::Value getAddr() const { 83 return std::visit(common::visitors{ 84 [](const None &) { return mlir::Value{}; }, 85 [](const auto &x) { return x.getAddr(); }, 86 }, 87 box); 88 } 89 90 /// Get the LEN type parameter of a CHARACTER boxed value. getCharLenSymbolBox91 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{}; }, 97 }, 98 box); 99 } 100 101 /// Does the boxed value have an intrinsic type? isIntrinsicSymbolBox102 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; }, 107 }, 108 box); 109 } 110 111 /// Does the boxed value have a rank greater than zero? hasRankSymbolBox112 bool hasRank() const { 113 return std::visit( 114 common::visitors{ 115 [](const Intrinsic &) { return false; }, 116 [](const Char &) { return false; }, 117 [](const None &) { return false; }, 118 [](const auto &x) { return x.getExtents().size() > 0; }, 119 }, 120 box); 121 } 122 123 /// Does the boxed value have trivial lower bounds (== 1)? hasSimpleLBoundsSymbolBox124 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(); 131 return false; 132 } 133 134 /// Does the boxed value have a constant shape? hasConstantShapeSymbolBox135 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(); 139 return false; 140 } 141 142 /// Get the lbound if the box explicitly contains it. getLBoundSymbolBox143 mlir::Value getLBound(unsigned dim) const { 144 return std::visit( 145 common::visitors{ 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{}; }}, 150 box); 151 } 152 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)) 157 return func(*x); 158 return RT{}; 159 } 160 161 std::variant<Intrinsic, FullDim, Char, CharFullDim, Derived, None> box; 162 }; 163 164 //===----------------------------------------------------------------------===// 165 // Map of symbol information 166 //===----------------------------------------------------------------------===// 167 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, 172 /// etc. 173 class SymMap { 174 public: 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); 179 } 180 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); 185 } 186 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); 192 } 193 194 /// Add an array of CHARACTER mapping. 195 void addCharSymbolWithShape(semantics::SymbolRef sym, mlir::Value value, 196 mlir::Value len, 197 llvm::ArrayRef<mlir::Value> shape, 198 bool force = false) { 199 makeSym(sym, SymbolBox::CharFullDim(value, len, shape), force); 200 } 201 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); 208 } 209 210 /// Add an array of CHARACTER with bounds notation. 211 void addCharSymbolWithBounds(semantics::SymbolRef sym, mlir::Value value, 212 mlir::Value len, 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); 217 } 218 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), 226 force); 227 } 228 229 /// Find `symbol` and return its value if it appears in the current mappings. lookupSymbol(semantics::SymbolRef sym)230 SymbolBox lookupSymbol(semantics::SymbolRef sym) { 231 auto iter = symbolMap.find(&*sym); 232 return (iter == symbolMap.end()) ? SymbolBox() : iter->second; 233 } 234 235 /// Remove `sym` from the map. erase(semantics::SymbolRef sym)236 void erase(semantics::SymbolRef sym) { symbolMap.erase(&*sym); } 237 238 /// Remove all symbols from the map. clear()239 void clear() { symbolMap.clear(); } 240 241 /// Dump the map. For debugging. 242 LLVM_DUMP_METHOD void dump() const; 243 244 private: 245 /// Add `symbol` to the current map and bind a `box`. 246 void makeSym(semantics::SymbolRef sym, const SymbolBox &box, 247 bool force = false) { 248 if (force) 249 erase(sym); 250 assert(box && "cannot add an undefined symbol box"); 251 symbolMap.try_emplace(&*sym, box); 252 } 253 254 llvm::DenseMap<const semantics::Symbol *, SymbolBox> symbolMap; 255 }; 256 257 } // namespace Fortran::lower 258 259 #endif // FORTRAN_LOWER_SYMBOLMAP_H 260