forked from OSchip/llvm-project
[Flang][OpenMP] Add semantic checks for OpenMP Private clause.
Add the semantic checks for the OpenMP 4.5 - 2.15.3.3 Private clause. 1. Pointers with the INTENT(IN) attribute may not appear in a private clause. 2. Variables that appear in namelist statements may not appear in a private clause. A flag 'InNamelist' is added to the Symbol::Flag to identify the symbols in Namelist statemnts. Test cases : omp-private01.f90, omp-private02.f90 Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D90210
This commit is contained in:
parent
1b723a955d
commit
7a91794d5b
|
@ -493,6 +493,7 @@ public:
|
||||||
LocalityLocalInit, // named in LOCAL_INIT locality-spec
|
LocalityLocalInit, // named in LOCAL_INIT locality-spec
|
||||||
LocalityShared, // named in SHARED locality-spec
|
LocalityShared, // named in SHARED locality-spec
|
||||||
InDataStmt, // initialized in a DATA statement
|
InDataStmt, // initialized in a DATA statement
|
||||||
|
InNamelist, // flag is set if the symbol is in Namelist statement
|
||||||
// OpenACC data-sharing attribute
|
// OpenACC data-sharing attribute
|
||||||
AccPrivate, AccFirstPrivate, AccShared,
|
AccPrivate, AccFirstPrivate, AccShared,
|
||||||
// OpenACC data-mapping attribute
|
// OpenACC data-mapping attribute
|
||||||
|
|
|
@ -417,6 +417,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Shared &x) {
|
||||||
void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) {
|
void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) {
|
||||||
CheckAllowed(llvm::omp::Clause::OMPC_private);
|
CheckAllowed(llvm::omp::Clause::OMPC_private);
|
||||||
CheckIsVarPartOfAnotherVar(x.v);
|
CheckIsVarPartOfAnotherVar(x.v);
|
||||||
|
CheckIntentInPointer(x.v, llvm::omp::Clause::OMPC_private);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
|
void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
|
||||||
|
@ -693,4 +694,38 @@ void OmpStructureChecker::CheckDependArraySection(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OmpStructureChecker::CheckIntentInPointer(
|
||||||
|
const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
|
||||||
|
std::vector<const Symbol *> symbols;
|
||||||
|
GetSymbolsInObjectList(objectList, symbols);
|
||||||
|
for (const auto *symbol : symbols) {
|
||||||
|
if (IsPointer(*symbol) && IsIntentIn(*symbol)) {
|
||||||
|
context_.Say(GetContext().clauseSource,
|
||||||
|
"Pointer '%s' with the INTENT(IN) attribute may not appear "
|
||||||
|
"in a %s clause"_err_en_US,
|
||||||
|
symbol->name(),
|
||||||
|
parser::ToUpperCaseLetters(getClauseName(clause).str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OmpStructureChecker::GetSymbolsInObjectList(
|
||||||
|
const parser::OmpObjectList &objectList,
|
||||||
|
std::vector<const Symbol *> &symbols) {
|
||||||
|
for (const auto &ompObject : objectList.v) {
|
||||||
|
if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
|
||||||
|
if (const auto *symbol{name->symbol}) {
|
||||||
|
if (const auto *commonBlockDetails{
|
||||||
|
symbol->detailsIf<CommonBlockDetails>()}) {
|
||||||
|
for (const auto &object : commonBlockDetails->objects()) {
|
||||||
|
symbols.emplace_back(&object->GetUltimate());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
symbols.emplace_back(&symbol->GetUltimate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Fortran::semantics
|
} // namespace Fortran::semantics
|
||||||
|
|
|
@ -185,8 +185,11 @@ private:
|
||||||
void CheckDependList(const parser::DataRef &);
|
void CheckDependList(const parser::DataRef &);
|
||||||
void CheckDependArraySection(
|
void CheckDependArraySection(
|
||||||
const common::Indirection<parser::ArrayElement> &, const parser::Name &);
|
const common::Indirection<parser::ArrayElement> &, const parser::Name &);
|
||||||
|
|
||||||
void CheckIsVarPartOfAnotherVar(const parser::OmpObjectList &objList);
|
void CheckIsVarPartOfAnotherVar(const parser::OmpObjectList &objList);
|
||||||
|
void CheckIntentInPointer(
|
||||||
|
const parser::OmpObjectList &, const llvm::omp::Clause);
|
||||||
|
void GetSymbolsInObjectList(
|
||||||
|
const parser::OmpObjectList &, std::vector<const Symbol *> &);
|
||||||
};
|
};
|
||||||
} // namespace Fortran::semantics
|
} // namespace Fortran::semantics
|
||||||
#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
|
#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
|
||||||
|
|
|
@ -375,6 +375,8 @@ private:
|
||||||
const parser::Name &, const Symbol &, Symbol::Flag);
|
const parser::Name &, const Symbol &, Symbol::Flag);
|
||||||
|
|
||||||
void CheckAssocLoopLevel(std::int64_t level, const parser::OmpClause *clause);
|
void CheckAssocLoopLevel(std::int64_t level, const parser::OmpClause *clause);
|
||||||
|
void CheckObjectInNamelist(
|
||||||
|
const parser::Name &, const Symbol &, Symbol::Flag);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -1107,6 +1109,10 @@ void OmpAttributeVisitor::ResolveOmpObject(
|
||||||
if (dataSharingAttributeFlags.test(ompFlag)) {
|
if (dataSharingAttributeFlags.test(ompFlag)) {
|
||||||
CheckMultipleAppearances(*name, *symbol, ompFlag);
|
CheckMultipleAppearances(*name, *symbol, ompFlag);
|
||||||
}
|
}
|
||||||
|
if (privateDataSharingAttributeFlags.test(ompFlag)) {
|
||||||
|
CheckObjectInNamelist(*name, *symbol, ompFlag);
|
||||||
|
}
|
||||||
|
|
||||||
if (ompFlag == Symbol::Flag::OmpAllocate) {
|
if (ompFlag == Symbol::Flag::OmpAllocate) {
|
||||||
AddAllocateName(name);
|
AddAllocateName(name);
|
||||||
}
|
}
|
||||||
|
@ -1258,4 +1264,18 @@ void OmpAttributeVisitor::CheckDataCopyingClause(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OmpAttributeVisitor::CheckObjectInNamelist(
|
||||||
|
const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) {
|
||||||
|
if (symbol.GetUltimate().test(Symbol::Flag::InNamelist)) {
|
||||||
|
llvm::StringRef clauseName{"PRIVATE"};
|
||||||
|
if (ompFlag == Symbol::Flag::OmpFirstPrivate)
|
||||||
|
clauseName = "FIRSTPRIVATE";
|
||||||
|
else if (ompFlag == Symbol::Flag::OmpLastPrivate)
|
||||||
|
clauseName = "LASTPRIVATE";
|
||||||
|
context_.Say(name.source,
|
||||||
|
"Variable '%s' in NAMELIST cannot be in a %s clause"_err_en_US,
|
||||||
|
name.ToString(), clauseName.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Fortran::semantics
|
} // namespace Fortran::semantics
|
||||||
|
|
|
@ -4289,6 +4289,7 @@ bool DeclarationVisitor::Pre(const parser::NamelistStmt::Group &x) {
|
||||||
} else if (!ConvertToObjectEntity(*symbol)) {
|
} else if (!ConvertToObjectEntity(*symbol)) {
|
||||||
SayWithDecl(name, *symbol, "'%s' is not a variable"_err_en_US);
|
SayWithDecl(name, *symbol, "'%s' is not a variable"_err_en_US);
|
||||||
}
|
}
|
||||||
|
symbol->GetUltimate().set(Symbol::Flag::InNamelist);
|
||||||
details.add_object(*symbol);
|
details.add_object(*symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
|
||||||
|
! OpenMP Version 4.5
|
||||||
|
! 2.15.3.3 private Clause
|
||||||
|
! Pointers with the INTENT(IN) attribute may not appear in a private clause.
|
||||||
|
|
||||||
|
subroutine omp_private(p)
|
||||||
|
integer :: a(10), b(10), c(10)
|
||||||
|
integer, pointer, intent(in) :: p
|
||||||
|
|
||||||
|
a = 10
|
||||||
|
b = 20
|
||||||
|
|
||||||
|
!ERROR: Pointer 'p' with the INTENT(IN) attribute may not appear in a PRIVATE clause
|
||||||
|
!$omp parallel private(p)
|
||||||
|
c = a + b + p
|
||||||
|
!$omp end parallel
|
||||||
|
|
||||||
|
print *, c
|
||||||
|
|
||||||
|
end subroutine omp_private
|
|
@ -0,0 +1,46 @@
|
||||||
|
! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
|
||||||
|
! OpenMP Version 4.5
|
||||||
|
! 2.15.3.3 private Clause
|
||||||
|
! Variables that appear in namelist statements may not appear in a private clause.
|
||||||
|
|
||||||
|
module test
|
||||||
|
integer :: a, b, c
|
||||||
|
namelist /nlist1/ a, b
|
||||||
|
end module
|
||||||
|
|
||||||
|
program omp_private
|
||||||
|
use test
|
||||||
|
|
||||||
|
integer :: p(10) ,q(10)
|
||||||
|
namelist /nlist2/ c, d
|
||||||
|
|
||||||
|
a = 5
|
||||||
|
b = 10
|
||||||
|
c = 100
|
||||||
|
|
||||||
|
!ERROR: Variable 'a' in NAMELIST cannot be in a PRIVATE clause
|
||||||
|
!ERROR: Variable 'c' in NAMELIST cannot be in a PRIVATE clause
|
||||||
|
!$omp parallel private(a, c)
|
||||||
|
d = a + b
|
||||||
|
!$omp end parallel
|
||||||
|
|
||||||
|
call sb()
|
||||||
|
|
||||||
|
contains
|
||||||
|
subroutine sb()
|
||||||
|
namelist /nlist3/ p, q
|
||||||
|
|
||||||
|
!ERROR: Variable 'p' in NAMELIST cannot be in a PRIVATE clause
|
||||||
|
!ERROR: Variable 'd' in NAMELIST cannot be in a PRIVATE clause
|
||||||
|
!$omp parallel private(p, d)
|
||||||
|
p = c * b
|
||||||
|
q = p * d
|
||||||
|
!$omp end parallel
|
||||||
|
|
||||||
|
write(*, nlist1)
|
||||||
|
write(*, nlist2)
|
||||||
|
write(*, nlist3)
|
||||||
|
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
end program omp_private
|
Loading…
Reference in New Issue