diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index b26f3e23f9ec7..fb67cb41953c7 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -170,20 +170,22 @@ bool OmpStructureChecker::IsCloselyNestedRegion(const OmpDirectiveSet &set) { return false; } +void OmpStructureChecker::CheckMultipleOccurrence( + semantics::UnorderedSymbolSet &listVars, + const std::list &nameList, const parser::CharBlock &item, + const std::string &clauseName) { + for (auto const &var : nameList) { + if (llvm::is_contained(listVars, *(var.symbol))) { + context_.Say(item, + "List item '%s' present at multiple %s clauses"_err_en_US, + var.ToString(), clauseName); + } + listVars.insert(*(var.symbol)); + } +} + void OmpStructureChecker::CheckMultListItems() { semantics::UnorderedSymbolSet listVars; - auto checkMultipleOcurrence = [&](const std::list &nameList, - const parser::CharBlock &item, - const std::string &clauseName) { - for (auto const &var : nameList) { - if (llvm::is_contained(listVars, *(var.symbol))) { - context_.Say(item, - "List item '%s' present at multiple %s clauses"_err_en_US, - var.ToString(), clauseName); - } - listVars.insert(*(var.symbol)); - } - }; // Aligned clause auto alignedClauses{FindClauses(llvm::omp::Clause::OMPC_aligned)}; @@ -216,7 +218,8 @@ void OmpStructureChecker::CheckMultListItems() { } } } - checkMultipleOcurrence(alignedNameList, itr->second->source, "ALIGNED"); + CheckMultipleOccurrence( + listVars, alignedNameList, itr->second->source, "ALIGNED"); } // Nontemporal clause @@ -226,7 +229,8 @@ void OmpStructureChecker::CheckMultListItems() { const auto &nontempClause{ std::get(itr->second->u)}; const auto &nontempNameList{nontempClause.v}; - checkMultipleOcurrence(nontempNameList, itr->second->source, "NONTEMPORAL"); + CheckMultipleOccurrence( + listVars, nontempNameList, itr->second->source, "NONTEMPORAL"); } } @@ -2000,10 +2004,8 @@ CHECK_SIMPLE_CLAUSE(UnifiedSharedMemory, OMPC_unified_shared_memory) CHECK_SIMPLE_CLAUSE(Uniform, OMPC_uniform) CHECK_SIMPLE_CLAUSE(Unknown, OMPC_unknown) CHECK_SIMPLE_CLAUSE(Untied, OMPC_untied) -CHECK_SIMPLE_CLAUSE(UseDevicePtr, OMPC_use_device_ptr) CHECK_SIMPLE_CLAUSE(UsesAllocators, OMPC_uses_allocators) CHECK_SIMPLE_CLAUSE(Update, OMPC_update) -CHECK_SIMPLE_CLAUSE(UseDeviceAddr, OMPC_use_device_addr) CHECK_SIMPLE_CLAUSE(Write, OMPC_write) CHECK_SIMPLE_CLAUSE(Init, OMPC_init) CHECK_SIMPLE_CLAUSE(Use, OMPC_use) @@ -2618,6 +2620,89 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyin &x) { currSymbols, llvm::omp::Clause::OMPC_copyin); } +void OmpStructureChecker::CheckStructureElement( + const parser::OmpObjectList &ompObjectList, + const llvm::omp::Clause clause) { + for (const auto &ompObject : ompObjectList.v) { + common::visit( + common::visitors{ + [&](const parser::Designator &designator) { + if (const auto *dataRef{ + std::get_if(&designator.u)}) { + if (parser::Unwrap(ompObject)) { + context_.Say(GetContext().clauseSource, + "A variable that is part of another variable " + "(structure element) cannot appear on the %s " + "%s clause"_err_en_US, + ContextDirectiveAsFortran(), + parser::ToUpperCaseLetters(getClauseName(clause).str())); + } + } + }, + [&](const parser::Name &name) {}, + }, + ompObject.u); + } + return; +} + +void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &x) { + CheckStructureElement(x.v, llvm::omp::Clause::OMPC_use_device_ptr); + CheckAllowed(llvm::omp::Clause::OMPC_use_device_ptr); + SymbolSourceMap currSymbols; + GetSymbolsInObjectList(x.v, currSymbols); + semantics::UnorderedSymbolSet listVars; + auto useDevicePtrClauses{FindClauses(llvm::omp::Clause::OMPC_use_device_ptr)}; + for (auto itr = useDevicePtrClauses.first; itr != useDevicePtrClauses.second; + ++itr) { + const auto &useDevicePtrClause{ + std::get(itr->second->u)}; + const auto &useDevicePtrList{useDevicePtrClause.v}; + std::list useDevicePtrNameList; + for (const auto &ompObject : useDevicePtrList.v) { + if (const auto *name{parser::Unwrap(ompObject)}) { + if (name->symbol) { + if (!(IsBuiltinCPtr(*(name->symbol)))) { + context_.Say(itr->second->source, + "'%s' in USE_DEVICE_PTR clause must be of type C_PTR"_err_en_US, + name->ToString()); + } else { + useDevicePtrNameList.push_back(*name); + } + } + } + } + CheckMultipleOccurrence( + listVars, useDevicePtrNameList, itr->second->source, "USE_DEVICE_PTR"); + } +} + +void OmpStructureChecker::Enter(const parser::OmpClause::UseDeviceAddr &x) { + CheckStructureElement(x.v, llvm::omp::Clause::OMPC_use_device_addr); + CheckAllowed(llvm::omp::Clause::OMPC_use_device_addr); + SymbolSourceMap currSymbols; + GetSymbolsInObjectList(x.v, currSymbols); + semantics::UnorderedSymbolSet listVars; + auto useDeviceAddrClauses{ + FindClauses(llvm::omp::Clause::OMPC_use_device_addr)}; + for (auto itr = useDeviceAddrClauses.first; + itr != useDeviceAddrClauses.second; ++itr) { + const auto &useDeviceAddrClause{ + std::get(itr->second->u)}; + const auto &useDeviceAddrList{useDeviceAddrClause.v}; + std::list useDeviceAddrNameList; + for (const auto &ompObject : useDeviceAddrList.v) { + if (const auto *name{parser::Unwrap(ompObject)}) { + if (name->symbol) { + useDeviceAddrNameList.push_back(*name); + } + } + } + CheckMultipleOccurrence(listVars, useDeviceAddrNameList, + itr->second->source, "USE_DEVICE_ADDR"); + } +} + llvm::StringRef OmpStructureChecker::getClauseName(llvm::omp::Clause clause) { return llvm::omp::getOpenMPClauseName(clause); } diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 195b0c2326f54..d41d60755edbc 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -195,7 +195,12 @@ class OmpStructureChecker } private: + void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars, + const std::list &nameList, const parser::CharBlock &item, + const std::string &clauseName); void CheckMultListItems(); + void CheckStructureElement(const parser::OmpObjectList &ompObjectList, + const llvm::omp::Clause clause); bool HasInvalidWorksharingNesting( const parser::CharBlock &, const OmpDirectiveSet &); bool IsCloselyNestedRegion(const OmpDirectiveSet &set); diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 747f1e414eb21..25c398ce1e703 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -1829,6 +1829,18 @@ void OmpAttributeVisitor::ResolveOmpObject( GetContext().directive) .str())); } + if ((GetContext().directive == + llvm::omp::Directive::OMPD_target_data) && + (((ompFlag == Symbol::Flag::OmpUseDevicePtr) && + symbol->test(Symbol::Flag::OmpUseDeviceAddr)) || + ((ompFlag == Symbol::Flag::OmpUseDeviceAddr) && + symbol->test(Symbol::Flag::OmpUseDevicePtr)))) { + context_.Say(designator.source, + "Variable '%s' may not " + "appear on both USE_DEVICE_PTR and USE_DEVICE_ADDR " + "clauses on a TARGET DATA construct"_err_en_US, + symbol->name()); + } } } else { // Array sections to be changed to substrings as needed diff --git a/flang/test/Semantics/OpenMP/use_device_addr1.f90 b/flang/test/Semantics/OpenMP/use_device_addr1.f90 new file mode 100644 index 0000000000000..867e324b68ad9 --- /dev/null +++ b/flang/test/Semantics/OpenMP/use_device_addr1.f90 @@ -0,0 +1,33 @@ +! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp +! OpenMP Version 5.0 +! 2.10.1 use_device_ptr clause +! List item in USE_DEVICE_ADDR clause must not be structure element. +! Same list item can not be present multiple times or in multipe +! USE_DEVICE_ADDR clauses. + +subroutine omp_target_data + integer :: a(1024) + integer, target :: b(1024) + type my_type + integer :: my_b(1024) + end type my_type + + type(my_type) :: my_var + a = 1 + + !ERROR: A variable that is part of another variable (structure element) cannot appear on the TARGET DATA USE_DEVICE_ADDR clause + !$omp target data map(tofrom: a) use_device_addr(my_var%my_b) + my_var%my_b = a + !$omp end target data + + !ERROR: List item 'b' present at multiple USE_DEVICE_ADDR clauses + !$omp target data map(tofrom: a) use_device_addr(b,b) + b = a + !$omp end target data + + !ERROR: List item 'b' present at multiple USE_DEVICE_ADDR clauses + !$omp target data map(tofrom: a) use_device_addr(b) use_device_addr(b) + b = a + !$omp end target data + +end subroutine omp_target_data diff --git a/flang/test/Semantics/OpenMP/use_device_ptr1.f90 b/flang/test/Semantics/OpenMP/use_device_ptr1.f90 new file mode 100644 index 0000000000000..af89698a5c5a9 --- /dev/null +++ b/flang/test/Semantics/OpenMP/use_device_ptr1.f90 @@ -0,0 +1,64 @@ +! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp +! OpenMP Version 5.0 +! 2.10.1 use_device_ptr clause +! List item in USE_DEVICE_PTR clause must not be structure element. +! List item in USE_DEVICE_PTR clause must be of type C_PTR. +! List items that appear in a use_device_ptr clause can not appear in +! use_device_addr clause. +! Same list item can not be present multiple times or in multipe +! USE_DEVICE_PTR clauses. + +subroutine omp_target_data + use iso_c_binding + integer :: a(1024) + type(C_PTR) :: b + integer, pointer :: arrayB + type my_type + type(C_PTR) :: my_cptr + end type my_type + + type(my_type) :: my_var + a = 1 + + !ERROR: A variable that is part of another variable (structure element) cannot appear on the TARGET DATA USE_DEVICE_PTR clause + !$omp target data map(tofrom: a, arrayB) use_device_ptr(my_var%my_cptr) + allocate(arrayB) + call c_f_pointer(my_var%my_cptr, arrayB) + a = arrayB + !$omp end target data + + !ERROR: 'a' in USE_DEVICE_PTR clause must be of type C_PTR + !$omp target data map(tofrom: a) use_device_ptr(a) + a = 2 + !$omp end target data + + !ERROR: List item 'b' present at multiple USE_DEVICE_PTR clauses + !$omp target data map(tofrom: a, arrayB) use_device_ptr(b) use_device_ptr(b) + allocate(arrayB) + call c_f_pointer(b, arrayB) + a = arrayB + !$omp end target data + + !ERROR: List item 'b' present at multiple USE_DEVICE_PTR clauses + !$omp target data map(tofrom: a, arrayB) use_device_ptr(b,b) + allocate(arrayB) + call c_f_pointer(b, arrayB) + a = arrayB + !$omp end target data + + !ERROR: Variable 'b' may not appear on both USE_DEVICE_PTR and USE_DEVICE_ADDR clauses on a TARGET DATA construct + !$omp target data map(tofrom: a, arrayB) use_device_addr(b) use_device_ptr(b) + allocate(arrayB) + call c_f_pointer(b, arrayB) + a = arrayB + !$omp end target data + + !ERROR: Variable 'b' may not appear on both USE_DEVICE_PTR and USE_DEVICE_ADDR clauses on a TARGET DATA construct + !$omp target data map(tofrom: a, arrayB) use_device_ptr(b) use_device_addr(b) + allocate(arrayB) + call c_f_pointer(b, arrayB) + a = arrayB + !$omp end target data + +end subroutine omp_target_data +