[flang-commits] [flang] b5d51c2 - [flang] Add SymbolMap

Eric Schweitz via flang-commits flang-commits at lists.llvm.org
Fri Jun 19 11:48:14 PDT 2020


Author: Eric Schweitz
Date: 2020-06-19T11:47:58-07:00
New Revision: b5d51c24488b5955700f29e40cfb4c5fb4241f76

URL: https://github.com/llvm/llvm-project/commit/b5d51c24488b5955700f29e40cfb4c5fb4241f76
DIFF: https://github.com/llvm/llvm-project/commit/b5d51c24488b5955700f29e40cfb4c5fb4241f76.diff

LOG: [flang] Add SymbolMap

The symbol map is a data structure for tracking variables in a subprogram during the lowering of that subprogram to FIR/MLIR. These data structures will be used by the bridge, which has not been upstreamed yet.

Differential revision: https://reviews.llvm.org/D82140

Added: 
    flang/lib/Lower/SymbolMap.h

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/SymbolMap.h b/flang/lib/Lower/SymbolMap.h
new file mode 100644
index 000000000000..fa225458f435
--- /dev/null
+++ b/flang/lib/Lower/SymbolMap.h
@@ -0,0 +1,257 @@
+//===-- 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"
+
+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.addr; },
+                      },
+                      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.len}; },
+                          [](const CharFullDim &x) { return T{x.len}; },
+                          [](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.extents.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->lbounds.empty();
+    if (auto *arr = std::get_if<CharFullDim>(&box))
+      return arr->lbounds.empty();
+    if (auto *arr = std::get_if<Derived>(&box))
+      return (arr->extents.size() > 0) && arr->lbounds.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.lbounds[dim]; },
+            [&](const CharFullDim &box) { return box.lbounds[dim]; },
+            [&](const Derived &box) { return box.lbounds[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.
+  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


        


More information about the flang-commits mailing list