blob: 0d5dec97ef097eb2035d7e967bf9ab58532c5eb4 [file] [log] [blame]
//===-- 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/Compiler.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 &);
LLVM_DUMP_METHOD 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 &);
LLVM_DUMP_METHOD 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 &);
LLVM_DUMP_METHOD 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 &);
LLVM_DUMP_METHOD 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 &);
LLVM_DUMP_METHOD 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
LLVM_DUMP_METHOD 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