forked from OSchip/llvm-project
[flang] Begin shape analysis
Original-commit: flang-compiler/f18@888166c97e Reviewed-on: https://github.com/flang-compiler/f18/pull/386 Tree-same-pre-rewrite: false
This commit is contained in:
parent
89a219488c
commit
47f8713854
|
@ -28,6 +28,7 @@ add_library(FortranEvaluate
|
|||
intrinsics-library.cc
|
||||
logical.cc
|
||||
real.cc
|
||||
shape.cc
|
||||
static-data.cc
|
||||
tools.cc
|
||||
type.cc
|
||||
|
|
|
@ -210,16 +210,23 @@ public:
|
|||
Visit(aref.subscript());
|
||||
}
|
||||
|
||||
void Descend(const CoarrayRef::BasePartRef &part) {
|
||||
Visit(*part.symbol);
|
||||
Visit(part.subscript);
|
||||
}
|
||||
void Descend(CoarrayRef::BasePartRef &part) {
|
||||
Visit(*part.symbol);
|
||||
Visit(part.subscript);
|
||||
}
|
||||
|
||||
void Descend(const CoarrayRef &caref) {
|
||||
Visit(caref.base());
|
||||
Visit(caref.subscript());
|
||||
Visit(caref.baseDataRef());
|
||||
Visit(caref.cosubscript());
|
||||
Visit(caref.stat());
|
||||
Visit(caref.team());
|
||||
}
|
||||
void Descend(CoarrayRef &caref) {
|
||||
Visit(caref.base());
|
||||
Visit(caref.subscript());
|
||||
Visit(caref.baseDataRef());
|
||||
Visit(caref.cosubscript());
|
||||
Visit(caref.stat());
|
||||
Visit(caref.team());
|
||||
|
|
|
@ -533,12 +533,15 @@ private:
|
|||
Power<Result>, Extremum<Result>>;
|
||||
using Indices = std::conditional_t<KIND == ImpliedDoIndex::Result::kind,
|
||||
std::tuple<ImpliedDoIndex>, std::tuple<>>;
|
||||
using DescriptorInquiries =
|
||||
std::conditional_t<KIND == DescriptorInquiry::Result::kind,
|
||||
std::tuple<DescriptorInquiry>, std::tuple<>>;
|
||||
using Others = std::tuple<Constant<Result>, ArrayConstructor<Result>,
|
||||
TypeParamInquiry<KIND>, Designator<Result>, FunctionRef<Result>>;
|
||||
|
||||
public:
|
||||
common::TupleToVariant<
|
||||
common::CombineTuples<Operations, Conversions, Indices, Others>>
|
||||
common::TupleToVariant<common::CombineTuples<Operations, Conversions, Indices,
|
||||
DescriptorInquiries, Others>>
|
||||
u;
|
||||
};
|
||||
|
||||
|
|
|
@ -113,16 +113,19 @@ ArrayRef FoldOperation(FoldingContext &context, ArrayRef &&arrayRef) {
|
|||
}
|
||||
|
||||
CoarrayRef FoldOperation(FoldingContext &context, CoarrayRef &&coarrayRef) {
|
||||
auto base{coarrayRef.base()};
|
||||
std::vector<Expr<SubscriptInteger>> subscript, cosubscript;
|
||||
for (Expr<SubscriptInteger> x : coarrayRef.subscript()) {
|
||||
subscript.emplace_back(Fold(context, std::move(x)));
|
||||
CoarrayRef::BaseDataRef baseDataRef;
|
||||
for (auto &&part : std::move(coarrayRef.baseDataRef())) {
|
||||
baseDataRef.emplace_back(*coarrayRef.baseDataRef().front().symbol);
|
||||
for (auto &&subscript : std::move(part.subscript)) {
|
||||
baseDataRef.back().subscript.emplace_back(
|
||||
Fold(context, std::move(subscript)));
|
||||
}
|
||||
}
|
||||
std::vector<Expr<SubscriptInteger>> cosubscript;
|
||||
for (Expr<SubscriptInteger> x : coarrayRef.cosubscript()) {
|
||||
cosubscript.emplace_back(Fold(context, std::move(x)));
|
||||
}
|
||||
CoarrayRef folded{
|
||||
std::move(base), std::move(subscript), std::move(cosubscript)};
|
||||
CoarrayRef folded{std::move(baseDataRef), std::move(cosubscript)};
|
||||
if (std::optional<Expr<SomeInteger>> stat{coarrayRef.stat()}) {
|
||||
folded.set_stat(Fold(context, std::move(*stat)));
|
||||
}
|
||||
|
|
|
@ -510,18 +510,24 @@ std::ostream &ArrayRef::AsFortran(std::ostream &o) const {
|
|||
}
|
||||
|
||||
std::ostream &CoarrayRef::AsFortran(std::ostream &o) const {
|
||||
for (const Symbol *sym : base_) {
|
||||
EmitVar(o, *sym);
|
||||
bool first{true};
|
||||
for (const auto &part : baseDataRef_) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
o << '%';
|
||||
}
|
||||
EmitVar(o, *part.symbol);
|
||||
char ch{'('};
|
||||
for (const auto &sscript : part.subscript) {
|
||||
EmitVar(o << ch, sscript);
|
||||
ch = ',';
|
||||
}
|
||||
if (ch == ',') {
|
||||
o << ')';
|
||||
}
|
||||
}
|
||||
char separator{'('};
|
||||
for (const auto &ss : subscript_) {
|
||||
EmitVar(o << separator, ss);
|
||||
separator = ',';
|
||||
}
|
||||
if (separator == ',') {
|
||||
o << ')';
|
||||
}
|
||||
separator = '[';
|
||||
char separator{'['};
|
||||
for (const auto &css : cosubscript_) {
|
||||
EmitVar(o << separator, css);
|
||||
separator = ',';
|
||||
|
@ -566,6 +572,28 @@ std::ostream &Designator<T>::AsFortran(std::ostream &o) const {
|
|||
return o;
|
||||
}
|
||||
|
||||
std::ostream &DescriptorInquiry::AsFortran(std::ostream &o) const {
|
||||
switch (field_) {
|
||||
case Field::LowerBound: o << "lbound("; break;
|
||||
case Field::Extent: o << "%EXTENT("; break;
|
||||
case Field::Stride: o << "%STRIDE("; break;
|
||||
}
|
||||
std::visit(
|
||||
common::visitors{
|
||||
[&](const Symbol *sym) {
|
||||
if (sym != nullptr) {
|
||||
EmitVar(o, *sym);
|
||||
}
|
||||
},
|
||||
[&](const Component &comp) { EmitVar(o, comp); },
|
||||
},
|
||||
base_);
|
||||
if (dimension_ > 0) {
|
||||
o << ",dim=" << dimension_;
|
||||
}
|
||||
return o << ')';
|
||||
}
|
||||
|
||||
INSTANTIATE_CONSTANT_TEMPLATES
|
||||
INSTANTIATE_EXPRESSION_TEMPLATES
|
||||
INSTANTIATE_VARIABLE_TEMPLATES
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "shape.h"
|
||||
#include "fold.h"
|
||||
#include "tools.h"
|
||||
#include "../common/idioms.h"
|
||||
#include "../semantics/symbol.h"
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
std::optional<Shape> GetShape(
|
||||
const semantics::Symbol &symbol, const Component *component) {
|
||||
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
Shape result;
|
||||
int dimension{1};
|
||||
for (const auto &shapeSpec : details->shape()) {
|
||||
if (shapeSpec.isExplicit()) {
|
||||
result.emplace_back(
|
||||
common::Clone(shapeSpec.ubound().GetExplicit().value()) -
|
||||
common::Clone(shapeSpec.lbound().GetExplicit().value()) +
|
||||
Expr<SubscriptInteger>{1});
|
||||
} else if (component != nullptr) {
|
||||
result.emplace_back(Expr<SubscriptInteger>{DescriptorInquiry{
|
||||
*component, DescriptorInquiry::Field::Extent, dimension}});
|
||||
} else {
|
||||
result.emplace_back(Expr<SubscriptInteger>{DescriptorInquiry{
|
||||
symbol, DescriptorInquiry::Field::Extent, dimension}});
|
||||
}
|
||||
++dimension;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Shape> GetShape(const Component &component) {
|
||||
const Symbol &symbol{component.GetLastSymbol()};
|
||||
if (symbol.Rank() > 0) {
|
||||
return GetShape(symbol, &component);
|
||||
} else {
|
||||
return GetShape(component.base());
|
||||
}
|
||||
}
|
||||
static Extent GetExtent(const Subscript &subscript) {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[](const Triplet &triplet) -> Extent {
|
||||
if (auto lower{triplet.lower()}) {
|
||||
if (auto lowerValue{ToInt64(*lower)}) {
|
||||
if (auto upper{triplet.upper()}) {
|
||||
if (auto upperValue{ToInt64(*upper)}) {
|
||||
if (auto strideValue{ToInt64(triplet.stride())}) {
|
||||
if (*strideValue != 0) {
|
||||
std::int64_t extent{
|
||||
(*upperValue - *lowerValue + *strideValue) /
|
||||
*strideValue};
|
||||
return Expr<SubscriptInteger>{extent > 0 ? extent : 0};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
},
|
||||
[](const IndirectSubscriptIntegerExpr &subs) -> Extent {
|
||||
if (auto shape{GetShape(subs.value())}) {
|
||||
if (shape->size() == 1) {
|
||||
return std::move(shape->at(0));
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
},
|
||||
},
|
||||
subscript.u);
|
||||
}
|
||||
std::optional<Shape> GetShape(const ArrayRef &arrayRef) {
|
||||
int subscripts{arrayRef.size()};
|
||||
Shape shape;
|
||||
for (int j = 0; j < subscripts; ++j) {
|
||||
const Subscript &subscript{arrayRef.at(j)};
|
||||
if (subscript.Rank() > 0) {
|
||||
shape.emplace_back(GetExtent(subscript));
|
||||
}
|
||||
}
|
||||
if (shape.empty()) {
|
||||
return GetShape(arrayRef.base());
|
||||
} else {
|
||||
return shape;
|
||||
}
|
||||
}
|
||||
std::optional<Shape> GetShape(const CoarrayRef &); // TODO pmk
|
||||
std::optional<Shape> GetShape(const DataRef &dataRef) {
|
||||
return std::visit([](const auto &x) { return GetShape(x); }, dataRef.u);
|
||||
}
|
||||
std::optional<Shape> GetShape(const Substring &substring) {
|
||||
if (const auto *dataRef{substring.GetParentIf<DataRef>()}) {
|
||||
return GetShape(*dataRef);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
std::optional<Shape> GetShape(const ComplexPart &part) {
|
||||
return GetShape(part.complex());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// GetShape() analyzes an expression and determines its shape, if possible,
|
||||
// representing the result as a vector of scalar integer expressions.
|
||||
|
||||
#ifndef FORTRAN_EVALUATE_SHAPE_H_
|
||||
#define FORTRAN_EVALUATE_SHAPE_H_
|
||||
|
||||
#include "expression.h"
|
||||
#include "type.h"
|
||||
#include "../common/indirection.h"
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
using Extent = std::optional<Expr<SubscriptInteger>>;
|
||||
using Shape = std::vector<Extent>;
|
||||
|
||||
template<typename A> std::optional<Shape> GetShape(const A &) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename T> std::optional<Shape> GetShape(const Expr<T> &);
|
||||
|
||||
template<typename A, bool COPY>
|
||||
std::optional<Shape> GetShape(const common::Indirection<A, COPY> &p) {
|
||||
return GetShape(p.value());
|
||||
}
|
||||
|
||||
template<typename A> std::optional<Shape> GetShape(const std::optional<A> &x) {
|
||||
if (x.has_value()) {
|
||||
return GetShape(*x);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... A>
|
||||
std::optional<Shape> GetShape(const std::variant<A...> &u) {
|
||||
return std::visit([](const auto &x) { return GetShape(x); }, u);
|
||||
}
|
||||
|
||||
std::optional<Shape> GetShape(
|
||||
const semantics::Symbol &, const Component * = nullptr);
|
||||
std::optional<Shape> GetShape(const DataRef &);
|
||||
std::optional<Shape> GetShape(const ComplexPart &);
|
||||
std::optional<Shape> GetShape(const Substring &);
|
||||
std::optional<Shape> GetShape(const Component &);
|
||||
std::optional<Shape> GetShape(const ArrayRef &);
|
||||
std::optional<Shape> GetShape(const CoarrayRef &);
|
||||
|
||||
template<typename T>
|
||||
std::optional<Shape> GetShape(const Designator<T> &designator) {
|
||||
return std::visit([](const auto &x) { return GetShape(x); }, designator.u);
|
||||
}
|
||||
|
||||
template<typename T> std::optional<Shape> GetShape(const Expr<T> &expr) {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[](const BOZLiteralConstant &) { return Shape{}; },
|
||||
[](const NullPointer &) { return std::nullopt; },
|
||||
[](const auto &x) { return GetShape(x); },
|
||||
},
|
||||
expr.u);
|
||||
}
|
||||
}
|
||||
#endif // FORTRAN_EVALUATE_SHAPE_H_
|
|
@ -69,12 +69,14 @@ bool Triplet::IsStrideOne() const {
|
|||
}
|
||||
}
|
||||
|
||||
CoarrayRef::CoarrayRef(std::vector<const Symbol *> &&c,
|
||||
std::vector<Expr<SubscriptInteger>> &&ss,
|
||||
std::vector<Expr<SubscriptInteger>> &&css)
|
||||
: base_(std::move(c)), subscript_(std::move(ss)),
|
||||
cosubscript_(std::move(css)) {
|
||||
CHECK(!base_.empty());
|
||||
bool CoarrayRef::BasePartRef::operator==(const BasePartRef &that) const {
|
||||
return symbol == that.symbol && subscript == that.subscript;
|
||||
}
|
||||
|
||||
CoarrayRef::CoarrayRef(
|
||||
CoarrayRef::BaseDataRef &&base, std::vector<Expr<SubscriptInteger>> &&css)
|
||||
: baseDataRef_{std::move(base)}, cosubscript_(std::move(css)) {
|
||||
CHECK(!baseDataRef_.empty());
|
||||
}
|
||||
|
||||
std::optional<Expr<SomeInteger>> CoarrayRef::stat() const {
|
||||
|
@ -106,6 +108,14 @@ CoarrayRef &CoarrayRef::set_team(Expr<SomeInteger> &&v, bool isTeamNumber) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
const Symbol &CoarrayRef::GetFirstSymbol() const {
|
||||
return *baseDataRef_.front().symbol;
|
||||
}
|
||||
|
||||
const Symbol &CoarrayRef::GetLastSymbol() const {
|
||||
return *baseDataRef_.back().symbol;
|
||||
}
|
||||
|
||||
void Substring::SetBounds(std::optional<Expr<SubscriptInteger>> &lower,
|
||||
std::optional<Expr<SubscriptInteger>> &upper) {
|
||||
if (lower.has_value()) {
|
||||
|
@ -213,6 +223,31 @@ std::optional<Expr<SomeCharacter>> Substring::Fold(FoldingContext &context) {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
DescriptorInquiry::DescriptorInquiry(const Symbol &symbol, Field field, int dim)
|
||||
: base_{&symbol}, field_{field}, dimension_{dim} {
|
||||
CHECK(IsDescriptor(symbol));
|
||||
CHECK(dim >= 1 && dim <= symbol.Rank());
|
||||
}
|
||||
DescriptorInquiry::DescriptorInquiry(
|
||||
Component &&component, Field field, int dim)
|
||||
: base_{std::move(component)}, field_{field}, dimension_{dim} {
|
||||
const Symbol &symbol{std::get<Component>(base_).GetLastSymbol()};
|
||||
CHECK(IsDescriptor(symbol));
|
||||
CHECK(dim >= 1 && dim <= symbol.Rank());
|
||||
}
|
||||
DescriptorInquiry::DescriptorInquiry(
|
||||
SymbolOrComponent &&x, Field field, int dim)
|
||||
: base_{std::move(x)}, field_{field}, dimension_{dim} {
|
||||
const Symbol *symbol{std::visit(
|
||||
common::visitors{
|
||||
[](const Symbol *s) { return s; },
|
||||
[](Component &c) { return &c.GetLastSymbol(); },
|
||||
},
|
||||
base_)};
|
||||
CHECK(symbol != nullptr && IsDescriptor(*symbol));
|
||||
CHECK(dim >= 1 && dim <= symbol->Rank());
|
||||
}
|
||||
|
||||
// LEN()
|
||||
static Expr<SubscriptInteger> SymbolLEN(const Symbol &sym) {
|
||||
return AsExpr(Constant<SubscriptInteger>{0}); // TODO
|
||||
|
@ -243,7 +278,7 @@ Expr<SubscriptInteger> ArrayRef::LEN() const {
|
|||
}
|
||||
|
||||
Expr<SubscriptInteger> CoarrayRef::LEN() const {
|
||||
return SymbolLEN(*base_.back());
|
||||
return SymbolLEN(GetLastSymbol());
|
||||
}
|
||||
|
||||
Expr<SubscriptInteger> DataRef::LEN() const {
|
||||
|
@ -333,14 +368,6 @@ int ArrayRef::Rank() const {
|
|||
base_);
|
||||
}
|
||||
|
||||
int CoarrayRef::Rank() const {
|
||||
int rank{0};
|
||||
for (const auto &expr : subscript_) {
|
||||
rank += expr.Rank();
|
||||
}
|
||||
return rank;
|
||||
}
|
||||
|
||||
int DataRef::Rank() const {
|
||||
return std::visit(
|
||||
// g++ 7.2 emits bogus warnings here and below when common::visitors{}
|
||||
|
@ -504,7 +531,7 @@ bool ArrayRef::operator==(const ArrayRef &that) const {
|
|||
return base_ == that.base_ && subscript_ == that.subscript_;
|
||||
}
|
||||
bool CoarrayRef::operator==(const CoarrayRef &that) const {
|
||||
return base_ == that.base_ && subscript_ == that.subscript_ &&
|
||||
return baseDataRef_ == that.baseDataRef_ &&
|
||||
cosubscript_ == that.cosubscript_ && stat_ == that.stat_ &&
|
||||
team_ == that.team_ && teamIsTeamNumber_ == that.teamIsTeamNumber_;
|
||||
}
|
||||
|
@ -518,6 +545,10 @@ bool ComplexPart::operator==(const ComplexPart &that) const {
|
|||
bool ProcedureRef::operator==(const ProcedureRef &that) const {
|
||||
return proc_ == that.proc_ && arguments_ == that.arguments_;
|
||||
}
|
||||
bool DescriptorInquiry::operator==(const DescriptorInquiry &that) const {
|
||||
return field_ == that.field_ && base_ == that.base_ &&
|
||||
dimension_ == that.dimension_;
|
||||
}
|
||||
|
||||
INSTANTIATE_VARIABLE_TEMPLATES
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ struct BaseObject {
|
|||
// R913 structure-component & C920: Defined to be a multi-part
|
||||
// data-ref whose last part has no subscripts (or image-selector, although
|
||||
// that isn't explicit in the document). Pointer and allocatable components
|
||||
// are not explicitly indirected in this representation (TODO: yet?)
|
||||
// are not explicitly indirected in this representation.
|
||||
// Complex components (%RE, %IM) are isolated below in ComplexPart.
|
||||
// (Type parameter inquiries look like component references but are distinct
|
||||
// constructs and not represented by this class.)
|
||||
|
@ -204,22 +204,35 @@ private:
|
|||
// C824 severely limits the usage of derived types with coarray ultimate
|
||||
// components: they can't be pointers, allocatables, arrays, coarrays, or
|
||||
// function results. They can be components of other derived types.
|
||||
// Although the F'2018 Standard never prohibits multiple image-selectors
|
||||
// in the same data-ref or designator, nor the presence of an image-selector
|
||||
// after a part-ref with rank, the constraints on the derived types that
|
||||
// would have be involved make it impossible to declare an object that
|
||||
// could be referenced in these ways.
|
||||
// C930 precludes having both TEAM= and TEAM_NUMBER=.
|
||||
// TODO C931 prohibits the use of a coindexed object as a stat-variable.
|
||||
class CoarrayRef {
|
||||
public:
|
||||
CLASS_BOILERPLATE(CoarrayRef)
|
||||
CoarrayRef(std::vector<const Symbol *> &&,
|
||||
std::vector<Expr<SubscriptInteger>> &&,
|
||||
std::vector<Expr<SubscriptInteger>> &&);
|
||||
struct BasePartRef {
|
||||
explicit BasePartRef(const Symbol &s) : symbol{&s} {}
|
||||
BasePartRef(const Symbol &s, std::vector<Expr<SubscriptInteger>> &&ss)
|
||||
: symbol{&s}, subscript{std::move(ss)} {}
|
||||
CLASS_BOILERPLATE(BasePartRef)
|
||||
bool operator==(const BasePartRef &) const;
|
||||
const Symbol *symbol;
|
||||
std::vector<Expr<SubscriptInteger>> subscript;
|
||||
};
|
||||
using BaseDataRef = std::vector<BasePartRef>;
|
||||
|
||||
const std::vector<const Symbol *> &base() const { return base_; }
|
||||
const std::vector<Expr<SubscriptInteger>> &subscript() const {
|
||||
return subscript_;
|
||||
}
|
||||
CLASS_BOILERPLATE(CoarrayRef)
|
||||
CoarrayRef(BaseDataRef &&, std::vector<Expr<SubscriptInteger>> &&);
|
||||
|
||||
const BaseDataRef &baseDataRef() const { return baseDataRef_; }
|
||||
BaseDataRef &baseDataRef() { return baseDataRef_; }
|
||||
const std::vector<Expr<SubscriptInteger>> &cosubscript() const {
|
||||
return cosubscript_;
|
||||
}
|
||||
std::vector<Expr<SubscriptInteger>> &cosubscript() { return cosubscript_; }
|
||||
|
||||
// These integral expressions for STAT= and TEAM= must be variables
|
||||
// (i.e., Designator or pointer-valued FunctionRef).
|
||||
|
@ -229,16 +242,16 @@ public:
|
|||
bool teamIsTeamNumber() const { return teamIsTeamNumber_; }
|
||||
CoarrayRef &set_team(Expr<SomeInteger> &&, bool isTeamNumber = false);
|
||||
|
||||
int Rank() const;
|
||||
const Symbol &GetFirstSymbol() const { return *base_.front(); }
|
||||
const Symbol &GetLastSymbol() const { return *base_.back(); }
|
||||
int Rank() const { return 0; }
|
||||
const Symbol &GetFirstSymbol() const;
|
||||
const Symbol &GetLastSymbol() const;
|
||||
Expr<SubscriptInteger> LEN() const;
|
||||
bool operator==(const CoarrayRef &) const;
|
||||
std::ostream &AsFortran(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::vector<const Symbol *> base_;
|
||||
std::vector<Expr<SubscriptInteger>> subscript_, cosubscript_;
|
||||
BaseDataRef baseDataRef_;
|
||||
std::vector<Expr<SubscriptInteger>> cosubscript_;
|
||||
std::optional<common::CopyableIndirection<Expr<SomeInteger>>> stat_, team_;
|
||||
bool teamIsTeamNumber_{false}; // false: TEAM=, true: TEAM_NUMBER=
|
||||
};
|
||||
|
@ -375,9 +388,35 @@ template<typename T> struct Variable {
|
|||
std::variant<Designator<Result>, FunctionRef<Result>> u;
|
||||
};
|
||||
|
||||
class DescriptorInquiry {
|
||||
public:
|
||||
using Result = SubscriptInteger;
|
||||
ENUM_CLASS(Field, LowerBound, Extent, Stride)
|
||||
// TODO: Also type parameters and/or CHARACTER length?
|
||||
|
||||
CLASS_BOILERPLATE(DescriptorInquiry)
|
||||
DescriptorInquiry(const Symbol &, Field, int);
|
||||
DescriptorInquiry(Component &&, Field, int);
|
||||
DescriptorInquiry(SymbolOrComponent &&, Field, int);
|
||||
|
||||
SymbolOrComponent &base() { return base_; }
|
||||
const SymbolOrComponent &base() const { return base_; }
|
||||
Field field() const { return field_; }
|
||||
int dimension() const { return dimension_; }
|
||||
|
||||
static constexpr int Rank() { return 0; } // always scalar
|
||||
bool operator==(const DescriptorInquiry &) const;
|
||||
std::ostream &AsFortran(std::ostream &) const;
|
||||
|
||||
private:
|
||||
SymbolOrComponent base_{nullptr};
|
||||
Field field_;
|
||||
int dimension_{0};
|
||||
};
|
||||
|
||||
#define INSTANTIATE_VARIABLE_TEMPLATES \
|
||||
EXPAND_FOR_EACH_INTEGER_KIND( \
|
||||
TEMPLATE_INSTANTIATION, template class TypeParamInquiry, ) \
|
||||
EXPAND_FOR_EACH_INTEGER_KIND( \
|
||||
TEMPLATE_INSTANTIATION, template class TypeParamInquiry, ) \
|
||||
FOR_EACH_SPECIFIC_TYPE(template class Designator, )
|
||||
}
|
||||
#endif // FORTRAN_EVALUATE_VARIABLE_H_
|
||||
|
|
Loading…
Reference in New Issue