[flang][OpenMP] Added semantic checks for hint clause

This patch improves semantic checks for hint clause.
It checks "hint-expression is a constant expression
that evaluates to a scalar value with kind
`omp_sync_hint_kind` and a value that is a valid
synchronization hint."

Reviewed By: peixin

Differential Revision: https://reviews.llvm.org/D127615
This commit is contained in:
Nimish Mishra 2022-07-14 18:24:57 +05:30
parent a56b76d9ca
commit 7dc18a62e4
4 changed files with 275 additions and 0 deletions

View file

@ -314,6 +314,48 @@ void OmpStructureChecker::CheckPredefinedAllocatorRestriction(
}
}
template <class D>
void OmpStructureChecker::CheckHintClause(
D *leftOmpClauseList, D *rightOmpClauseList) {
auto checkForValidHintClause = [&](const D *clauseList) {
for (const auto &clause : clauseList->v) {
const Fortran::parser::OmpClause *ompClause = nullptr;
if constexpr (std::is_same_v<D,
const Fortran::parser::OmpAtomicClauseList>) {
ompClause = std::get_if<Fortran::parser::OmpClause>(&clause.u);
if (!ompClause)
continue;
} else if constexpr (std::is_same_v<D,
const Fortran::parser::OmpClauseList>) {
ompClause = &clause;
}
if (const Fortran::parser::OmpClause::Hint *
hintClause{
std::get_if<Fortran::parser::OmpClause::Hint>(&ompClause->u)}) {
std::optional<std::int64_t> hintValue = GetIntValue(hintClause->v);
if (hintValue && hintValue.value() >= 0) {
if((hintValue.value() & 0xC) == 0xC /*`omp_sync_hint_nonspeculative` and `omp_lock_hint_speculative`*/
|| (hintValue.value() & 0x3) == 0x3 /*`omp_sync_hint_uncontended` and omp_sync_hint_contended*/ )
context_.Say(clause.source,
"Hint clause value "
"is not a valid OpenMP synchronization value"_err_en_US);
} else {
context_.Say(clause.source,
"Hint clause must have non-negative constant "
"integer expression"_err_en_US);
}
}
}
};
if (leftOmpClauseList) {
checkForValidHintClause(leftOmpClauseList);
}
if (rightOmpClauseList) {
checkForValidHintClause(rightOmpClauseList);
}
}
void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) {
// Simd Construct with Ordered Construct Nesting check
// We cannot use CurrentDirectiveIsNested() here because
@ -1277,6 +1319,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPCriticalConstruct &x) {
parser::MessageFormattedText{
"Hint clause other than omp_sync_hint_none cannot be specified for an unnamed CRITICAL directive"_err_en_US});
}
CheckHintClause<const parser::OmpClauseList>(&ompClause, nullptr);
}
void OmpStructureChecker::Leave(const parser::OpenMPCriticalConstruct &) {
@ -1580,6 +1623,9 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
CheckAtomicMemoryOrderClause(
&std::get<parser::OmpAtomicClauseList>(atomicConstruct.t),
nullptr);
CheckHintClause<const parser::OmpAtomicClauseList>(
&std::get<parser::OmpAtomicClauseList>(atomicConstruct.t),
nullptr);
},
[&](const parser::OmpAtomicUpdate &atomicUpdate) {
const auto &dir{std::get<parser::Verbatim>(atomicUpdate.t)};
@ -1591,6 +1637,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
.statement);
CheckAtomicMemoryOrderClause(
&std::get<0>(atomicUpdate.t), &std::get<2>(atomicUpdate.t));
CheckHintClause<const parser::OmpAtomicClauseList>(
&std::get<0>(atomicUpdate.t), &std::get<2>(atomicUpdate.t));
},
[&](const auto &atomicConstruct) {
const auto &dir{std::get<parser::Verbatim>(atomicConstruct.t)};
@ -1598,6 +1646,9 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
dir.source, llvm::omp::Directive::OMPD_atomic);
CheckAtomicMemoryOrderClause(&std::get<0>(atomicConstruct.t),
&std::get<2>(atomicConstruct.t));
CheckHintClause<const parser::OmpAtomicClauseList>(
&std::get<0>(atomicConstruct.t),
&std::get<2>(atomicConstruct.t));
},
},
x.u);

View file

@ -268,6 +268,7 @@ private:
void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
int GetDirectiveNest(const int index) { return directiveNest_[index]; }
template <typename D> void CheckHintClause(D *, D *);
enum directiveNestType {
SIMDNest,

View file

@ -0,0 +1,105 @@
! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
! Semantic checks on hint clauses, as they appear on atomic constructs
program sample
use omp_lib
integer :: x, y
logical :: z
real :: k
integer :: p(1)
integer, parameter :: a = 1
!$omp atomic hint(1) write
y = 2
!$omp atomic read hint(2)
y = x
!ERROR: Hint clause value is not a valid OpenMP synchronization value
!$omp atomic hint(3)
y = y + 10
!$omp atomic update hint(5)
y = x
!ERROR: Hint clause value is not a valid OpenMP synchronization value
!$omp atomic hint(7) capture
y = x
x = y
!$omp end atomic
!ERROR: Hint clause must have non-negative constant integer expression
!ERROR: Must be a constant value
!$omp atomic update hint(x)
y = y * 1
!$omp atomic read hint(4)
y = x
!$omp atomic hint(8)
x = x * y
!$omp atomic write hint(omp_sync_hint_uncontended)
x = 10 * y
!$omp atomic hint(omp_lock_hint_speculative)
x = y + x
!ERROR: Hint clause must have non-negative constant integer expression
!ERROR: Must be a constant value
!$omp atomic hint(omp_sync_hint_uncontended + omp_sync_hint) read
y = x
!$omp atomic hint(omp_sync_hint_nonspeculative)
y = y * 9
!$omp atomic hint(omp_sync_hint_none) read
y = x
!$omp atomic read hint(omp_sync_hint_uncontended + omp_lock_hint_speculative)
y = x
!$omp atomic hint(omp_lock_hint_nonspeculative + omp_lock_hint_uncontended)
x = x * y
!$omp atomic write hint(omp_lock_hint_contended + omp_sync_hint_speculative)
x = 10 * y
!$omp atomic hint(omp_lock_hint_contended + omp_sync_hint_nonspeculative)
x = y + x
!ERROR: Hint clause value is not a valid OpenMP synchronization value
!$omp atomic hint(omp_sync_hint_uncontended + omp_sync_hint_contended) read
y = x
!ERROR: Hint clause value is not a valid OpenMP synchronization value
!$omp atomic hint(omp_sync_hint_nonspeculative + omp_lock_hint_speculative)
y = y * 9
!ERROR: Hint clause must have non-negative constant integer expression
!$omp atomic hint(1.0) read
y = x
!ERROR: Hint clause must have non-negative constant integer expression
!ERROR: Operands of + must be numeric; have LOGICAL(4) and INTEGER(4)
!$omp atomic hint(z + omp_sync_hint_nonspeculative) read
y = x
!ERROR: Hint clause must have non-negative constant integer expression
!ERROR: Must be a constant value
!$omp atomic hint(k + omp_sync_hint_speculative) read
y = x
!ERROR: Hint clause must have non-negative constant integer expression
!ERROR: Must be a constant value
!$omp atomic hint(p(1) + omp_sync_hint_uncontended) write
x = 10 * y
!$omp atomic write hint(a)
x = y + x
!$omp atomic hint(abs(-1)) write
x = 7
!$omp atomic hint(omp_sync_hint_uncontended + omp_sync_hint_uncontended + omp_sync_hint_speculative) write
x = 7
end program

View file

@ -0,0 +1,118 @@
! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
! Semantic checks on hint clauses, as they appear on critical construct
program sample
use omp_lib
integer :: y
logical :: z
real :: k
integer :: p(1)
!$omp critical (name) hint(1)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(2)
y = 2
!$omp end critical (name)
!ERROR: Hint clause value is not a valid OpenMP synchronization value
!$omp critical (name) hint(3)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(5)
y = 2
!$omp end critical (name)
!ERROR: Hint clause value is not a valid OpenMP synchronization value
!$omp critical (name) hint(7)
y = 2
!$omp end critical (name)
!ERROR: Hint clause must have non-negative constant integer expression
!ERROR: Must be a constant value
!$omp critical (name) hint(x)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(4)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(8)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(omp_sync_hint_uncontended)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(omp_lock_hint_speculative)
y = 2
!$omp end critical (name)
!ERROR: Hint clause must have non-negative constant integer expression
!ERROR: Must be a constant value
!$omp critical (name) hint(omp_sync_hint_uncontended + omp_sync_hint)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(omp_sync_hint_nonspeculative)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(omp_sync_hint_none)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(omp_sync_hint_uncontended + omp_lock_hint_speculative)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(omp_lock_hint_nonspeculative + omp_lock_hint_uncontended)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(omp_lock_hint_contended + omp_sync_hint_speculative)
y = 2
!$omp end critical (name)
!$omp critical (name) hint(omp_lock_hint_contended + omp_sync_hint_nonspeculative)
y = 2
!$omp end critical (name)
!ERROR: Hint clause value is not a valid OpenMP synchronization value
!$omp critical (name) hint(omp_sync_hint_uncontended + omp_sync_hint_contended)
y = 2
!$omp end critical (name)
!ERROR: Hint clause value is not a valid OpenMP synchronization value
!$omp critical (name) hint(omp_sync_hint_nonspeculative + omp_lock_hint_speculative)
y = 2
!$omp end critical (name)
!ERROR: Hint clause must have non-negative constant integer expression
!$omp critical (name) hint(1.0)
y = 2
!$omp end critical (name)
!ERROR: Hint clause must have non-negative constant integer expression
!ERROR: Operands of + must be numeric; have LOGICAL(4) and INTEGER(4)
!$omp critical (name) hint(z + omp_sync_hint_nonspeculative)
y = 2
!$omp end critical (name)
!ERROR: Hint clause must have non-negative constant integer expression
!ERROR: Must be a constant value
!$omp critical (name) hint(k + omp_sync_hint_speculative)
y = 2
!$omp end critical (name)
!ERROR: Hint clause must have non-negative constant integer expression
!ERROR: Must be a constant value
!$omp critical (name) hint(p(1) + omp_sync_hint_uncontended)
y = 2
!$omp end critical (name)
end program