diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -643,8 +643,8 @@ // OpenMP data-sharing attribute OmpShared, OmpPrivate, OmpLinear, OmpFirstPrivate, OmpLastPrivate, // OpenMP data-mapping attribute - OmpMapTo, OmpMapFrom, OmpMapAlloc, OmpMapRelease, OmpMapDelete, - OmpUseDevicePtr, OmpUseDeviceAddr, + OmpMapTo, OmpMapFrom, OmpMapToFrom, OmpMapAlloc, OmpMapRelease, + OmpMapDelete, OmpUseDevicePtr, OmpUseDeviceAddr, // OpenMP data-copying attribute OmpCopyIn, OmpCopyPrivate, // OpenMP miscellaneous flags @@ -674,6 +674,7 @@ void set_offset(std::size_t offset) { offset_ = offset; } // Give the symbol a name with a different source location but same chars. void ReplaceName(const SourceName &); + std::string OmpFlagToClauseName(Flag ompFlag); // Does symbol have this type of details? template bool has() const { 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 @@ -529,6 +529,34 @@ void Post(const parser::EorLabel &eorLabel) { CheckSourceLabel(eorLabel.v); } void Post(const parser::OmpMapClause &x) { + Symbol::Flag ompFlag = Symbol::Flag::OmpMapToFrom; + if (const auto &maptype{std::get>(x.t)}) { + using Type = parser::OmpMapType::Type; + const Type &type{std::get(maptype->t)}; + switch (type) { + case Type::To: + ompFlag = Symbol::Flag::OmpMapTo; + break; + case Type::From: + ompFlag = Symbol::Flag::OmpMapFrom; + break; + case Type::Tofrom: + ompFlag = Symbol::Flag::OmpMapToFrom; + break; + case Type::Alloc: + ompFlag = Symbol::Flag::OmpMapAlloc; + break; + case Type::Release: + ompFlag = Symbol::Flag::OmpMapRelease; + break; + case Type::Delete: + ompFlag = Symbol::Flag::OmpMapDelete; + break; + default: + assert(false && "Unsupported map-type"); + break; + } + } const auto &ompObjList{std::get(x.t)}; for (const auto &ompObj : ompObjList.v) { common::visit( @@ -536,6 +564,10 @@ [&](const parser::Designator &designator) { if (const auto *name{ semantics::getDesignatorNameIfDataRef(designator)}) { + if (name->symbol) { + name->symbol->set(ompFlag); + AddToContextObjectWithDSA(*name->symbol, ompFlag); + } if (name->symbol && semantics::IsAssumedSizeArray(*name->symbol)) { context_.Say(designator.source, @@ -1908,6 +1940,27 @@ if (const auto *name{ semantics::getDesignatorNameIfDataRef(designator)}) { if (auto *symbol{ResolveOmp(*name, ompFlag, currScope())}) { + auto checkExclusivelists = + [&](const Symbol *symbol1, Symbol::Flag firstOmpFlag, + Symbol *symbol2, Symbol::Flag secondOmpFlag) { + if ((symbol1->test(firstOmpFlag) && + symbol2->test(secondOmpFlag)) || + (symbol1->test(secondOmpFlag) && + symbol2->test(firstOmpFlag))) { + context_.Say(designator.source, + "Variable '%s' may not " + "appear on both %s and %s " + "clauses on a %s construct"_err_en_US, + symbol2->name(), + const_cast(symbol1)->OmpFlagToClauseName( + firstOmpFlag), + symbol2->OmpFlagToClauseName(secondOmpFlag), + parser::ToUpperCaseLetters( + llvm::omp::getOpenMPDirectiveName( + GetContext().directive) + .str())); + } + }; if (dataCopyingAttributeFlags.test(ompFlag)) { CheckDataCopyingClause(*name, *symbol, ompFlag); } else { @@ -1943,28 +1996,37 @@ 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()); + if (GetContext().directive == + llvm::omp::Directive::OMPD_target_data) { + checkExclusivelists(symbol, Symbol::Flag::OmpUseDevicePtr, + symbol, Symbol::Flag::OmpUseDeviceAddr); } - if (llvm::omp::allDistributeSet.test(GetContext().directive) && - (((ompFlag == Symbol::Flag::OmpFirstPrivate) && - symbol->test(Symbol::Flag::OmpLastPrivate)) || - ((ompFlag == Symbol::Flag::OmpLastPrivate) && - symbol->test(Symbol::Flag::OmpFirstPrivate)))) { - context_.Say(designator.source, - "Variable '%s' may not " - "appear on both FIRSTPRIVATE and LASTPRIVATE " - "clauses on a DISTRIBUTE construct"_err_en_US, - symbol->name()); + if (llvm::omp::allDistributeSet.test(GetContext().directive)) { + checkExclusivelists(symbol, Symbol::Flag::OmpFirstPrivate, + symbol, Symbol::Flag::OmpLastPrivate); + } + if (llvm::omp::allTargetSet.test(GetContext().directive)) { + const auto *hostAssocSym{symbol}; + if (const auto *details{ + symbol->detailsIf()}) { + hostAssocSym = &details->symbol(); + } + Symbol::Flag dataMappingAttributeFlags[] = { + Symbol::Flag::OmpMapTo, Symbol::Flag::OmpMapFrom, + Symbol::Flag::OmpMapToFrom, Symbol::Flag::OmpMapAlloc, + Symbol::Flag::OmpMapRelease, Symbol::Flag::OmpMapDelete}; + + Symbol::Flag dataSharingAttributeFlags[] = { + Symbol::Flag::OmpPrivate, Symbol::Flag::OmpFirstPrivate, + Symbol::Flag::OmpLastPrivate, Symbol::Flag::OmpShared, + Symbol::Flag::OmpLinear}; + + for (Symbol::Flag ompFlag1 : dataMappingAttributeFlags) { + for (Symbol::Flag ompFlag2 : dataSharingAttributeFlags) { + checkExclusivelists( + hostAssocSym, ompFlag1, symbol, ompFlag2); + } + } } } } else { diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp --- a/flang/lib/Semantics/symbol.cpp +++ b/flang/lib/Semantics/symbol.cpp @@ -757,6 +757,51 @@ return y && *y == x; } +std::string Symbol::OmpFlagToClauseName(Symbol::Flag ompFlag) { + std::string clauseName; + switch (ompFlag) { + case Symbol::Flag::OmpShared: + clauseName = "SHARED"; + break; + case Symbol::Flag::OmpPrivate: + clauseName = "PRIVATE"; + break; + case Symbol::Flag::OmpLinear: + clauseName = "LINEAR"; + break; + case Symbol::Flag::OmpFirstPrivate: + clauseName = "FIRSTPRIVATE"; + break; + case Symbol::Flag::OmpLastPrivate: + clauseName = "LASTPRIVATE"; + break; + case Symbol::Flag::OmpMapTo: + case Symbol::Flag::OmpMapFrom: + case Symbol::Flag::OmpMapToFrom: + case Symbol::Flag::OmpMapAlloc: + case Symbol::Flag::OmpMapRelease: + case Symbol::Flag::OmpMapDelete: + clauseName = "MAP"; + break; + case Symbol::Flag::OmpUseDevicePtr: + clauseName = "USE_DEVICE_PTR"; + break; + case Symbol::Flag::OmpUseDeviceAddr: + clauseName = "USE_DEVICE_ADDR"; + break; + case Symbol::Flag::OmpCopyIn: + clauseName = "COPYIN"; + break; + case Symbol::Flag::OmpCopyPrivate: + clauseName = "COPYPRIVATE"; + break; + default: + clauseName = ""; + break; + } + return clauseName; +} + bool SymbolOffsetCompare::operator()( const SymbolRef &x, const SymbolRef &y) const { const Symbol *xCommon{FindCommonBlockContaining(*x)}; diff --git a/flang/test/Semantics/OpenMP/firstprivate01.f90 b/flang/test/Semantics/OpenMP/firstprivate01.f90 --- a/flang/test/Semantics/OpenMP/firstprivate01.f90 +++ b/flang/test/Semantics/OpenMP/firstprivate01.f90 @@ -38,27 +38,27 @@ a(i) = a(i) + b(i) - i end do !$omp end teams distribute - !ERROR: Variable 'b' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a DISTRIBUTE construct + !ERROR: Variable 'b' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a TEAMS DISTRIBUTE construct !$omp teams distribute firstprivate(a,b) lastprivate(b) do i = 1, 10 a(i) = a(i) + b(i) - i end do !$omp end teams distribute - !ERROR: Variable 'a' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a DISTRIBUTE construct - !ERROR: Variable 'b' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a DISTRIBUTE construct + !ERROR: Variable 'a' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a TEAMS DISTRIBUTE construct + !ERROR: Variable 'b' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a TEAMS DISTRIBUTE construct !$omp teams distribute firstprivate(a,b) lastprivate(a,b) do i = 1, 10 a(i) = a(i) + b(i) - i end do !$omp end teams distribute - !ERROR: Variable 'b' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a DISTRIBUTE construct + !ERROR: Variable 'b' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a TEAMS DISTRIBUTE construct !$omp teams distribute lastprivate(a,b) firstprivate(b) do i = 1, 10 a(i) = a(i) + b(i) - i end do !$omp end teams distribute - !ERROR: Variable 'b' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a DISTRIBUTE construct - !ERROR: Variable 'a' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a DISTRIBUTE construct + !ERROR: Variable 'b' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a TEAMS DISTRIBUTE construct + !ERROR: Variable 'a' may not appear on both FIRSTPRIVATE and LASTPRIVATE clauses on a TEAMS DISTRIBUTE construct !$omp teams distribute lastprivate(a,b) firstprivate(b,a) do i = 1, 10 a(i) = a(i) + b(i) - i diff --git a/flang/test/Semantics/OpenMP/symbol08.f90 b/flang/test/Semantics/OpenMP/symbol08.f90 --- a/flang/test/Semantics/OpenMP/symbol08.f90 +++ b/flang/test/Semantics/OpenMP/symbol08.f90 @@ -106,8 +106,8 @@ ! Rule a); OpenMP 4.5 Examples teams.2.f90 ! TODO: reduction; data-mapping attributes !DEF: /dotprod (Subroutine) Subprogram -!DEF: /dotprod/b ObjectEntity REAL(4) -!DEF: /dotprod/c ObjectEntity REAL(4) +!DEF: /dotprod/b (OmpMapTo) ObjectEntity REAL(4) +!DEF: /dotprod/c (OmpMapTo) ObjectEntity REAL(4) !DEF: /dotprod/n ObjectEntity INTEGER(4) !DEF: /dotprod/block_size ObjectEntity INTEGER(4) !DEF: /dotprod/num_teams ObjectEntity INTEGER(4) @@ -119,7 +119,7 @@ !REF: /dotprod/b !REF: /dotprod/n !REF: /dotprod/c - !DEF: /dotprod/sum ObjectEntity REAL(4) + !DEF: /dotprod/sum (OmpMapToFrom) ObjectEntity REAL(4) real b(n), c(n), sum !REF: /dotprod/block_size !REF: /dotprod/num_teams diff --git a/flang/test/Semantics/OpenMP/target01.f90 b/flang/test/Semantics/OpenMP/target01.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/target01.f90 @@ -0,0 +1,10 @@ +! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp +! OpenMP Version 4.5 + +integer :: x +!ERROR: Variable 'x' may not appear on both MAP and PRIVATE clauses on a TARGET construct +!$omp target map(x) private(x) +x = x + 1 +!$omp end target + +end diff --git a/flang/test/Semantics/OpenMP/target02.f90 b/flang/test/Semantics/OpenMP/target02.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/target02.f90 @@ -0,0 +1,17 @@ +! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp +! OpenMP Version 4.5 + +program p +integer :: y +!ERROR: Variable 'y' may not appear on both MAP and FIRSTPRIVATE clauses on a TARGET construct +!$omp target map(y) firstprivate(y) +y = y + 1 +!$omp end target +!ERROR: Variable 'y' may not appear on both MAP and FIRSTPRIVATE clauses on a TARGET SIMD construct +!$omp target simd map(y) firstprivate(y) +do i=1,1 + y = y + 1 +end do +!$omp end target simd + +end program p