[flang] Re-fold bounds expressions in DATA implied DO loops

To accommodate triangular implied DO loops in DATA statements, in which
the bounds of nested implied DO loops might depend on the values of the
indices of outer implied DO loops in the same DATA statement set, it
is necessary to run them through constant folding each time they are
encountered.

Differential Revision: https://reviews.llvm.org/D114754
This commit is contained in:
Peter Klausler 2021-11-22 18:37:25 -08:00
parent 3ad0c6b75e
commit cbd445e4a3
1 changed files with 20 additions and 11 deletions

View File

@ -155,14 +155,24 @@ bool DataInitializationCompiler::Scan(const parser::DataImpliedDo &ido) {
const auto *stepExpr{ const auto *stepExpr{
bounds.step ? GetExpr(bounds.step->thing.thing) : nullptr}; bounds.step ? GetExpr(bounds.step->thing.thing) : nullptr};
if (lowerExpr && upperExpr) { if (lowerExpr && upperExpr) {
auto lower{ToInt64(*lowerExpr)}; // Fold the bounds expressions (again) in case any of them depend
auto upper{ToInt64(*upperExpr)}; // on outer implied DO loops.
auto step{stepExpr ? ToInt64(*stepExpr) : std::nullopt}; evaluate::FoldingContext &context{exprAnalyzer_.GetFoldingContext()};
auto stepVal{step.value_or(1)}; std::int64_t stepVal{1};
if (stepVal == 0) { if (stepExpr) {
exprAnalyzer_.Say(name.source, auto foldedStep{evaluate::Fold(context, SomeExpr{*stepExpr})};
"DATA statement implied DO loop has a step value of zero"_err_en_US); stepVal = ToInt64(foldedStep).value_or(1);
} else if (lower && upper) { if (stepVal == 0) {
exprAnalyzer_.Say(name.source,
"DATA statement implied DO loop has a step value of zero"_err_en_US);
return false;
}
}
auto foldedLower{evaluate::Fold(context, SomeExpr{*lowerExpr})};
auto lower{ToInt64(foldedLower)};
auto foldedUpper{evaluate::Fold(context, SomeExpr{*upperExpr})};
auto upper{ToInt64(foldedUpper)};
if (lower && upper) {
int kind{evaluate::ResultType<evaluate::ImpliedDoIndex>::kind}; int kind{evaluate::ResultType<evaluate::ImpliedDoIndex>::kind};
if (const auto dynamicType{evaluate::DynamicType::From(*name.symbol)}) { if (const auto dynamicType{evaluate::DynamicType::From(*name.symbol)}) {
if (dynamicType->category() == TypeCategory::Integer) { if (dynamicType->category() == TypeCategory::Integer) {
@ -170,8 +180,7 @@ bool DataInitializationCompiler::Scan(const parser::DataImpliedDo &ido) {
} }
} }
if (exprAnalyzer_.AddImpliedDo(name.source, kind)) { if (exprAnalyzer_.AddImpliedDo(name.source, kind)) {
auto &value{exprAnalyzer_.GetFoldingContext().StartImpliedDo( auto &value{context.StartImpliedDo(name.source, *lower)};
name.source, *lower)};
bool result{true}; bool result{true};
for (auto n{(*upper - value + stepVal) / stepVal}; n > 0; for (auto n{(*upper - value + stepVal) / stepVal}; n > 0;
--n, value += stepVal) { --n, value += stepVal) {
@ -183,7 +192,7 @@ bool DataInitializationCompiler::Scan(const parser::DataImpliedDo &ido) {
} }
} }
} }
exprAnalyzer_.GetFoldingContext().EndImpliedDo(name.source); context.EndImpliedDo(name.source);
exprAnalyzer_.RemoveImpliedDo(name.source); exprAnalyzer_.RemoveImpliedDo(name.source);
return result; return result;
} }