diff --git a/flang/include/flang/Lower/Support/BoxValue.h b/flang/include/flang/Lower/Support/BoxValue.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Lower/Support/BoxValue.h @@ -0,0 +1,237 @@ +//===-- 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 +#include + +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 extents, + llvm::ArrayRef lbounds) + : extents{extents.begin(), extents.end()}, lbounds{lbounds.begin(), + lbounds.end()} {} + + // Every array has extents that describe its shape. + const llvm::SmallVectorImpl &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 &getLBounds() const { + return lbounds; + } + + bool lboundsAllOne() const { return lbounds.empty(); } + +protected: + llvm::SmallVector extents; + llvm::SmallVector 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 extents, + llvm::ArrayRef 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 extents, + llvm::ArrayRef 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 extents, + llvm::ArrayRef lbounds = {}) + : AbstractBox{addr}, AbstractArrayBox{extents, lbounds} {} + BoxValue(mlir::Value addr, mlir::Value len, + llvm::ArrayRef params, + llvm::ArrayRef extents, + llvm::ArrayRef 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 &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 params; +}; + +/// Used for triple notation (array slices) +using RangeBoxValue = std::tuple; + +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 + constexpr ExtendedValue(A &&box) : box{std::forward(box)} {} + + constexpr const CharBoxValue *getCharBox() const { + return std::get_if(&box); + } + + constexpr const UnboxedValue *getUnboxed() const { + return std::get_if(&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 + box; +}; +} // namespace fir + +#endif // LOWER_SUPPORT_BOXVALUE_H diff --git a/flang/lib/Lower/SymbolMap.h b/flang/lib/Lower/SymbolMap.h --- a/flang/lib/Lower/SymbolMap.h +++ b/flang/lib/Lower/SymbolMap.h @@ -81,7 +81,7 @@ 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); } @@ -90,8 +90,8 @@ llvm::Optional getCharLen() const { using T = llvm::Optional; 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); @@ -109,23 +109,24 @@ /// 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(&box)) - return arr->lbounds.empty(); + return arr->getLBounds().empty(); if (auto *arr = std::get_if(&box)) - return arr->lbounds.empty(); + return arr->getLBounds().empty(); if (auto *arr = std::get_if(&box)) - return (arr->extents.size() > 0) && arr->lbounds.empty(); + return (arr->getExtents().size() > 0) && arr->getLBounds().empty(); return false; } @@ -141,9 +142,9 @@ 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); }