Skip to content

Commit

Permalink
[flang]Semantics for SELECT RANK.
Browse files Browse the repository at this point in the history
    Summary:
    Initially on github I worked on semantic checks.Then I tried some compile-time
    test of the rank value, they were failing as there were no symbols
    generated for them inside SELECT RANK's scope.So I went further to
    add new symbol in each scope, also added the respective 'rank: '
    field for a symbol when we dump the symboltable. I added a field to
    keep track of the rank in AssocEntityDetails class.This caused shape
    analysis framework to become inconsistent. So shape analysis framework
    was updated to handle this new representation.

	 *   I added more tests for above changes.

	 *   On phabricator I addressed some minor changes.

	 *   Lastly I worked on review comments.

    Reviewers: klausler,sscalpone,DavidTruby,kiranchandramohan,tskeith,anchu-rajendran,kiranktp

    Reviewed By:klausler, DavidTruby, tskeith

    Subscribers:#flang-commits, #llvm-commits

    Tags: #flang, #llvm

    Differential Revision: https://reviews.llvm.org/D78623
  • Loading branch information
Sameeranjoshi committed May 8, 2020
1 parent 4ae537c commit 332e6ae
Show file tree
Hide file tree
Showing 11 changed files with 554 additions and 17 deletions.
8 changes: 7 additions & 1 deletion flang/include/flang/Evaluate/shape.h
Expand Up @@ -128,7 +128,13 @@ class GetShapeHelper

private:
static Result Scalar() { return Shape{}; }

Shape CreateShape(int rank, NamedEntity &base) const {
Shape shape;
for (int dimension{0}; dimension < rank; ++dimension) {
shape.emplace_back(GetExtent(context_, base, dimension));
}
return shape;
}
template <typename T>
MaybeExtentExpr GetArrayConstructorValueExtent(
const ArrayConstructorValue<T> &value) const {
Expand Down
14 changes: 10 additions & 4 deletions flang/include/flang/Semantics/symbol.h
Expand Up @@ -147,9 +147,12 @@ class AssocEntityDetails : public EntityDetails {
AssocEntityDetails &operator=(const AssocEntityDetails &) = default;
AssocEntityDetails &operator=(AssocEntityDetails &&) = default;
const MaybeExpr &expr() const { return expr_; }
void set_rank(int rank);
std::optional<int> rank() const { return rank_; }

private:
MaybeExpr expr_;
std::optional<int> rank_;
};

// An entity known to be an object.
Expand Down Expand Up @@ -320,8 +323,8 @@ class FinalProcDetails {}; // TODO
class MiscDetails {
public:
ENUM_CLASS(Kind, None, ConstructName, ScopeName, PassName, ComplexPartRe,
ComplexPartIm, KindParamInquiry, LenParamInquiry, SelectTypeAssociateName,
TypeBoundDefinedOp);
ComplexPartIm, KindParamInquiry, LenParamInquiry, SelectRankAssociateName,
SelectTypeAssociateName, TypeBoundDefinedOp);
MiscDetails(Kind kind) : kind_{kind} {}
Kind kind() const { return kind_; }

Expand Down Expand Up @@ -587,7 +590,6 @@ class Symbol {
}

void SetType(const DeclTypeSpec &);

bool IsDummy() const;
bool IsFuncResult() const;
bool IsObjectArray() const;
Expand Down Expand Up @@ -637,7 +639,11 @@ class Symbol {
[](const ObjectEntityDetails &oed) { return oed.shape().Rank(); },
[](const AssocEntityDetails &aed) {
if (const auto &expr{aed.expr()}) {
return expr->Rank();
if (auto assocRank{aed.rank()}) {
return *assocRank;
} else {
return expr->Rank();
}
} else {
return 0;
}
Expand Down
23 changes: 12 additions & 11 deletions flang/lib/Evaluate/shape.cpp
Expand Up @@ -399,13 +399,9 @@ auto GetShapeHelper::operator()(const Symbol &symbol) const -> Result {
if (IsImpliedShape(symbol)) {
return (*this)(object.init());
} else {
Shape shape;
int n{object.shape().Rank()};
NamedEntity base{symbol};
for (int dimension{0}; dimension < n; ++dimension) {
shape.emplace_back(GetExtent(context_, base, dimension));
}
return Result{shape};
return Result{CreateShape(n, base)};
}
},
[](const semantics::EntityDetails &) {
Expand All @@ -419,7 +415,13 @@ auto GetShapeHelper::operator()(const Symbol &symbol) const -> Result {
}
},
[&](const semantics::AssocEntityDetails &assoc) {
return (*this)(assoc.expr());
if (!assoc.rank()) {
return (*this)(assoc.expr());
} else {
int n{assoc.rank().value()};
NamedEntity base{symbol};
return Result{CreateShape(n, base)};
}
},
[&](const semantics::SubprogramDetails &subp) {
if (subp.isFunction()) {
Expand Down Expand Up @@ -448,12 +450,11 @@ auto GetShapeHelper::operator()(const Component &component) const -> Result {
if (rank == 0) {
return (*this)(component.base());
} else if (symbol.has<semantics::ObjectEntityDetails>()) {
Shape shape;
NamedEntity base{Component{component}};
for (int dimension{0}; dimension < rank; ++dimension) {
shape.emplace_back(GetExtent(context_, base, dimension));
}
return shape;
return CreateShape(rank, base);
} else if (symbol.has<semantics::AssocEntityDetails>()) {
NamedEntity base{Component{component}};
return Result{CreateShape(rank, base)};
} else {
return (*this)(symbol);
}
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Semantics/CMakeLists.txt
Expand Up @@ -20,6 +20,7 @@ add_flang_library(FortranSemantics
check-omp-structure.cpp
check-purity.cpp
check-return.cpp
check-select-rank.cpp
check-stop.cpp
compute-offsets.cpp
expression.cpp
Expand Down
129 changes: 129 additions & 0 deletions flang/lib/Semantics/check-select-rank.cpp
@@ -0,0 +1,129 @@
//===-- lib/Semantics/check-select-rank.cpp -------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "check-select-rank.h"
#include "flang/Common/Fortran.h"
#include "flang/Common/idioms.h"
#include "flang/Parser/message.h"
#include "flang/Parser/tools.h"
#include "flang/Semantics/tools.h"
#include <list>
#include <optional>
#include <set>
#include <tuple>
#include <variant>

namespace Fortran::semantics {

void SelectRankConstructChecker::Leave(
const parser::SelectRankConstruct &selectRankConstruct) {
const auto &selectRankStmt{
std::get<parser::Statement<parser::SelectRankStmt>>(
selectRankConstruct.t)};
const auto &selectRankStmtSel{
std::get<parser::Selector>(selectRankStmt.statement.t)};

// R1149 select-rank-stmt checks
const Symbol *saveSelSymbol{nullptr};
if (const auto selExpr{GetExprFromSelector(selectRankStmtSel)}) {
if (const Symbol * sel{evaluate::UnwrapWholeSymbolDataRef(*selExpr)}) {
if (!IsAssumedRankArray(*sel)) { // C1150
context_.Say(parser::FindSourceLocation(selectRankStmtSel),
"Selector '%s' is not an assumed-rank array variable"_err_en_US,
sel->name().ToString());
} else {
saveSelSymbol = sel;
}
} else {
context_.Say(parser::FindSourceLocation(selectRankStmtSel),
"Selector '%s' is not an assumed-rank array variable"_err_en_US,
parser::FindSourceLocation(selectRankStmtSel).ToString());
}
}

// R1150 select-rank-case-stmt checks
auto &rankCaseList{std::get<std::list<parser::SelectRankConstruct::RankCase>>(
selectRankConstruct.t)};
bool defaultRankFound{false};
bool starRankFound{false};
parser::CharBlock prevLocDefault;
parser::CharBlock prevLocStar;
std::optional<parser::CharBlock> caseForRank[common::maxRank + 1];

for (const auto &rankCase : rankCaseList) {
const auto &rankCaseStmt{
std::get<parser::Statement<parser::SelectRankCaseStmt>>(rankCase.t)};
const auto &rank{
std::get<parser::SelectRankCaseStmt::Rank>(rankCaseStmt.statement.t)};
std::visit(
common::visitors{
[&](const parser::Default &) { // C1153
if (!defaultRankFound) {
defaultRankFound = true;
prevLocDefault = rankCaseStmt.source;
} else {
context_
.Say(rankCaseStmt.source,
"Not more than one of the selectors of SELECT RANK "
"statement may be DEFAULT"_err_en_US)
.Attach(prevLocDefault, "Previous use"_err_en_US);
}
},
[&](const parser::Star &) { // C1153
if (!starRankFound) {
starRankFound = true;
prevLocStar = rankCaseStmt.source;
} else {
context_
.Say(rankCaseStmt.source,
"Not more than one of the selectors of SELECT RANK "
"statement may be '*'"_err_en_US)
.Attach(prevLocStar, "Previous use"_err_en_US);
}
if (saveSelSymbol &&
IsAllocatableOrPointer(*saveSelSymbol)) { // C1155
context_.Say(parser::FindSourceLocation(selectRankStmtSel),
"RANK (*) cannot be used when selector is "
"POINTER or ALLOCATABLE"_err_en_US);
}
},
[&](const parser::ScalarIntConstantExpr &init) {
if (auto val{GetIntValue(init)}) {
// If value is in valid range, then only show
// value repeat error, else stack smashing occurs
if (*val < 0 || *val > common::maxRank) { // C1151
context_.Say(rankCaseStmt.source,
"The value of the selector must be "
"between zero and %d"_err_en_US,
common::maxRank);

} else {
if (!caseForRank[*val].has_value()) {
caseForRank[*val] = rankCaseStmt.source;
} else {
auto prevloc{caseForRank[*val].value()};
context_
.Say(rankCaseStmt.source,
"Same rank value (%d) not allowed more than once"_err_en_US,
*val)
.Attach(prevloc, "Previous use"_err_en_US);
}
}
}
},
},
rank.u);
}
}

const SomeExpr *SelectRankConstructChecker::GetExprFromSelector(
const parser::Selector &selector) {
return std::visit([](const auto &x) { return GetExpr(x); }, selector.u);
}

} // namespace Fortran::semantics
26 changes: 26 additions & 0 deletions flang/lib/Semantics/check-select-rank.h
@@ -0,0 +1,26 @@
//===-- lib/Semantics/check-select-rank.h -----------------------*- 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 FORTRAN_SEMANTICS_CHECK_SELECT_STMT_H_
#define FORTRAN_SEMANTICS_CHECK_SELECT_STMT_H_

#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/semantics.h"

namespace Fortran::semantics {
class SelectRankConstructChecker : public virtual BaseChecker {
public:
SelectRankConstructChecker(SemanticsContext &context) : context_{context} {}
void Leave(const parser::SelectRankConstruct &);

private:
const SomeExpr *GetExprFromSelector(const parser::Selector &);
SemanticsContext &context_;
};
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_CHECK_SELECT_STMT_H_
36 changes: 36 additions & 0 deletions flang/lib/Semantics/resolve-names.cpp
Expand Up @@ -985,11 +985,16 @@ class ConstructVisitor : public virtual DeclarationVisitor {
void Post(const parser::EndAssociateStmt &);
void Post(const parser::Association &);
void Post(const parser::SelectTypeStmt &);
void Post(const parser::SelectRankStmt &);
bool Pre(const parser::SelectTypeConstruct &);
void Post(const parser::SelectTypeConstruct &);
bool Pre(const parser::SelectTypeConstruct::TypeCase &);
void Post(const parser::SelectTypeConstruct::TypeCase &);
// Creates Block scopes with neither symbol name nor symbol details.
bool Pre(const parser::SelectRankConstruct::RankCase &);
void Post(const parser::SelectRankConstruct::RankCase &);
void Post(const parser::TypeGuardStmt::Guard &);
void Post(const parser::SelectRankCaseStmt::Rank &);
bool Pre(const parser::ChangeTeamStmt &);
void Post(const parser::EndChangeTeamStmt &);
void Post(const parser::CoarrayAssociation &);
Expand Down Expand Up @@ -5133,6 +5138,15 @@ void ConstructVisitor::Post(const parser::SelectTypeStmt &x) {
}
}

void ConstructVisitor::Post(const parser::SelectRankStmt &x) {
auto &association{GetCurrentAssociation()};
if (const std::optional<parser::Name> &name{std::get<1>(x.t)}) {
// This isn't a name in the current scope, it is in each SelectRankCaseStmt
MakePlaceholder(*name, MiscDetails::Kind::SelectRankAssociateName);
association.name = &*name;
}
}

bool ConstructVisitor::Pre(const parser::SelectTypeConstruct::TypeCase &) {
PushScope(Scope::Kind::Block, nullptr);
return true;
Expand All @@ -5141,6 +5155,14 @@ void ConstructVisitor::Post(const parser::SelectTypeConstruct::TypeCase &) {
PopScope();
}

bool ConstructVisitor::Pre(const parser::SelectRankConstruct::RankCase &) {
PushScope(Scope::Kind::Block, nullptr);
return true;
}
void ConstructVisitor::Post(const parser::SelectRankConstruct::RankCase &) {
PopScope();
}

void ConstructVisitor::Post(const parser::TypeGuardStmt::Guard &x) {
if (auto *symbol{MakeAssocEntity()}) {
if (std::holds_alternative<parser::Default>(x.u)) {
Expand All @@ -5152,6 +5174,20 @@ void ConstructVisitor::Post(const parser::TypeGuardStmt::Guard &x) {
}
}

void ConstructVisitor::Post(const parser::SelectRankCaseStmt::Rank &x) {
if (auto *symbol{MakeAssocEntity()}) {
SetTypeFromAssociation(*symbol);
SetAttrsFromAssociation(*symbol);
if (const auto *init{std::get_if<parser::ScalarIntConstantExpr>(&x.u)}) {
MaybeIntExpr expr{EvaluateIntExpr(*init)};
if (auto val{evaluate::ToInt64(expr)}) {
auto &details{symbol->get<AssocEntityDetails>()};
details.set_rank(*val);
}
}
}
}

bool ConstructVisitor::Pre(const parser::SelectRankConstruct &) {
PushAssociation();
return true;
Expand Down
3 changes: 2 additions & 1 deletion flang/lib/Semantics/semantics.cpp
Expand Up @@ -25,6 +25,7 @@
#include "check-omp-structure.h"
#include "check-purity.h"
#include "check-return.h"
#include "check-select-rank.h"
#include "check-stop.h"
#include "compute-offsets.h"
#include "mod-file.h"
Expand Down Expand Up @@ -156,7 +157,7 @@ using StatementSemanticsPass2 = SemanticsVisitor<AllocateChecker,
ArithmeticIfStmtChecker, AssignmentChecker, CaseChecker, CoarrayChecker,
DataChecker, DeallocateChecker, DoForallChecker, IfStmtChecker, IoChecker,
MiscChecker, NamelistChecker, NullifyChecker, OmpStructureChecker,
PurityChecker, ReturnStmtChecker, StopChecker>;
PurityChecker, ReturnStmtChecker, SelectRankConstructChecker, StopChecker>;

static bool PerformStatementSemantics(
SemanticsContext &context, parser::Program &program) {
Expand Down
4 changes: 4 additions & 0 deletions flang/lib/Semantics/symbol.cpp
Expand Up @@ -119,6 +119,7 @@ void EntityDetails::set_type(const DeclTypeSpec &type) {
type_ = &type;
}

void AssocEntityDetails::set_rank(int rank) { rank_ = rank; }
void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }

void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
Expand Down Expand Up @@ -353,6 +354,9 @@ llvm::raw_ostream &operator<<(
llvm::raw_ostream &operator<<(
llvm::raw_ostream &os, const AssocEntityDetails &x) {
os << *static_cast<const EntityDetails *>(&x);
if (auto assocRank{x.rank()}) {
os << " rank: " << *assocRank;
}
DumpExpr(os, "expr", x.expr());
return os;
}
Expand Down

0 comments on commit 332e6ae

Please sign in to comment.