Skip to content

Commit

Permalink
[flang] Implement semantic checking for TASKLOOP
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidTruby authored and David Truby committed Sep 3, 2019
1 parent 5d2f120 commit f1212c6
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 41 deletions.
123 changes: 82 additions & 41 deletions flang/lib/semantics/check-omp-structure.cc
Expand Up @@ -56,23 +56,67 @@ bool OmpStructureChecker::HasInvalidWorksharingNesting(

void OmpStructureChecker::CheckAllowed(OmpClause type) {
if (!GetContext().allowedClauses.test(type) &&
!GetContext().allowedOnceClauses.test(type)) {
!GetContext().allowedOnceClauses.test(type) &&
!GetContext().allowedExclusiveClauses.test(type)) {
context_.Say(GetContext().clauseSource,
"%s clause is not allowed on the %s directive"_err_en_US,
EnumToString(type),
parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
return;
}
if (GetContext().allowedOnceClauses.test(type) && FindClause(type)) {
if ((GetContext().allowedOnceClauses.test(type) ||
GetContext().allowedExclusiveClauses.test(type)) &&
FindClause(type)) {
context_.Say(GetContext().clauseSource,
"At most one %s clause can appear on the %s directive"_err_en_US,
EnumToString(type),
parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
return;
}
if (GetContext().allowedExclusiveClauses.test(type)) {
std::vector<OmpClause> others;
GetContext().allowedExclusiveClauses.IterateOverMembers([&](OmpClause o) {
if (FindClause(o)) {
others.emplace_back(o);
}
});
for (const auto &e : others) {
context_.Say(GetContext().clauseSource,
"%s and %s are mutually exclusive and may not appear on the same %s directive"_err_en_US,
EnumToString(type), EnumToString(e),
parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
}
if (!others.empty()) {
return;
}
}
SetContextClauseInfo(type);
}

void OmpStructureChecker::RequiresConstantPositiveParameter(
const OmpClause &clause, const parser::ScalarIntConstantExpr &i) {
if (const auto v{GetIntValue(i)}) {
if (*v <= 0) {
context_.Say(GetContext().clauseSource,
"The parameter of the %s clause must be "
"a constant positive integer expression"_err_en_US,
EnumToString(clause));
}
}
}

void OmpStructureChecker::RequiresPositiveParameter(
const OmpClause &clause, const parser::ScalarIntExpr &i) {
if (const auto v{GetIntValue(i)}) {
if (*v <= 0) {
context_.Say(GetContext().clauseSource,
"The parameter of the %s clause must be "
"a positive integer expression"_err_en_US,
EnumToString(clause));
}
}
}

void OmpStructureChecker::Enter(const parser::OpenMPConstruct &) {
// 2.8.1 TODO: Simd Construct with Ordered Construct Nesting check
}
Expand Down Expand Up @@ -173,6 +217,33 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
SetContextAllowedOnce(allowedOnce);
} break;

// 2.9.2 taskloop-clause -> if-clause |
// shared-clause |
// private-clause |
// firstprivate-clause |
// lastprivate-clause |
// default-clause |
// grainsize-clause |
// num-tasks-clause |
// collapse-clause |
// final-clause |
// priority-clause |
// untied-clause |
// mergeable-clause |
// nogroup-clause
case parser::OmpLoopDirective::Directive::Taskloop: {
PushContext(beginDir.source, OmpDirective::TASKLOOP);
OmpClauseSet allowed{OmpClause::SHARED, OmpClause::PRIVATE,
OmpClause::FIRSTPRIVATE, OmpClause::LASTPRIVATE, OmpClause::DEFAULT,
OmpClause::UNTIED, OmpClause::MERGEABLE, OmpClause::NOGROUP};
SetContextAllowed(allowed);
OmpClauseSet allowedOnce{OmpClause::COLLAPSE, OmpClause::IF,
OmpClause::FINAL, OmpClause::PRIORITY};
SetContextAllowedOnce(allowedOnce);
OmpClauseSet allowedExclusive{OmpClause::GRAINSIZE, OmpClause::NUM_TASKS};
SetContextAllowedExclusive(allowedExclusive);
} break;

default:
// TODO others
break;
Expand Down Expand Up @@ -550,13 +621,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Untied &) {
void OmpStructureChecker::Enter(const parser::OmpClause::Collapse &x) {
CheckAllowed(OmpClause::COLLAPSE);
// collapse clause must have a parameter
if (const auto v{GetIntValue(x.v)}) {
if (*v <= 0) {
context_.Say(GetContext().clauseSource,
"The parameter of the COLLAPSE clause must be "
"a constant positive integer expression"_err_en_US);
}
}
RequiresConstantPositiveParameter(OmpClause::COLLAPSE, x.v);
}

void OmpStructureChecker::Enter(const parser::OmpClause::Copyin &) {
Expand All @@ -580,41 +645,31 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &) {
void OmpStructureChecker::Enter(const parser::OmpClause::From &) {
CheckAllowed(OmpClause::FROM);
}
void OmpStructureChecker::Enter(const parser::OmpClause::Grainsize &) {
void OmpStructureChecker::Enter(const parser::OmpClause::Grainsize &x) {
CheckAllowed(OmpClause::GRAINSIZE);
RequiresPositiveParameter(OmpClause::GRAINSIZE, x.v);
}
void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &) {
CheckAllowed(OmpClause::LASTPRIVATE);
}
void OmpStructureChecker::Enter(const parser::OmpClause::NumTasks &) {
void OmpStructureChecker::Enter(const parser::OmpClause::NumTasks &x) {
CheckAllowed(OmpClause::NUM_TASKS);
RequiresPositiveParameter(OmpClause::NUM_TASKS, x.v);
}
void OmpStructureChecker::Enter(const parser::OmpClause::NumTeams &) {
CheckAllowed(OmpClause::NUM_TEAMS);
}
void OmpStructureChecker::Enter(const parser::OmpClause::NumThreads &x) {
CheckAllowed(OmpClause::NUM_THREADS);
if (const auto v{GetIntValue(x.v)}) {
if (*v <= 0) {
context_.Say(GetContext().clauseSource,
"The parameter of the NUM_THREADS clause must be "
"a positive integer expression"_err_en_US);
}
}
RequiresPositiveParameter(OmpClause::NUM_THREADS, x.v);
// if parameter is variable, defer to Expression Analysis
}

void OmpStructureChecker::Enter(const parser::OmpClause::Ordered &x) {
CheckAllowed(OmpClause::ORDERED);
// the parameter of ordered clause is optional
if (const auto &expr{x.v}) {
if (const auto v{GetIntValue(expr)}) {
if (*v <= 0) {
context_.Say(GetContext().clauseSource,
"The parameter of the ORDERED clause must be "
"a constant positive integer expression"_err_en_US);
}
}
RequiresConstantPositiveParameter(OmpClause::ORDERED, *expr);

// 2.8.3 Loop SIMD Construct Restriction
if (doSimdSet.test(GetContext().directive)) {
Expand All @@ -633,28 +688,14 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Private &) {
}
void OmpStructureChecker::Enter(const parser::OmpClause::Safelen &x) {
CheckAllowed(OmpClause::SAFELEN);

if (const auto v{GetIntValue(x.v)}) {
if (*v <= 0) {
context_.Say(GetContext().clauseSource,
"The parameter of the SAFELEN clause must be "
"a constant positive integer expression"_err_en_US);
}
}
RequiresConstantPositiveParameter(OmpClause::SAFELEN, x.v);
}
void OmpStructureChecker::Enter(const parser::OmpClause::Shared &) {
CheckAllowed(OmpClause::SHARED);
}
void OmpStructureChecker::Enter(const parser::OmpClause::Simdlen &x) {
CheckAllowed(OmpClause::SIMDLEN);

if (const auto v{GetIntValue(x.v)}) {
if (*v <= 0) {
context_.Say(GetContext().clauseSource,
"The parameter of the SIMDLEN clause must be "
"a constant positive integer expression"_err_en_US);
}
}
RequiresConstantPositiveParameter(OmpClause::SIMDLEN, x.v);
}
void OmpStructureChecker::Enter(const parser::OmpClause::ThreadLimit &) {
CheckAllowed(OmpClause::THREAD_LIMIT);
Expand Down
10 changes: 10 additions & 0 deletions flang/lib/semantics/check-omp-structure.h
Expand Up @@ -137,6 +137,7 @@ class OmpStructureChecker : public virtual BaseChecker {
OmpDirective directive;
OmpClauseSet allowedClauses{};
OmpClauseSet allowedOnceClauses{};
OmpClauseSet allowedExclusiveClauses{};

const parser::OmpClause *clause{nullptr};
std::multimap<OmpClause, const parser::OmpClause *> clauseInfo;
Expand All @@ -153,6 +154,7 @@ class OmpStructureChecker : public virtual BaseChecker {
SetContextDirectiveSource(source);
GetContext().allowedClauses = {};
GetContext().allowedOnceClauses = {};
GetContext().allowedExclusiveClauses = {};
GetContext().clauseInfo = {};
}
void SetContextDirectiveSource(const parser::CharBlock &directive) {
Expand All @@ -171,6 +173,9 @@ class OmpStructureChecker : public virtual BaseChecker {
void SetContextAllowedOnce(const OmpClauseSet &allowedOnce) {
GetContext().allowedOnceClauses = allowedOnce;
}
void SetContextAllowedExclusive(const OmpClauseSet &allowedExclusive) {
GetContext().allowedExclusiveClauses = allowedExclusive;
}
void SetContextClauseInfo(OmpClause type) {
GetContext().clauseInfo.emplace(type, GetContext().clause);
}
Expand All @@ -185,6 +190,11 @@ class OmpStructureChecker : public virtual BaseChecker {
ompContext_.emplace_back(source, dir);
}

void RequiresConstantPositiveParameter(
const OmpClause &clause, const parser::ScalarIntConstantExpr &i);
void RequiresPositiveParameter(
const OmpClause &clause, const parser::ScalarIntExpr &i);

bool CurrentDirectiveIsNested() { return ompContext_.size() > 0; };
bool HasInvalidWorksharingNesting(
const parser::CharBlock &, const OmpDirectiveSet &);
Expand Down
40 changes: 40 additions & 0 deletions flang/test/semantics/omp-clause-validity01.f90
Expand Up @@ -337,6 +337,46 @@
enddo
enddo

! 2.9.2 taskloop -> TASKLOOP [taskloop-clause[ [,] taskloop-clause]...]
! taskloop-clause -> if-clause |
! shared-clause |
! private-clause |
! firstprivate-clause |
! lastprivate-clause |
! default-clause |
! grainsize-clause |
! num-tasks-clause |
! collapse-clause |
! final-clause |
! priority-clause |
! untied-clause |
! mergeable-clause |
! nogroup-clause

!$omp taskloop
do i = 1, N
a = 3.14
enddo

!ERROR: SCHEDULE clause is not allowed on the TASKLOOP directive
!$omp taskloop schedule(static)
do i = 1, N
a = 3.14
enddo

!ERROR: GRAINSIZE and NUM_TASKS are mutually exclusive and may not appear on the same TASKLOOP directive
!$omp taskloop num_tasks(3) grainsize(2)
do i = 1,N
a = 3.14
enddo

!ERROR: At most one NUM_TASKS clause can appear on the TASKLOOP directive
!$omp taskloop num_tasks(3) num_tasks(2)
do i = 1,N
a = 3.14
enddo


! Standalone Directives (basic)

!$omp taskyield
Expand Down

0 comments on commit f1212c6

Please sign in to comment.