Skip to content

Commit

Permalink
[flang] Add BoxValue.h
Browse files Browse the repository at this point in the history
The bridge uses internal boxes of related ssa-values to track all the
information associated with a Fortran variable. Variables may have a
location and a value, but may also carry other properties such as rank,
shape, LEN parameters, etc. in Fortran.

Differential revision: https://reviews.llvm.org/D82228
  • Loading branch information
schweitzpgi committed Jun 20, 2020
1 parent 8116d01 commit b938eae
Show file tree
Hide file tree
Showing 2 changed files with 254 additions and 16 deletions.
237 changes: 237 additions & 0 deletions flang/include/flang/Lower/Support/BoxValue.h
Original file line number Diff line number Diff line change
@@ -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 <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
33 changes: 17 additions & 16 deletions flang/lib/Lower/SymbolMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ struct SymbolBox {
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);
}
Expand All @@ -90,8 +90,8 @@ struct SymbolBox {
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);
Expand All @@ -109,23 +109,24 @@ struct SymbolBox {

/// 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;
}

Expand All @@ -141,9 +142,9 @@ struct SymbolBox {
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);
}
Expand Down

0 comments on commit b938eae

Please sign in to comment.