diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -185,48 +185,101 @@ } }; - // Aligned clause - auto alignedClauses{FindClauses(llvm::omp::Clause::OMPC_aligned)}; - for (auto itr = alignedClauses.first; itr != alignedClauses.second; ++itr) { - const auto &alignedClause{ - std::get(itr->second->u)}; - const auto &alignedList{std::get<0>(alignedClause.v.t)}; - std::list alignedNameList; - for (const auto &ompObject : alignedList.v) { - if (const auto *name{parser::Unwrap(ompObject)}) { - if (name->symbol) { - if (FindCommonBlockContaining(*(name->symbol))) { - context_.Say(itr->second->source, - "'%s' is a common block name and can not appear in an " - "ALIGNED clause"_err_en_US, - name->ToString()); - } else if (!(IsBuiltinCPtr(*(name->symbol)) || - IsAllocatableOrPointer( - (name->symbol->GetUltimate())))) { - context_.Say(itr->second->source, - "'%s' in ALIGNED clause must be of type C_PTR, POINTER or " - "ALLOCATABLE"_err_en_US, - name->ToString()); + if (llvm::omp::simdSet.test(GetContext().directive)) { + // Aligned clause + auto alignedClauses{FindClauses(llvm::omp::Clause::OMPC_aligned)}; + for (auto itr = alignedClauses.first; itr != alignedClauses.second; ++itr) { + const auto &alignedClause{ + std::get(itr->second->u)}; + const auto &alignedList{std::get<0>(alignedClause.v.t)}; + std::list alignedNameList; + for (const auto &ompObject : alignedList.v) { + if (const auto *name{parser::Unwrap(ompObject)}) { + if (name->symbol) { + if (FindCommonBlockContaining(*(name->symbol))) { + context_.Say(itr->second->source, + "'%s' is a common block name and can not appear in an " + "ALIGNED clause"_err_en_US, + name->ToString()); + } else if (!(IsBuiltinCPtr(*(name->symbol)) || + IsAllocatableOrPointer( + (name->symbol->GetUltimate())))) { + context_.Say(itr->second->source, + "'%s' in ALIGNED clause must be of type C_PTR, POINTER or " + "ALLOCATABLE"_err_en_US, + name->ToString()); + } else { + alignedNameList.push_back(*name); + } } else { - alignedNameList.push_back(*name); + // The symbol is null, return early + return; } - } else { - // The symbol is null, return early - return; } } + checkMultipleOcurrence(alignedNameList, itr->second->source, "ALIGNED"); + } + + // Nontemporal clause + auto nonTemporalClauses{FindClauses(llvm::omp::Clause::OMPC_nontemporal)}; + for (auto itr = nonTemporalClauses.first; itr != nonTemporalClauses.second; + ++itr) { + const auto &nontempClause{ + std::get(itr->second->u)}; + const auto &nontempNameList{nontempClause.v}; + checkMultipleOcurrence( + nontempNameList, itr->second->source, "NONTEMPORAL"); + } + } + + if (GetContext().directive == llvm::omp::Directive::OMPD_target_data) { + listVars.clear(); + // USE_DEVICE_PTR clause + 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); + } + } + } + } + checkMultipleOcurrence( + useDevicePtrNameList, itr->second->source, "USE_DEVICE_PTR"); + } + + listVars.clear(); + // USE_DEVICE_ADDR clause + 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); + } + } + } + checkMultipleOcurrence( + useDeviceAddrNameList, itr->second->source, "USE_DEVICE_ADDR"); } - checkMultipleOcurrence(alignedNameList, itr->second->source, "ALIGNED"); - } - - // Nontemporal clause - auto nonTemporalClauses{FindClauses(llvm::omp::Clause::OMPC_nontemporal)}; - for (auto itr = nonTemporalClauses.first; itr != nonTemporalClauses.second; - ++itr) { - const auto &nontempClause{ - std::get(itr->second->u)}; - const auto &nontempNameList{nontempClause.v}; - checkMultipleOcurrence(nontempNameList, itr->second->source, "NONTEMPORAL"); } } @@ -1940,10 +1993,8 @@ 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) @@ -2556,6 +2607,58 @@ currSymbols, llvm::omp::Clause::OMPC_copyin); } +void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &x) { + for (const auto &ompObject : x.v.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 " + "USE_DEVICE_PTR clause"_err_en_US, + ContextDirectiveAsFortran()); + } + } + }, + [&](const parser::Name &name) {}, + }, + ompObject.u); + } + CheckAllowed(llvm::omp::Clause::OMPC_use_device_ptr); + SymbolSourceMap currSymbols; + GetSymbolsInObjectList(x.v, currSymbols); + CheckMultListItems(); +} + +void OmpStructureChecker::Enter(const parser::OmpClause::UseDeviceAddr &x) { + for (const auto &ompObject : x.v.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 " + "USE_DEVICE_ADDR clause"_err_en_US, + ContextDirectiveAsFortran()); + } + } + }, + [&](const parser::Name &name) {}, + }, + ompObject.u); + } + CheckAllowed(llvm::omp::Clause::OMPC_use_device_addr); + SymbolSourceMap currSymbols; + GetSymbolsInObjectList(x.v, currSymbols); + CheckMultListItems(); +} + llvm::StringRef OmpStructureChecker::getClauseName(llvm::omp::Clause clause) { return llvm::omp::getOpenMPClauseName(clause); } diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -1772,6 +1772,18 @@ "List items must be declared in the same scoping unit " "in which the ALLOCATE directive appears"_err_en_US); } + 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 --- /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 --- /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 +