--- /dev/null
+//===-- Lower/Support/BoxValue.h -- internal box values ---------*- 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 LOWER_SUPPORT_BOXVALUE_H
+#define LOWER_SUPPORT_BOXVALUE_H
+
+#include "mlir/IR/Value.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/raw_ostream.h"
+#include <utility>
+#include <variant>
+
+namespace fir {
+class CharBoxValue;
+class ArrayBoxValue;
+class CharArrayBoxValue;
+class BoxValue;
+class ProcBoxValue;
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CharBoxValue &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ArrayBoxValue &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CharArrayBoxValue &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const BoxValue &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ProcBoxValue &);
+
+//===----------------------------------------------------------------------===//
+//
+// Boxed values
+//
+// Define a set of containers used internally by the lowering bridge to keep
+// track of extended values associated with a Fortran subexpression. These
+// associations are maintained during the construction of FIR.
+//
+//===----------------------------------------------------------------------===//
+
+/// Most expressions of intrinsic type can be passed unboxed. Their properties
+/// are known statically.
+using UnboxedValue = mlir::Value;
+
+/// Abstract base class.
+class AbstractBox {
+public:
+ AbstractBox() = delete;
+ AbstractBox(mlir::Value addr) : addr{addr} {}
+ mlir::Value getAddr() const { return addr; }
+
+protected:
+ mlir::Value addr;
+};
+
+/// Expressions of CHARACTER type have an associated, possibly dynamic LEN
+/// value.
+class CharBoxValue : public AbstractBox {
+public:
+ CharBoxValue(mlir::Value addr, mlir::Value len)
+ : AbstractBox{addr}, len{len} {}
+
+ CharBoxValue clone(mlir::Value newBase) const { return {newBase, len}; }
+
+ mlir::Value getLen() const { return len; }
+ mlir::Value getBuffer() const { return getAddr(); }
+
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ const CharBoxValue &);
+ void dump() const { llvm::errs() << *this; }
+
+protected:
+ mlir::Value len;
+};
+
+/// Abstract base class.
+/// Expressions of type array have at minimum a shape. These expressions may
+/// have lbound attributes (dynamic values) that affect the interpretation of
+/// indexing expressions.
+class AbstractArrayBox {
+public:
+ AbstractArrayBox() = default;
+ AbstractArrayBox(llvm::ArrayRef<mlir::Value> extents,
+ llvm::ArrayRef<mlir::Value> lbounds)
+ : extents{extents.begin(), extents.end()}, lbounds{lbounds.begin(),
+ lbounds.end()} {}
+
+ // Every array has extents that describe its shape.
+ const llvm::SmallVectorImpl<mlir::Value> &getExtents() const {
+ return extents;
+ }
+
+ // An array expression may have user-defined lower bound values.
+ // If this vector is empty, the default in all dimensions in `1`.
+ const llvm::SmallVectorImpl<mlir::Value> &getLBounds() const {
+ return lbounds;
+ }
+
+ bool lboundsAllOne() const { return lbounds.empty(); }
+
+protected:
+ llvm::SmallVector<mlir::Value, 4> extents;
+ llvm::SmallVector<mlir::Value, 4> lbounds;
+};
+
+/// Expressions with rank > 0 have extents. They may also have lbounds that are
+/// not 1.
+class ArrayBoxValue : public AbstractBox, public AbstractArrayBox {
+public:
+ ArrayBoxValue(mlir::Value addr, llvm::ArrayRef<mlir::Value> extents,
+ llvm::ArrayRef<mlir::Value> lbounds = {})
+ : AbstractBox{addr}, AbstractArrayBox{extents, lbounds} {}
+
+ ArrayBoxValue clone(mlir::Value newBase) const {
+ return {newBase, extents, lbounds};
+ }
+
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ const ArrayBoxValue &);
+ void dump() const { operator<<(llvm::errs(), *this); }
+};
+
+/// Expressions of type CHARACTER and with rank > 0.
+class CharArrayBoxValue : public CharBoxValue, public AbstractArrayBox {
+public:
+ CharArrayBoxValue(mlir::Value addr, mlir::Value len,
+ llvm::ArrayRef<mlir::Value> extents,
+ llvm::ArrayRef<mlir::Value> lbounds = {})
+ : CharBoxValue{addr, len}, AbstractArrayBox{extents, lbounds} {}
+
+ CharArrayBoxValue clone(mlir::Value newBase) const {
+ return {newBase, len, extents, lbounds};
+ }
+
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ const CharArrayBoxValue &);
+ void dump() const { operator<<(llvm::errs(), *this); }
+};
+
+/// Expressions that are procedure POINTERs may need a set of references to
+/// variables in the host scope.
+class ProcBoxValue : public AbstractBox {
+public:
+ ProcBoxValue(mlir::Value addr, mlir::Value context)
+ : AbstractBox{addr}, hostContext{context} {}
+
+ ProcBoxValue clone(mlir::Value newBase) const {
+ return {newBase, hostContext};
+ }
+
+ mlir::Value getHostContext() const { return hostContext; }
+
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ const ProcBoxValue &);
+ void dump() const { operator<<(llvm::errs(), *this); }
+
+protected:
+ mlir::Value hostContext;
+};
+
+/// In the generalized form, a boxed value can have a dynamic size, be an array
+/// with dynamic extents and lbounds, and take dynamic type parameters.
+class BoxValue : public AbstractBox, public AbstractArrayBox {
+public:
+ BoxValue(mlir::Value addr) : AbstractBox{addr}, AbstractArrayBox{} {}
+ BoxValue(mlir::Value addr, mlir::Value len)
+ : AbstractBox{addr}, AbstractArrayBox{}, len{len} {}
+ BoxValue(mlir::Value addr, llvm::ArrayRef<mlir::Value> extents,
+ llvm::ArrayRef<mlir::Value> lbounds = {})
+ : AbstractBox{addr}, AbstractArrayBox{extents, lbounds} {}
+ BoxValue(mlir::Value addr, mlir::Value len,
+ llvm::ArrayRef<mlir::Value> params,
+ llvm::ArrayRef<mlir::Value> extents,
+ llvm::ArrayRef<mlir::Value> lbounds = {})
+ : AbstractBox{addr}, AbstractArrayBox{extents, lbounds}, len{len},
+ params{params.begin(), params.end()} {}
+
+ BoxValue clone(mlir::Value newBase) const {
+ return {newBase, len, params, extents, lbounds};
+ }
+
+ mlir::Value getLen() const { return len; }
+ const llvm::SmallVectorImpl<mlir::Value> &getLenTypeParams() const {
+ return params;
+ }
+
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const BoxValue &);
+ void dump() const { operator<<(llvm::errs(), *this); }
+
+protected:
+ mlir::Value len;
+ llvm::SmallVector<mlir::Value, 2> params;
+};
+
+/// Used for triple notation (array slices)
+using RangeBoxValue = std::tuple<mlir::Value, mlir::Value, mlir::Value>;
+
+class ExtendedValue;
+
+mlir::Value getBase(const ExtendedValue &exv);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ExtendedValue &);
+ExtendedValue substBase(const ExtendedValue &exv, mlir::Value base);
+
+/// An extended value is a box of values pertaining to a discrete entity. It is
+/// used in lowering to track all the runtime values related to an entity. For
+/// example, an entity may have an address in memory that contains its value(s)
+/// as well as various attribute values that describe the shape and starting
+/// indices if it is an array entity.
+class ExtendedValue {
+public:
+ template <typename A>
+ constexpr ExtendedValue(A &&box) : box{std::forward<A>(box)} {}
+
+ constexpr const CharBoxValue *getCharBox() const {
+ return std::get_if<CharBoxValue>(&box);
+ }
+
+ constexpr const UnboxedValue *getUnboxed() const {
+ return std::get_if<UnboxedValue>(&box);
+ }
+
+ /// LLVM style debugging of extended values
+ void dump() const { llvm::errs() << *this << '\n'; }
+
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ const ExtendedValue &);
+ friend mlir::Value getBase(const ExtendedValue &exv);
+ friend ExtendedValue substBase(const ExtendedValue &exv, mlir::Value base);
+
+private:
+ std::variant<UnboxedValue, CharBoxValue, ArrayBoxValue, CharArrayBoxValue,
+ BoxValue, ProcBoxValue>
+ box;
+};
+} // namespace fir
+
+#endif // LOWER_SUPPORT_BOXVALUE_H
mlir::Value getAddr() const {
return std::visit(common::visitors{
[](const None &) { return mlir::Value{}; },
- [](const auto &x) { return x.addr; },
+ [](const auto &x) { return x.getAddr(); },
},
box);
}
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 Char &x) { return T{x.getLen()}; },
+ [](const CharFullDim &x) { return T{x.getLen()}; },
[](const auto &) { return T{}; },
},
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);
+ 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->lbounds.empty();
+ return arr->getLBounds().empty();
if (auto *arr = std::get_if<CharFullDim>(&box))
- return arr->lbounds.empty();
+ return arr->getLBounds().empty();
if (auto *arr = std::get_if<Derived>(&box))
- return (arr->extents.size() > 0) && arr->lbounds.empty();
+ return (arr->getExtents().size() > 0) && arr->getLBounds().empty();
return false;
}
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 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);
}