Skip to content

Commit

Permalink
Added OpenMP 5.0 specification based semantic checks for CRITICAL con…
Browse files Browse the repository at this point in the history
…struct name resolution

As reported in https://bugs.llvm.org/show_bug.cgi?id=48145, name resolution for omp critical construct was failing. This patch adds functionality to help that name resolution as well as implementation to catch name mismatches.

The following semantic restrictions are therefore handled here:

- If a name is specified on a critical directive, the same name must also be specified on the end critical directive

- If no name appears on the critical directive, no name can appear on the end critical directive

- If a name appears on either the start critical directive or the end critical directive

Reviewed By: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D110502
  • Loading branch information
NimishMishra authored and nimishra committed Oct 12, 2021
1 parent 098a0d8 commit fe2d053
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 4 deletions.
2 changes: 1 addition & 1 deletion flang/include/flang/Parser/parse-tree.h
Expand Up @@ -3594,7 +3594,7 @@ struct OpenMPDeclarativeConstruct {
struct OmpCriticalDirective {
TUPLE_CLASS_BOILERPLATE(OmpCriticalDirective);
CharBlock source;
std::tuple<Verbatim, std::optional<Name>, std::optional<OmpClause>> t;
std::tuple<Verbatim, std::optional<Name>, OmpClauseList> t;
};
struct OmpEndCriticalDirective {
TUPLE_CLASS_BOILERPLATE(OmpEndCriticalDirective);
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Parser/openmp-parsers.cpp
Expand Up @@ -469,7 +469,7 @@ TYPE_PARSER(startOmpLine >>
verbatim("END CRITICAL"_tok), maybe(parenthesized(name)))) /
endOmpLine)
TYPE_PARSER(sourced(construct<OmpCriticalDirective>(verbatim("CRITICAL"_tok),
maybe(parenthesized(name)), maybe(Parser<OmpClause>{}))) /
maybe(parenthesized(name)), Parser<OmpClauseList>{})) /
endOmpLine)

TYPE_PARSER(construct<OpenMPCriticalConstruct>(
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Parser/unparse.cpp
Expand Up @@ -2287,7 +2287,7 @@ class UnparseVisitor {
BeginOpenMP();
Word("!$OMP CRITICAL");
Walk(" (", std::get<std::optional<Name>>(x.t), ")");
Walk(std::get<std::optional<OmpClause>>(x.t));
Walk(std::get<OmpClauseList>(x.t));
Put("\n");
EndOpenMP();
}
Expand Down
30 changes: 30 additions & 0 deletions flang/lib/Semantics/check-omp-structure.cpp
Expand Up @@ -1024,9 +1024,39 @@ void OmpStructureChecker::Leave(const parser::OpenMPCancelConstruct &) {

void OmpStructureChecker::Enter(const parser::OpenMPCriticalConstruct &x) {
const auto &dir{std::get<parser::OmpCriticalDirective>(x.t)};
const auto &endDir{std::get<parser::OmpEndCriticalDirective>(x.t)};
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_critical);
const auto &block{std::get<parser::Block>(x.t)};
CheckNoBranching(block, llvm::omp::Directive::OMPD_critical, dir.source);
const auto &dirName{std::get<std::optional<parser::Name>>(dir.t)};
const auto &endDirName{std::get<std::optional<parser::Name>>(endDir.t)};
const auto &ompClause{std::get<parser::OmpClauseList>(dir.t)};
if (dirName && endDirName &&
dirName->ToString().compare(endDirName->ToString())) {
context_
.Say(endDirName->source,
parser::MessageFormattedText{
"CRITICAL directive names do not match"_err_en_US})
.Attach(dirName->source, "should be "_en_US);
} else if (dirName && !endDirName) {
context_
.Say(dirName->source,
parser::MessageFormattedText{
"CRITICAL directive names do not match"_err_en_US})
.Attach(dirName->source, "should be NULL"_en_US);
} else if (!dirName && endDirName) {
context_
.Say(endDirName->source,
parser::MessageFormattedText{
"CRITICAL directive names do not match"_err_en_US})
.Attach(endDirName->source, "should be NULL"_en_US);
}
if (!dirName && !ompClause.source.empty() &&
ompClause.source.NULTerminatedToString() != "hint(omp_sync_hint_none)") {
context_.Say(dir.source,
parser::MessageFormattedText{
"Hint clause other than omp_sync_hint_none cannot be specified for an unnamed CRITICAL directive"_err_en_US});
}
}

void OmpStructureChecker::Leave(const parser::OpenMPCriticalConstruct &) {
Expand Down
27 changes: 26 additions & 1 deletion flang/lib/Semantics/resolve-directives.cpp
Expand Up @@ -293,6 +293,8 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {

bool Pre(const parser::OpenMPBlockConstruct &);
void Post(const parser::OpenMPBlockConstruct &);
bool Pre(const parser::OmpCriticalDirective &x);
bool Pre(const parser::OmpEndCriticalDirective &x);

void Post(const parser::OmpBeginBlockDirective &) {
GetContext().withinConstruct = true;
Expand Down Expand Up @@ -476,7 +478,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
static constexpr Symbol::Flags ompFlagsRequireNewSymbol{
Symbol::Flag::OmpPrivate, Symbol::Flag::OmpLinear,
Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate,
Symbol::Flag::OmpReduction};
Symbol::Flag::OmpReduction, Symbol::Flag::OmpCriticalLock};

static constexpr Symbol::Flags ompFlagsRequireMark{
Symbol::Flag::OmpThreadprivate};
Expand Down Expand Up @@ -1374,6 +1376,22 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPSectionsConstruct &x) {
return true;
}

bool OmpAttributeVisitor::Pre(const parser::OmpCriticalDirective &x) {
const auto &name{std::get<std::optional<parser::Name>>(x.t)};
if (name) {
ResolveOmpName(*name, Symbol::Flag::OmpCriticalLock);
}
return true;
}

bool OmpAttributeVisitor::Pre(const parser::OmpEndCriticalDirective &x) {
const auto &name{std::get<std::optional<parser::Name>>(x.t)};
if (name) {
ResolveOmpName(*name, Symbol::Flag::OmpCriticalLock);
}
return true;
}

bool OmpAttributeVisitor::Pre(const parser::OpenMPCriticalConstruct &x) {
const auto &criticalDir{std::get<parser::OmpCriticalDirective>(x.t)};
PushContext(criticalDir.source, llvm::omp::Directive::OMPD_critical);
Expand Down Expand Up @@ -1497,6 +1515,13 @@ void OmpAttributeVisitor::ResolveOmpName(
AddToContextObjectWithDSA(*resolvedSymbol, ompFlag);
}
}
} else if (ompFlagsRequireNewSymbol.test(ompFlag)) {
const auto pair{GetContext().scope.try_emplace(
name.source, Attrs{}, ObjectEntityDetails{})};
CHECK(pair.second);
name.symbol = &pair.first->second.get();
} else {
DIE("OpenMP Name resolution failed");
}
}

Expand Down
41 changes: 41 additions & 0 deletions flang/test/Semantics/omp-sync-critical01.f90
@@ -0,0 +1,41 @@
! RUN: %python %S/test_errors.py %s %flang -fopenmp

! OpenMP Version 5.0
! 2.17.1 critical construct
! CRITICAL start and end CRITICAL directive names mismatch
integer function timer_tick_sec()
implicit none
integer t

!$OMP CRITICAL
t = t + 1
!$OMP END CRITICAL

!$OMP CRITICAL (foo)
t = t + 1
!$OMP END CRITICAL (foo)

!$OMP CRITICAL (foo)
t = t + 1
!ERROR: CRITICAL directive names do not match
!$OMP END CRITICAL (bar)

!$OMP CRITICAL (bar)
t = t + 1
!ERROR: CRITICAL directive names do not match
!$OMP END CRITICAL (foo)

!ERROR: CRITICAL directive names do not match
!$OMP CRITICAL (bar)
t = t + 1
!$OMP END CRITICAL

!$OMP CRITICAL
t = t + 1
!ERROR: CRITICAL directive names do not match
!$OMP END CRITICAL (foo)

timer_tick_sec = t
return

end function timer_tick_sec
53 changes: 53 additions & 0 deletions flang/test/Semantics/omp-sync-critical02.f90
@@ -0,0 +1,53 @@
! RUN: %python %S/test_errors.py %s %flang -fopenmp

! OpenMP Version 5.0
! 2.17.1 critical construct
! If the hint clause is specified, the critical construct must have a name.
program sample
use omp_lib
integer i, j
!ERROR: Hint clause other than omp_sync_hint_none cannot be specified for an unnamed CRITICAL directive
!$omp critical hint(omp_lock_hint_speculative)
j = j + 1
!$omp end critical

!$omp critical (foo) hint(omp_lock_hint_speculative)
i = i - 1
!$omp end critical (foo)

!ERROR: Hint clause other than omp_sync_hint_none cannot be specified for an unnamed CRITICAL directive
!$omp critical hint(omp_lock_hint_nonspeculative)
j = j + 1
!$omp end critical

!$omp critical (foo) hint(omp_lock_hint_nonspeculative)
i = i - 1
!$omp end critical (foo)

!ERROR: Hint clause other than omp_sync_hint_none cannot be specified for an unnamed CRITICAL directive
!$omp critical hint(omp_lock_hint_contended)
j = j + 1
!$omp end critical

!$omp critical (foo) hint(omp_lock_hint_contended)
i = i - 1
!$omp end critical (foo)

!ERROR: Hint clause other than omp_sync_hint_none cannot be specified for an unnamed CRITICAL directive
!$omp critical hint(omp_lock_hint_uncontended)
j = j + 1
!$omp end critical

!$omp critical (foo) hint(omp_lock_hint_uncontended)
i = i - 1
!$omp end critical (foo)

!$omp critical hint(omp_sync_hint_none)
j = j + 1
!$omp end critical

!$omp critical (foo) hint(omp_sync_hint_none)
i = i - 1
!$omp end critical (foo)

end program sample

0 comments on commit fe2d053

Please sign in to comment.