forked from OSchip/llvm-project
[flang] Put templates back into implementation header
Original-commit: flang-compiler/f18@8949924351 Reviewed-on: https://github.com/flang-compiler/f18/pull/900 Tree-same-pre-rewrite: false
This commit is contained in:
parent
8deb4bbeb7
commit
ceb8196023
|
@ -45,6 +45,7 @@
|
|||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
// Utilities
|
||||
template<typename T> class Folder {
|
||||
public:
|
||||
explicit Folder(FoldingContext &c) : context_{c} {}
|
||||
|
@ -63,7 +64,6 @@ public:
|
|||
private:
|
||||
FoldingContext &context_;
|
||||
};
|
||||
FOR_EACH_SPECIFIC_TYPE(extern template class Folder, )
|
||||
|
||||
// FoldOperation() rewrites expression tree nodes.
|
||||
// If there is any possibility that the rewritten node will
|
||||
|
@ -119,6 +119,357 @@ template<typename T>
|
|||
Expr<T> FoldOperation(FoldingContext &, ArrayConstructor<T> &&);
|
||||
Expr<SomeDerived> FoldOperation(FoldingContext &, StructureConstructor &&);
|
||||
|
||||
template<typename T>
|
||||
std::optional<Expr<T>> Folder<T>::GetNamedConstantValue(const Symbol &symbol0) {
|
||||
const Symbol &symbol{ResolveAssociations(symbol0).GetUltimate()};
|
||||
if (IsNamedConstant(symbol)) {
|
||||
if (const auto *object{
|
||||
symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
if (object->initWasValidated()) {
|
||||
const auto *constant{UnwrapConstantValue<T>(object->init())};
|
||||
return Expr<T>{DEREF(constant)};
|
||||
}
|
||||
if (const auto &init{object->init()}) {
|
||||
if (auto dyType{DynamicType::From(symbol)}) {
|
||||
semantics::ObjectEntityDetails *mutableObject{
|
||||
const_cast<semantics::ObjectEntityDetails *>(object)};
|
||||
auto converted{
|
||||
ConvertToType(*dyType, std::move(mutableObject->init().value()))};
|
||||
// Reset expression now to prevent infinite loops if the init
|
||||
// expression depends on symbol itself.
|
||||
mutableObject->set_init(std::nullopt);
|
||||
if (converted) {
|
||||
*converted = Fold(context_, std::move(*converted));
|
||||
auto *unwrapped{UnwrapExpr<Expr<T>>(*converted)};
|
||||
CHECK(unwrapped);
|
||||
if (auto *constant{UnwrapConstantValue<T>(*unwrapped)}) {
|
||||
if (symbol.Rank() > 0) {
|
||||
if (constant->Rank() == 0) {
|
||||
// scalar expansion
|
||||
if (auto symShape{GetShape(context_, symbol)}) {
|
||||
if (auto extents{AsConstantExtents(context_, *symShape)}) {
|
||||
*constant = constant->Reshape(std::move(*extents));
|
||||
CHECK(constant->Rank() == symbol.Rank());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (constant->Rank() == symbol.Rank()) {
|
||||
NamedEntity base{symbol};
|
||||
if (auto lbounds{AsConstantExtents(
|
||||
context_, GetLowerBounds(context_, base))}) {
|
||||
constant->set_lbounds(*std::move(lbounds));
|
||||
}
|
||||
}
|
||||
}
|
||||
mutableObject->set_init(AsGenericExpr(Expr<T>{*constant}));
|
||||
if (auto constShape{GetShape(context_, *constant)}) {
|
||||
if (auto symShape{GetShape(context_, symbol)}) {
|
||||
if (CheckConformance(context_.messages(), *constShape,
|
||||
*symShape, "initialization expression",
|
||||
"PARAMETER")) {
|
||||
mutableObject->set_initWasValidated();
|
||||
return std::move(*unwrapped);
|
||||
}
|
||||
} else {
|
||||
context_.messages().Say(symbol.name(),
|
||||
"Could not determine the shape of the PARAMETER"_err_en_US);
|
||||
}
|
||||
} else {
|
||||
context_.messages().Say(symbol.name(),
|
||||
"Could not determine the shape of the initialization expression"_err_en_US);
|
||||
}
|
||||
mutableObject->set_init(std::nullopt);
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
unwrapped->AsFortran(ss);
|
||||
context_.messages().Say(symbol.name(),
|
||||
"Initialization expression for PARAMETER '%s' (%s) cannot be computed as a constant value"_err_en_US,
|
||||
symbol.name(), ss.str());
|
||||
}
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
init->AsFortran(ss);
|
||||
context_.messages().Say(symbol.name(),
|
||||
"Initialization expression for PARAMETER '%s' (%s) cannot be converted to its type (%s)"_err_en_US,
|
||||
symbol.name(), ss.str(), dyType->AsFortran());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<Constant<T>> Folder<T>::GetFoldedNamedConstantValue(
|
||||
const Symbol &symbol) {
|
||||
if (auto value{GetNamedConstantValue(symbol)}) {
|
||||
Expr<T> folded{Fold(context_, std::move(*value))};
|
||||
if (const Constant<T> *value{UnwrapConstantValue<T>(folded)}) {
|
||||
return *value;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static std::optional<Constant<SubscriptInteger>> GetConstantSubscript(
|
||||
FoldingContext &context, Subscript &ss, const NamedEntity &base, int dim) {
|
||||
ss = FoldOperation(context, std::move(ss));
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[](IndirectSubscriptIntegerExpr &expr)
|
||||
-> std::optional<Constant<SubscriptInteger>> {
|
||||
if (auto constant{
|
||||
GetScalarConstantValue<SubscriptInteger>(expr.value())}) {
|
||||
return Constant<SubscriptInteger>{*constant};
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
},
|
||||
[&](Triplet &triplet) -> std::optional<Constant<SubscriptInteger>> {
|
||||
auto lower{triplet.lower()}, upper{triplet.upper()};
|
||||
std::optional<ConstantSubscript> stride{ToInt64(triplet.stride())};
|
||||
if (!lower) {
|
||||
lower = GetLowerBound(context, base, dim);
|
||||
}
|
||||
if (!upper) {
|
||||
upper =
|
||||
ComputeUpperBound(context, GetLowerBound(context, base, dim),
|
||||
GetExtent(context, base, dim));
|
||||
}
|
||||
auto lbi{ToInt64(lower)}, ubi{ToInt64(upper)};
|
||||
if (lbi && ubi && stride && *stride != 0) {
|
||||
std::vector<SubscriptInteger::Scalar> values;
|
||||
while ((*stride > 0 && *lbi <= *ubi) ||
|
||||
(*stride < 0 && *lbi >= *ubi)) {
|
||||
values.emplace_back(*lbi);
|
||||
*lbi += *stride;
|
||||
}
|
||||
return Constant<SubscriptInteger>{std::move(values),
|
||||
ConstantSubscripts{
|
||||
static_cast<ConstantSubscript>(values.size())}};
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
},
|
||||
},
|
||||
ss.u);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<Constant<T>> Folder<T>::Folding(ArrayRef &aRef) {
|
||||
std::vector<Constant<SubscriptInteger>> subscripts;
|
||||
int dim{0};
|
||||
for (Subscript &ss : aRef.subscript()) {
|
||||
if (auto constant{GetConstantSubscript(context_, ss, aRef.base(), dim++)}) {
|
||||
subscripts.emplace_back(std::move(*constant));
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
if (Component * component{aRef.base().UnwrapComponent()}) {
|
||||
return GetConstantComponent(*component, &subscripts);
|
||||
} else if (std::optional<Constant<T>> array{
|
||||
GetFoldedNamedConstantValue(aRef.base().GetLastSymbol())}) {
|
||||
return ApplySubscripts(*array, subscripts);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<Constant<T>> Folder<T>::ApplySubscripts(const Constant<T> &array,
|
||||
const std::vector<Constant<SubscriptInteger>> &subscripts) {
|
||||
const auto &shape{array.shape()};
|
||||
const auto &lbounds{array.lbounds()};
|
||||
int rank{GetRank(shape)};
|
||||
CHECK(rank == static_cast<int>(subscripts.size()));
|
||||
std::size_t elements{1};
|
||||
ConstantSubscripts resultShape;
|
||||
ConstantSubscripts ssLB;
|
||||
for (const auto &ss : subscripts) {
|
||||
CHECK(ss.Rank() <= 1);
|
||||
if (ss.Rank() == 1) {
|
||||
resultShape.push_back(static_cast<ConstantSubscript>(ss.size()));
|
||||
elements *= ss.size();
|
||||
ssLB.push_back(ss.lbounds().front());
|
||||
}
|
||||
}
|
||||
ConstantSubscripts ssAt(rank, 0), at(rank, 0), tmp(1, 0);
|
||||
std::vector<Scalar<T>> values;
|
||||
while (elements-- > 0) {
|
||||
bool increment{true};
|
||||
int k{0};
|
||||
for (int j{0}; j < rank; ++j) {
|
||||
if (subscripts[j].Rank() == 0) {
|
||||
at[j] = subscripts[j].GetScalarValue().value().ToInt64();
|
||||
} else {
|
||||
CHECK(k < GetRank(resultShape));
|
||||
tmp[0] = ssLB[j] + ssAt[j];
|
||||
at[j] = subscripts[j].At(tmp).ToInt64();
|
||||
if (increment) {
|
||||
if (++ssAt[j] == resultShape[k]) {
|
||||
ssAt[j] = 0;
|
||||
} else {
|
||||
increment = false;
|
||||
}
|
||||
}
|
||||
++k;
|
||||
}
|
||||
if (at[j] < lbounds[j] || at[j] >= lbounds[j] + shape[j]) {
|
||||
context_.messages().Say(
|
||||
"Subscript value (%jd) is out of range on dimension %d in reference to a constant array value"_err_en_US,
|
||||
static_cast<std::intmax_t>(at[j]), j + 1);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
values.emplace_back(array.At(at));
|
||||
CHECK(!increment || elements == 0);
|
||||
CHECK(k == GetRank(resultShape));
|
||||
}
|
||||
if constexpr (T::category == TypeCategory::Character) {
|
||||
return Constant<T>{array.LEN(), std::move(values), std::move(resultShape)};
|
||||
} else if constexpr (std::is_same_v<T, SomeDerived>) {
|
||||
return Constant<T>{array.result().derivedTypeSpec(), std::move(values),
|
||||
std::move(resultShape)};
|
||||
} else {
|
||||
return Constant<T>{std::move(values), std::move(resultShape)};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<Constant<T>> Folder<T>::ApplyComponent(
|
||||
Constant<SomeDerived> &&structures, const Symbol &component,
|
||||
const std::vector<Constant<SubscriptInteger>> *subscripts) {
|
||||
if (auto scalar{structures.GetScalarValue()}) {
|
||||
if (auto *expr{scalar->Find(component)}) {
|
||||
if (const Constant<T> *value{UnwrapConstantValue<T>(*expr)}) {
|
||||
if (!subscripts) {
|
||||
return std::move(*value);
|
||||
} else {
|
||||
return ApplySubscripts(*value, *subscripts);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// A(:)%scalar_component & A(:)%array_component(subscripts)
|
||||
std::unique_ptr<ArrayConstructor<T>> array;
|
||||
if (structures.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
ConstantSubscripts at{structures.lbounds()};
|
||||
do {
|
||||
StructureConstructor scalar{structures.At(at)};
|
||||
if (auto *expr{scalar.Find(component)}) {
|
||||
if (const Constant<T> *value{UnwrapConstantValue<T>(*expr)}) {
|
||||
if (!array.get()) {
|
||||
// This technique ensures that character length or derived type
|
||||
// information is propagated to the array constructor.
|
||||
auto *typedExpr{UnwrapExpr<Expr<T>>(*expr)};
|
||||
CHECK(typedExpr);
|
||||
array = std::make_unique<ArrayConstructor<T>>(*typedExpr);
|
||||
}
|
||||
if (subscripts) {
|
||||
if (auto element{ApplySubscripts(*value, *subscripts)}) {
|
||||
CHECK(element->Rank() == 0);
|
||||
array->Push(Expr<T>{std::move(*element)});
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
} else {
|
||||
CHECK(value->Rank() == 0);
|
||||
array->Push(Expr<T>{*value});
|
||||
}
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
} while (structures.IncrementSubscripts(at));
|
||||
// Fold the ArrayConstructor<> into a Constant<>.
|
||||
CHECK(array);
|
||||
Expr<T> result{Fold(context_, Expr<T>{std::move(*array)})};
|
||||
if (auto *constant{UnwrapConstantValue<T>(result)}) {
|
||||
return constant->Reshape(common::Clone(structures.shape()));
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<Constant<T>> Folder<T>::GetConstantComponent(Component &component,
|
||||
const std::vector<Constant<SubscriptInteger>> *subscripts) {
|
||||
if (std::optional<Constant<SomeDerived>> structures{std::visit(
|
||||
common::visitors{
|
||||
[&](const Symbol &symbol) {
|
||||
return Folder<SomeDerived>{context_}
|
||||
.GetFoldedNamedConstantValue(symbol);
|
||||
},
|
||||
[&](ArrayRef &aRef) {
|
||||
return Folder<SomeDerived>{context_}.Folding(aRef);
|
||||
},
|
||||
[&](Component &base) {
|
||||
return Folder<SomeDerived>{context_}.GetConstantComponent(base);
|
||||
},
|
||||
[&](CoarrayRef &) {
|
||||
return std::optional<Constant<SomeDerived>>{};
|
||||
},
|
||||
},
|
||||
component.base().u)}) {
|
||||
return ApplyComponent(
|
||||
std::move(*structures), component.GetLastSymbol(), subscripts);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> Expr<T> Folder<T>::Folding(Designator<T> &&designator) {
|
||||
if constexpr (T::category == TypeCategory::Character) {
|
||||
if (auto *substring{common::Unwrap<Substring>(designator.u)}) {
|
||||
if (std::optional<Expr<SomeCharacter>> folded{
|
||||
substring->Fold(context_)}) {
|
||||
if (auto value{GetScalarConstantValue<T>(*folded)}) {
|
||||
return Expr<T>{*value};
|
||||
}
|
||||
}
|
||||
if (auto length{ToInt64(Fold(context_, substring->LEN()))}) {
|
||||
if (*length == 0) {
|
||||
return Expr<T>{Constant<T>{Scalar<T>{}}};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](SymbolRef &&symbol) {
|
||||
if (auto constant{GetFoldedNamedConstantValue(*symbol)}) {
|
||||
return Expr<T>{std::move(*constant)};
|
||||
}
|
||||
return Expr<T>{std::move(designator)};
|
||||
},
|
||||
[&](ArrayRef &&aRef) {
|
||||
aRef = FoldOperation(context_, std::move(aRef));
|
||||
if (auto c{Folding(aRef)}) {
|
||||
return Expr<T>{std::move(*c)};
|
||||
} else {
|
||||
return Expr<T>{Designator<T>{std::move(aRef)}};
|
||||
}
|
||||
},
|
||||
[&](Component &&component) {
|
||||
component = FoldOperation(context_, std::move(component));
|
||||
if (auto c{GetConstantComponent(component)}) {
|
||||
return Expr<T>{std::move(*c)};
|
||||
} else {
|
||||
return Expr<T>{Designator<T>{std::move(component)}};
|
||||
}
|
||||
},
|
||||
[&](auto &&x) {
|
||||
return Expr<T>{
|
||||
Designator<T>{FoldOperation(context_, std::move(x))}};
|
||||
},
|
||||
},
|
||||
std::move(designator.u));
|
||||
}
|
||||
|
||||
// helpers to fold intrinsic function references
|
||||
// Define callable types used in a common utility that
|
||||
// takes care of array and cast/conversion aspects for elemental intrinsics
|
||||
|
|
|
@ -11,360 +11,6 @@
|
|||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
template<typename T>
|
||||
std::optional<Expr<T>> Folder<T>::GetNamedConstantValue(const Symbol &symbol0) {
|
||||
const Symbol &symbol{ResolveAssociations(symbol0).GetUltimate()};
|
||||
if (IsNamedConstant(symbol)) {
|
||||
if (const auto *object{
|
||||
symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
if (object->initWasValidated()) {
|
||||
const auto *constant{UnwrapConstantValue<T>(object->init())};
|
||||
CHECK(constant);
|
||||
return Expr<T>{*constant};
|
||||
}
|
||||
if (const auto &init{object->init()}) {
|
||||
if (auto dyType{DynamicType::From(symbol)}) {
|
||||
semantics::ObjectEntityDetails *mutableObject{
|
||||
const_cast<semantics::ObjectEntityDetails *>(object)};
|
||||
auto converted{
|
||||
ConvertToType(*dyType, std::move(mutableObject->init().value()))};
|
||||
// Reset expression now to prevent infinite loops if the init
|
||||
// expression depends on symbol itself.
|
||||
mutableObject->set_init(std::nullopt);
|
||||
if (converted) {
|
||||
*converted = Fold(context_, std::move(*converted));
|
||||
auto *unwrapped{UnwrapExpr<Expr<T>>(*converted)};
|
||||
CHECK(unwrapped);
|
||||
if (auto *constant{UnwrapConstantValue<T>(*unwrapped)}) {
|
||||
if (symbol.Rank() > 0) {
|
||||
if (constant->Rank() == 0) {
|
||||
// scalar expansion
|
||||
if (auto symShape{GetShape(context_, symbol)}) {
|
||||
if (auto extents{AsConstantExtents(context_, *symShape)}) {
|
||||
*constant = constant->Reshape(std::move(*extents));
|
||||
CHECK(constant->Rank() == symbol.Rank());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (constant->Rank() == symbol.Rank()) {
|
||||
NamedEntity base{symbol};
|
||||
if (auto lbounds{AsConstantExtents(
|
||||
context_, GetLowerBounds(context_, base))}) {
|
||||
constant->set_lbounds(*std::move(lbounds));
|
||||
}
|
||||
}
|
||||
}
|
||||
mutableObject->set_init(AsGenericExpr(Expr<T>{*constant}));
|
||||
if (auto constShape{GetShape(context_, *constant)}) {
|
||||
if (auto symShape{GetShape(context_, symbol)}) {
|
||||
if (CheckConformance(context_.messages(), *constShape,
|
||||
*symShape, "initialization expression",
|
||||
"PARAMETER")) {
|
||||
mutableObject->set_initWasValidated();
|
||||
return std::move(*unwrapped);
|
||||
}
|
||||
} else {
|
||||
context_.messages().Say(symbol.name(),
|
||||
"Could not determine the shape of the PARAMETER"_err_en_US);
|
||||
}
|
||||
} else {
|
||||
context_.messages().Say(symbol.name(),
|
||||
"Could not determine the shape of the initialization expression"_err_en_US);
|
||||
}
|
||||
mutableObject->set_init(std::nullopt);
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
unwrapped->AsFortran(ss);
|
||||
context_.messages().Say(symbol.name(),
|
||||
"Initialization expression for PARAMETER '%s' (%s) cannot be computed as a constant value"_err_en_US,
|
||||
symbol.name(), ss.str());
|
||||
}
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
init->AsFortran(ss);
|
||||
context_.messages().Say(symbol.name(),
|
||||
"Initialization expression for PARAMETER '%s' (%s) cannot be converted to its type (%s)"_err_en_US,
|
||||
symbol.name(), ss.str(), dyType->AsFortran());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<Constant<T>> Folder<T>::GetFoldedNamedConstantValue(
|
||||
const Symbol &symbol) {
|
||||
if (auto value{GetNamedConstantValue(symbol)}) {
|
||||
Expr<T> folded{Fold(context_, std::move(*value))};
|
||||
if (const Constant<T> *value{UnwrapConstantValue<T>(folded)}) {
|
||||
return *value;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static std::optional<Constant<SubscriptInteger>> GetConstantSubscript(
|
||||
FoldingContext &context, Subscript &ss, const NamedEntity &base, int dim) {
|
||||
ss = FoldOperation(context, std::move(ss));
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[](IndirectSubscriptIntegerExpr &expr)
|
||||
-> std::optional<Constant<SubscriptInteger>> {
|
||||
if (auto constant{
|
||||
GetScalarConstantValue<SubscriptInteger>(expr.value())}) {
|
||||
return Constant<SubscriptInteger>{*constant};
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
},
|
||||
[&](Triplet &triplet) -> std::optional<Constant<SubscriptInteger>> {
|
||||
auto lower{triplet.lower()}, upper{triplet.upper()};
|
||||
std::optional<ConstantSubscript> stride{ToInt64(triplet.stride())};
|
||||
if (!lower) {
|
||||
lower = GetLowerBound(context, base, dim);
|
||||
}
|
||||
if (!upper) {
|
||||
upper =
|
||||
ComputeUpperBound(context, GetLowerBound(context, base, dim),
|
||||
GetExtent(context, base, dim));
|
||||
}
|
||||
auto lbi{ToInt64(lower)}, ubi{ToInt64(upper)};
|
||||
if (lbi && ubi && stride && *stride != 0) {
|
||||
std::vector<SubscriptInteger::Scalar> values;
|
||||
while ((*stride > 0 && *lbi <= *ubi) ||
|
||||
(*stride < 0 && *lbi >= *ubi)) {
|
||||
values.emplace_back(*lbi);
|
||||
*lbi += *stride;
|
||||
}
|
||||
return Constant<SubscriptInteger>{std::move(values),
|
||||
ConstantSubscripts{
|
||||
static_cast<ConstantSubscript>(values.size())}};
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
},
|
||||
},
|
||||
ss.u);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<Constant<T>> Folder<T>::Folding(ArrayRef &aRef) {
|
||||
std::vector<Constant<SubscriptInteger>> subscripts;
|
||||
int dim{0};
|
||||
for (Subscript &ss : aRef.subscript()) {
|
||||
if (auto constant{GetConstantSubscript(context_, ss, aRef.base(), dim++)}) {
|
||||
subscripts.emplace_back(std::move(*constant));
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
if (Component * component{aRef.base().UnwrapComponent()}) {
|
||||
return GetConstantComponent(*component, &subscripts);
|
||||
} else if (std::optional<Constant<T>> array{
|
||||
GetFoldedNamedConstantValue(aRef.base().GetLastSymbol())}) {
|
||||
return ApplySubscripts(*array, subscripts);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<Constant<T>> Folder<T>::ApplySubscripts(const Constant<T> &array,
|
||||
const std::vector<Constant<SubscriptInteger>> &subscripts) {
|
||||
const auto &shape{array.shape()};
|
||||
const auto &lbounds{array.lbounds()};
|
||||
int rank{GetRank(shape)};
|
||||
CHECK(rank == static_cast<int>(subscripts.size()));
|
||||
std::size_t elements{1};
|
||||
ConstantSubscripts resultShape;
|
||||
ConstantSubscripts ssLB;
|
||||
for (const auto &ss : subscripts) {
|
||||
CHECK(ss.Rank() <= 1);
|
||||
if (ss.Rank() == 1) {
|
||||
resultShape.push_back(static_cast<ConstantSubscript>(ss.size()));
|
||||
elements *= ss.size();
|
||||
ssLB.push_back(ss.lbounds().front());
|
||||
}
|
||||
}
|
||||
ConstantSubscripts ssAt(rank, 0), at(rank, 0), tmp(1, 0);
|
||||
std::vector<Scalar<T>> values;
|
||||
while (elements-- > 0) {
|
||||
bool increment{true};
|
||||
int k{0};
|
||||
for (int j{0}; j < rank; ++j) {
|
||||
if (subscripts[j].Rank() == 0) {
|
||||
at[j] = subscripts[j].GetScalarValue().value().ToInt64();
|
||||
} else {
|
||||
CHECK(k < GetRank(resultShape));
|
||||
tmp[0] = ssLB[j] + ssAt[j];
|
||||
at[j] = subscripts[j].At(tmp).ToInt64();
|
||||
if (increment) {
|
||||
if (++ssAt[j] == resultShape[k]) {
|
||||
ssAt[j] = 0;
|
||||
} else {
|
||||
increment = false;
|
||||
}
|
||||
}
|
||||
++k;
|
||||
}
|
||||
if (at[j] < lbounds[j] || at[j] >= lbounds[j] + shape[j]) {
|
||||
context_.messages().Say(
|
||||
"Subscript value (%jd) is out of range on dimension %d in reference to a constant array value"_err_en_US,
|
||||
static_cast<std::intmax_t>(at[j]), j + 1);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
values.emplace_back(array.At(at));
|
||||
CHECK(!increment || elements == 0);
|
||||
CHECK(k == GetRank(resultShape));
|
||||
}
|
||||
if constexpr (T::category == TypeCategory::Character) {
|
||||
return Constant<T>{array.LEN(), std::move(values), std::move(resultShape)};
|
||||
} else if constexpr (std::is_same_v<T, SomeDerived>) {
|
||||
return Constant<T>{array.result().derivedTypeSpec(), std::move(values),
|
||||
std::move(resultShape)};
|
||||
} else {
|
||||
return Constant<T>{std::move(values), std::move(resultShape)};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<Constant<T>> Folder<T>::ApplyComponent(
|
||||
Constant<SomeDerived> &&structures, const Symbol &component,
|
||||
const std::vector<Constant<SubscriptInteger>> *subscripts) {
|
||||
if (auto scalar{structures.GetScalarValue()}) {
|
||||
if (auto *expr{scalar->Find(component)}) {
|
||||
if (const Constant<T> *value{UnwrapConstantValue<T>(*expr)}) {
|
||||
if (!subscripts) {
|
||||
return std::move(*value);
|
||||
} else {
|
||||
return ApplySubscripts(*value, *subscripts);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// A(:)%scalar_component & A(:)%array_component(subscripts)
|
||||
std::unique_ptr<ArrayConstructor<T>> array;
|
||||
if (structures.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
ConstantSubscripts at{structures.lbounds()};
|
||||
do {
|
||||
StructureConstructor scalar{structures.At(at)};
|
||||
if (auto *expr{scalar.Find(component)}) {
|
||||
if (const Constant<T> *value{UnwrapConstantValue<T>(*expr)}) {
|
||||
if (!array.get()) {
|
||||
// This technique ensures that character length or derived type
|
||||
// information is propagated to the array constructor.
|
||||
auto *typedExpr{UnwrapExpr<Expr<T>>(*expr)};
|
||||
CHECK(typedExpr);
|
||||
array = std::make_unique<ArrayConstructor<T>>(*typedExpr);
|
||||
}
|
||||
if (subscripts) {
|
||||
if (auto element{ApplySubscripts(*value, *subscripts)}) {
|
||||
CHECK(element->Rank() == 0);
|
||||
array->Push(Expr<T>{std::move(*element)});
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
} else {
|
||||
CHECK(value->Rank() == 0);
|
||||
array->Push(Expr<T>{*value});
|
||||
}
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
} while (structures.IncrementSubscripts(at));
|
||||
// Fold the ArrayConstructor<> into a Constant<>.
|
||||
CHECK(array);
|
||||
Expr<T> result{Fold(context_, Expr<T>{std::move(*array)})};
|
||||
if (auto *constant{UnwrapConstantValue<T>(result)}) {
|
||||
return constant->Reshape(common::Clone(structures.shape()));
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<Constant<T>> Folder<T>::GetConstantComponent(Component &component,
|
||||
const std::vector<Constant<SubscriptInteger>> *subscripts) {
|
||||
if (std::optional<Constant<SomeDerived>> structures{std::visit(
|
||||
common::visitors{
|
||||
[&](const Symbol &symbol) {
|
||||
return Folder<SomeDerived>{context_}
|
||||
.GetFoldedNamedConstantValue(symbol);
|
||||
},
|
||||
[&](ArrayRef &aRef) {
|
||||
return Folder<SomeDerived>{context_}.Folding(aRef);
|
||||
},
|
||||
[&](Component &base) {
|
||||
return Folder<SomeDerived>{context_}.GetConstantComponent(base);
|
||||
},
|
||||
[&](CoarrayRef &) {
|
||||
return std::optional<Constant<SomeDerived>>{};
|
||||
},
|
||||
},
|
||||
component.base().u)}) {
|
||||
return ApplyComponent(
|
||||
std::move(*structures), component.GetLastSymbol(), subscripts);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> Expr<T> Folder<T>::Folding(Designator<T> &&designator) {
|
||||
if constexpr (T::category == TypeCategory::Character) {
|
||||
if (auto *substring{common::Unwrap<Substring>(designator.u)}) {
|
||||
if (std::optional<Expr<SomeCharacter>> folded{
|
||||
substring->Fold(context_)}) {
|
||||
if (auto value{GetScalarConstantValue<T>(*folded)}) {
|
||||
return Expr<T>{*value};
|
||||
}
|
||||
}
|
||||
if (auto length{ToInt64(Fold(context_, substring->LEN()))}) {
|
||||
if (*length == 0) {
|
||||
return Expr<T>{Constant<T>{Scalar<T>{}}};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](SymbolRef &&symbol) {
|
||||
if (auto constant{GetFoldedNamedConstantValue(*symbol)}) {
|
||||
return Expr<T>{std::move(*constant)};
|
||||
}
|
||||
return Expr<T>{std::move(designator)};
|
||||
},
|
||||
[&](ArrayRef &&aRef) {
|
||||
aRef = FoldOperation(context_, std::move(aRef));
|
||||
if (auto c{Folding(aRef)}) {
|
||||
return Expr<T>{std::move(*c)};
|
||||
} else {
|
||||
return Expr<T>{Designator<T>{std::move(aRef)}};
|
||||
}
|
||||
},
|
||||
[&](Component &&component) {
|
||||
component = FoldOperation(context_, std::move(component));
|
||||
if (auto c{GetConstantComponent(component)}) {
|
||||
return Expr<T>{std::move(*c)};
|
||||
} else {
|
||||
return Expr<T>{Designator<T>{std::move(component)}};
|
||||
}
|
||||
},
|
||||
[&](auto &&x) {
|
||||
return Expr<T>{
|
||||
Designator<T>{FoldOperation(context_, std::move(x))}};
|
||||
},
|
||||
},
|
||||
std::move(designator.u));
|
||||
}
|
||||
|
||||
FOR_EACH_SPECIFIC_TYPE(template class Folder, )
|
||||
|
||||
Expr<SomeDerived> FoldOperation(
|
||||
FoldingContext &context, StructureConstructor &&structure) {
|
||||
StructureConstructor result{structure.derivedTypeSpec()};
|
||||
|
|
Loading…
Reference in New Issue