[flang-commits] [flang] c549aba - [flang][OpenMP] Check conflicts between predetermined/explicit DSA (#194961)
via flang-commits
flang-commits at lists.llvm.org
Fri May 1 06:09:42 PDT 2026
Author: Krzysztof Parzyszek
Date: 2026-05-01T08:09:36-05:00
New Revision: c549abab5d18bae56ef9b91d5991fa6dc2996898
URL: https://github.com/llvm/llvm-project/commit/c549abab5d18bae56ef9b91d5991fa6dc2996898
DIFF: https://github.com/llvm/llvm-project/commit/c549abab5d18bae56ef9b91d5991fa6dc2996898.diff
LOG: [flang][OpenMP] Check conflicts between predetermined/explicit DSA (#194961)
Improve checks for loop iteration variables with predetermined DSA
appearing in DSA clauses. Show both the location of the variable in the
offending clause, and in the loop.
Make the checks a bit more accurate as well: only allow LINEAR clause on
SIMD construct with a single affected loop.
Added:
Modified:
flang/include/flang/Semantics/openmp-utils.h
flang/lib/Semantics/check-directive-structure.h
flang/lib/Semantics/check-omp-loop.cpp
flang/lib/Semantics/check-omp-structure.cpp
flang/lib/Semantics/check-omp-structure.h
flang/lib/Semantics/openmp-utils.cpp
flang/lib/Semantics/resolve-directives.cpp
flang/test/Parser/OpenMP/linear-clause.f90
flang/test/Semantics/OpenMP/do01.f90
flang/test/Semantics/OpenMP/do04.f90
flang/test/Semantics/OpenMP/do10.f90
flang/test/Semantics/OpenMP/linear-clause03.f90
flang/test/Semantics/OpenMP/linear-iter.f90
llvm/include/llvm/Frontend/OpenMP/OMP.h
Removed:
################################################################################
diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h
index 3124005a4bbff..aab63df2e6e14 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -99,6 +99,8 @@ bool IsVarOrFunctionRef(const MaybeExpr &expr);
bool IsWholeAssumedSizeArray(const parser::OmpObject &object);
+const Symbol *GetHostSymbol(const Symbol &sym);
+
bool IsMapEnteringType(parser::OmpMapType::Value type);
bool IsMapExitingType(parser::OmpMapType::Value type);
@@ -150,7 +152,7 @@ struct LoopControl {
LoopControl(const parser::LoopControl::Bounds &x);
LoopControl(const parser::ConcurrentControl &x);
- const Symbol *iv{nullptr};
+ parser::Name iv;
WithSource<MaybeExpr> lbound, ubound, step;
private:
diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index 46fbc5191b38a..8b4c3be76098e 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -231,11 +231,8 @@ class DirectiveStructureChecker : public virtual BaseChecker {
std::list<C> actualClauses;
std::list<C> endDirectiveClauses;
std::list<C> crtGroup;
- Symbol *loopIV{nullptr};
};
- void SetLoopIv(Symbol *symbol) { GetContext().loopIV = symbol; }
-
// back() is the top of the stack
DirectiveContext &GetContext() {
CHECK(!dirContext_.empty());
@@ -260,7 +257,6 @@ class DirectiveStructureChecker : public virtual BaseChecker {
GetContext().allowedExclusiveClauses = {};
GetContext().requiredClauses = {};
GetContext().clauseInfo = {};
- GetContext().loopIV = {nullptr};
}
void SetContextDirectiveSource(const parser::CharBlock &directive) {
diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index b246d027e4807..2c40185b23011 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -414,7 +414,6 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
// nesting check
HasInvalidWorksharingNesting(beginName, llvm::omp::nestedWorkshareErrSet);
}
- SetLoopInfo(x);
for (auto &construct : std::get<parser::Block>(x.t)) {
if (const auto *doConstruct{parser::omp::GetDoConstruct(construct)}) {
@@ -422,7 +421,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
CheckNoBranching(doBlock, beginName.v, beginName.source);
}
}
- CheckIterationVariableType(x);
+ CheckIterationVariables(x);
CheckNestedConstruct(x);
CheckAssociatedLoopConstraints(x);
HasInvalidDistributeNesting(x);
@@ -443,30 +442,95 @@ const parser::Name OmpStructureChecker::GetLoopIndex(
return std::get<Bounds>(x->GetLoopControl()->u).Name().thing;
}
-void OmpStructureChecker::SetLoopInfo(const parser::OpenMPLoopConstruct &x) {
- if (const auto *loop{x.GetNestedLoop()}) {
- if (loop->IsDoNormal()) {
- const parser::Name &itrVal{GetLoopIndex(loop)};
- SetLoopIv(itrVal.symbol);
+void OmpStructureChecker::CheckIterationVariables(
+ const parser::OpenMPLoopConstruct &x) {
+ unsigned version{context_.langOptions().OpenMPVersion};
+ auto doLoops{CollectAffectedDoLoops(x, version, &context_)};
+ if (!doLoops) {
+ return;
+ }
+ const parser::OmpDirectiveSpecification &spec{x.BeginDir()};
+ llvm::omp::Directive dirId{spec.DirId()};
+
+ // Collect symbols from DSA clauses on the construct. These symbols
+ // are the "host" versions of symbols inside the construct. The flags
+ // of interest are on the associated symbols.
+ struct ClauseAppearance {
+ llvm::omp::Clause clauseId;
+ parser::CharBlock source;
+ };
+ std::multimap<const Symbol *, ClauseAppearance> dsa;
+ for (const parser::OmpClause &clause : spec.Clauses().v) {
+ llvm::omp::Clause clauseId{clause.Id()};
+ if (llvm::omp::isDataSharingAttributeClause(clauseId, version)) {
+ for (const parser::OmpObject &object :
+ parser::omp::GetOmpObjectList(clause)->v) {
+ if (const Symbol *symbol{GetObjectSymbol(object)}) {
+ auto maybeSource{parser::omp::GetObjectSource(object)};
+ assert(maybeSource && "Expecting object source");
+ dsa.insert(
+ std::make_pair(symbol, ClauseAppearance{clauseId, *maybeSource}));
+ }
+ }
}
}
-}
-void OmpStructureChecker::CheckIterationVariableType(
- const parser::OpenMPLoopConstruct &x) {
- auto &body{std::get<parser::Block>(x.t)};
- for (auto &construct : LoopRange(body, LoopRange::Step::Into)) {
- // 'construct' can also be OpenMPLoopConstruct
- if (auto *loop{parser::Unwrap<parser::DoConstruct>(construct)}) {
- if (loop->IsDoNormal()) {
- if (const parser::Name &iv{GetLoopIndex(loop)}; iv.symbol) {
- const auto *type{iv.symbol->GetType()};
- if (!type->IsNumeric(TypeCategory::Integer)) {
- context_.Say(iv.source,
- "The DO loop iteration variable must be of integer type"_err_en_US,
- iv.ToString());
- }
+ auto [depth, _]{GetAffectedNestDepthWithReason(spec, version)};
+ bool isLinearAllowed{false};
+ if (!depth || depth.value == 1) {
+ auto leafs{llvm::omp::getLeafConstructsOrSelf(dirId)};
+ isLinearAllowed = leafs.back() == llvm::omp::Directive::OMPD_simd;
+ }
+
+ std::vector<parser::Name> ivs;
+ for (const parser::DoConstruct *loop : *doLoops) {
+ for (auto &control : GetLoopControls(*loop)) {
+ if (control.iv.symbol) {
+ ivs.push_back(control.iv);
+ }
+ }
+ }
+
+ for (const parser::Name &iv : ivs) {
+ const auto *type{iv.symbol->GetType()};
+ if (!type->IsNumeric(TypeCategory::Integer)) {
+ context_.Say(iv.source,
+ "The DO loop iteration variable must be of integer type"_err_en_US,
+ iv.ToString());
+ }
+ const Symbol *host{GetHostSymbol(*iv.symbol)};
+ if (!host) {
+ continue;
+ }
+ if (host->test(Symbol::Flag::OmpThreadprivate)) {
+ context_.Say(iv.source,
+ "Loop iteration variable of an affected loop cannot be THREADPRIVATE"_err_en_US,
+ iv.ToString());
+ }
+ // Check conflict between a predetermined DSA and explicit DSA.
+ assert(iv.symbol->test(Symbol::Flag::OmpPreDetermined) &&
+ "Expecting affected iteration variable to have predetermined DSA");
+ if (iv.symbol->test(Symbol::Flag::OmpExplicit)) {
+ auto range{dsa.equal_range(host)};
+ for (auto found{range.first}; found != range.second; ++found) {
+ llvm::omp::Clause id{found->second.clauseId};
+ if (!llvm::omp::isAllowedClauseForDirective(dirId, id, version)) {
+ continue;
+ }
+ if (id == llvm::omp::Clause::OMPC_private ||
+ id == llvm::omp::Clause::OMPC_lastprivate) {
+ continue;
}
+ if (id == llvm::omp::Clause::OMPC_linear && isLinearAllowed) {
+ continue;
+ }
+ context_
+ .Say(found->second.source,
+ "Loop iteration variable with a predetermined data sharing attribute cannot appear in a %s clause"_err_en_US,
+ parser::omp::GetUpperName(id, version))
+ .Attach(iv.source,
+ "'%s' is an iteration variable of an affected loop"_because_en_US,
+ iv.ToString());
}
}
}
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 40f81bd3abcdc..a647d4cccfb68 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -4281,7 +4281,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) {
CheckVarIsNotPartOfAnotherVar(GetContext().clauseSource, x.v, "FIRSTPRIVATE");
CheckCrayPointee(x.v, "FIRSTPRIVATE");
- CheckIsLoopIvPartOfClause(llvm::omp::Clause::OMPC_firstprivate, x.v);
SymbolSourceMap currSymbols;
GetSymbolsInObjectList(x.v, currSymbols);
@@ -4319,20 +4318,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) {
currSymbols, dirClauseTriple, llvm::omp::Clause::OMPC_firstprivate);
}
-void OmpStructureChecker::CheckIsLoopIvPartOfClause(
- llvm::omp::Clause clause, const parser::OmpObjectList &ompObjectList) {
- unsigned version{context_.langOptions().OpenMPVersion};
- for (const auto &ompObject : ompObjectList.v) {
- if (const parser::Name *name{parser::Unwrap<parser::Name>(ompObject)}) {
- if (name->symbol == GetContext().loopIV) {
- context_.Say(name->source,
- "DO iteration variable %s is not allowed in %s clause."_err_en_US,
- name->ToString(), parser::omp::GetUpperName(clause, version));
- }
- }
- }
-}
-
void OmpStructureChecker::Enter(const parser::OmpClause::Align &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_align);
if (const auto &v{GetIntValue(x.v.v)}) {
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 142602c1f1118..397381e30cccd 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -250,8 +250,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
const omp::LoopSequence &nest);
void CheckNestedConstruct(const parser::OpenMPLoopConstruct &x);
const parser::Name GetLoopIndex(const parser::DoConstruct *x);
- void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
- void CheckIterationVariableType(const parser::OpenMPLoopConstruct &x);
+ void CheckIterationVariables(const parser::OpenMPLoopConstruct &x);
std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
void CheckScanModifier(const parser::OmpClause::Reduction &x);
@@ -351,8 +350,6 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
SymbolSourceMap &, const llvm::omp::Clause);
void CheckPrivateSymbolsInOuterCxt(
SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
- void CheckIsLoopIvPartOfClause(
- llvm::omp::Clause clause, const parser::OmpObjectList &ompObjectList);
bool CheckTargetBlockOnlyTeams(const parser::Block &);
void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);
diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index 9c5f77ef03a27..e837f8dca19f6 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -207,6 +207,13 @@ bool IsWholeAssumedSizeArray(const parser::OmpObject &object) {
return false;
}
+const Symbol *GetHostSymbol(const Symbol &sym) {
+ if (auto *details{sym.detailsIf<HostAssocDetails>()}) {
+ return &details->symbol();
+ }
+ return nullptr;
+}
+
bool IsMapEnteringType(parser::OmpMapType::Value type) {
switch (type) {
case parser::OmpMapType::Value::Alloc:
@@ -576,7 +583,7 @@ static bool IsTransformableLoop(const parser::ExecutionPartConstruct &epc) {
}
LoopControl::LoopControl(const parser::LoopControl::Bounds &x) {
- iv = x.Name().thing.symbol;
+ iv = x.Name().thing;
lbound = fromParserExpr(parser::UnwrapRef<parser::Expr>(x.Lower()));
ubound = fromParserExpr(parser::UnwrapRef<parser::Expr>(x.Upper()));
if (auto &inc{x.Step()}) {
@@ -586,7 +593,7 @@ LoopControl::LoopControl(const parser::LoopControl::Bounds &x) {
LoopControl::LoopControl(const parser::ConcurrentControl &x) {
auto &[name, lower, upper, inc]{x.t};
- iv = name.symbol;
+ iv = name;
lbound = fromParserExpr(parser::UnwrapRef<parser::Expr>(lower));
ubound = fromParserExpr(parser::UnwrapRef<parser::Expr>(upper));
if (inc) {
@@ -605,7 +612,8 @@ std::vector<LoopControl> GetLoopControls(const parser::DoConstruct &x) {
controls.emplace_back(std::get<parser::LoopControl::Bounds>(control.u));
} else if (x.IsDoConcurrent()) {
const parser::LoopControl &control{*x.GetLoopControl()};
- auto &header{parser::UnwrapRef<parser::ConcurrentHeader>(control)};
+ auto &concurrent{std::get<parser::LoopControl::Concurrent>(control.u)};
+ auto &header{std::get<parser::ConcurrentHeader>(concurrent.t)};
for (auto &cc : std::get<std::list<parser::ConcurrentControl>>(header.t)) {
controls.emplace_back(cc);
}
@@ -1776,8 +1784,8 @@ WithReason<bool> LoopSequence::isRectangular(
SymbolVector outerIVs;
for (auto *sequence : llvm::reverse(outer)) {
for (auto &control : sequence->getLoopControls()) {
- if (control.iv) {
- outerIVs.emplace_back(*control.iv);
+ if (control.iv.symbol) {
+ outerIVs.emplace_back(*control.iv.symbol);
}
}
}
@@ -1785,7 +1793,7 @@ WithReason<bool> LoopSequence::isRectangular(
WithReason<bool> result(true);
for (auto &control : getLoopControls()) {
- if (!control.iv || !control.lbound.value || !control.ubound.value) {
+ if (!control.iv.symbol || !control.lbound.value || !control.ubound.value) {
continue;
}
CheckSymbolExprOverlap(result, outerIVs, *control.lbound.value,
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 22c2ca082ff22..d056917d849fd 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2114,16 +2114,6 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndex(
ivDSA = Symbol::Flag::OmpLastPrivate;
}
- auto checkThreadprivate{[&](const parser::Name &iv) {
- if (const auto *details{iv.symbol->detailsIf<HostAssocDetails>()}) {
- if (details->symbol().test(Symbol::Flag::OmpThreadprivate)) {
- context_.Say(iv.source,
- "Loop iteration variable %s is not allowed in THREADPRIVATE."_err_en_US,
- iv.ToString());
- }
- }
- }};
-
Scope &scope{currScope()};
if (auto doLoops{omp::CollectAffectedDoLoops(x, version, &context_)}) {
@@ -2132,9 +2122,7 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndex(
if (!iv || (iv->symbol && IsLocalInsideScope(*iv->symbol, scope))) {
continue;
}
-
if (auto *symbol{ResolveOmp(*iv, ivDSA, scope)}) {
- checkThreadprivate(*iv);
SetSymbolDSA(*symbol, {Symbol::Flag::OmpPreDetermined, ivDSA});
iv->symbol = symbol; // adjust the symbol within region
AddToContextObjectWithDSA(*symbol, ivDSA);
diff --git a/flang/test/Parser/OpenMP/linear-clause.f90 b/flang/test/Parser/OpenMP/linear-clause.f90
index 5df37e0b3b028..45d288ce2077d 100644
--- a/flang/test/Parser/OpenMP/linear-clause.f90
+++ b/flang/test/Parser/OpenMP/linear-clause.f90
@@ -1,5 +1,5 @@
-!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=52 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
-!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=52 %s | FileCheck --check-prefix="PARSE-TREE" %s
+!RUN: %flang_fc1 -fdebug-unparse-no-sema -fopenmp -fopenmp-version=52 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
+!RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema -fopenmp -fopenmp-version=52 %s | FileCheck --check-prefix="PARSE-TREE" %s
subroutine f00(x)
integer :: x
@@ -12,7 +12,7 @@ subroutine f00(x)
!UNPARSE: SUBROUTINE f00 (x)
!UNPARSE: INTEGER x
!UNPARSE: !$OMP DO LINEAR(x)
-!UNPARSE: DO x=1_4,10_4
+!UNPARSE: DO x=1,10
!UNPARSE: END DO
!UNPARSE: !$OMP END DO
!UNPARSE: END SUBROUTINE
@@ -35,8 +35,8 @@ subroutine f01(x)
!UNPARSE: SUBROUTINE f01 (x)
!UNPARSE: INTEGER x
-!UNPARSE: !$OMP DO LINEAR(x: 2_4)
-!UNPARSE: DO x=1_4,10_4
+!UNPARSE: !$OMP DO LINEAR(x: 2)
+!UNPARSE: DO x=1,10
!UNPARSE: END DO
!UNPARSE: !$OMP END DO
!UNPARSE: END SUBROUTINE
@@ -45,8 +45,7 @@ subroutine f01(x)
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = do
!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
-!PARSE-TREE: | | Modifier -> OmpStepSimpleModifier -> Scalar -> Integer -> Expr = '2_4'
-!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | | Modifier -> OmpStepSimpleModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '2'
!PARSE-TREE: | | bool = 'true'
!PARSE-TREE: | Flags = {}
!PARSE-TREE: DoConstruct
@@ -61,8 +60,8 @@ subroutine f02(x)
!UNPARSE: SUBROUTINE f02 (x)
!UNPARSE: INTEGER x
-!UNPARSE: !$OMP DO LINEAR(x: STEP(3_4))
-!UNPARSE: DO x=1_4,10_4
+!UNPARSE: !$OMP DO LINEAR(x: STEP(3))
+!UNPARSE: DO x=1,10
!UNPARSE: END DO
!UNPARSE: !$OMP END DO
!UNPARSE: END SUBROUTINE
@@ -71,8 +70,7 @@ subroutine f02(x)
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = do
!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
-!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr = '3_4'
-!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '3'
+!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '3'
!PARSE-TREE: | | bool = 'true'
!PARSE-TREE: | Flags = {}
!PARSE-TREE: DoConstruct
@@ -102,7 +100,7 @@ subroutine f04(x)
!UNPARSE: SUBROUTINE f04 (x)
!UNPARSE: INTEGER x
-!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL, STEP(3_4))
+!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL, STEP(3))
!UNPARSE: END SUBROUTINE
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareSimdDirective -> OmpDirectiveSpecification
@@ -110,7 +108,6 @@ subroutine f04(x)
!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
!PARSE-TREE: | | Modifier -> OmpLinearModifier -> Value = Uval
-!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr = '3_4'
-!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '3'
+!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '3'
!PARSE-TREE: | | bool = 'true'
!PARSE-TREE: | Flags = {}
diff --git a/flang/test/Semantics/OpenMP/do01.f90 b/flang/test/Semantics/OpenMP/do01.f90
index 78c3ba38bc873..b4e9dcf753895 100644
--- a/flang/test/Semantics/OpenMP/do01.f90
+++ b/flang/test/Semantics/OpenMP/do01.f90
@@ -3,16 +3,31 @@
! 2.7.1 Loop Construct
! The loop iteration variable may not appear in a firstprivate directive.
-program omp_do
+subroutine f00
integer i, j, k
- !ERROR: DO iteration variable i is not allowed in FIRSTPRIVATE clause.
+ !ERROR: Loop iteration variable with a predetermined data sharing attribute cannot appear in a FIRSTPRIVATE clause
!$omp do firstprivate(k,i)
+ !BECAUSE: 'i' is an iteration variable of an affected loop
do i = 1, 10
do j = 1, 10
print *, "Hello"
end do
end do
!$omp end do
+end
-end program omp_do
+! Check multiple DSA clauses
+subroutine f01
+ integer :: i
+ !ERROR: Loop iteration variable with a predetermined data sharing attribute cannot appear in a FIRSTPRIVATE clause
+ !ERROR: 'i' appears in more than one data-sharing clause on the same OpenMP directive
+ !ERROR: Loop iteration variable with a predetermined data sharing attribute cannot appear in a LINEAR clause
+ !$omp do firstprivate(i) lastprivate(i) linear(i)
+ block
+ !BECAUSE: 'i' is an iteration variable of an affected loop
+ !BECAUSE: 'i' is an iteration variable of an affected loop
+ do i = 1, 10
+ end do
+ end block
+end
diff --git a/flang/test/Semantics/OpenMP/do04.f90 b/flang/test/Semantics/OpenMP/do04.f90
index 6690f4927f6a9..7c24ccac229c0 100644
--- a/flang/test/Semantics/OpenMP/do04.f90
+++ b/flang/test/Semantics/OpenMP/do04.f90
@@ -8,9 +8,9 @@ subroutine omp_do
integer, save:: i, j, k,n
!$omp threadprivate(k,j,i)
!$omp do collapse(2)
- !ERROR: Loop iteration variable i is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do i = 1, 10
- !ERROR: Loop iteration variable j is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do j = 1, 10
print *, "Hello"
end do
@@ -22,7 +22,7 @@ subroutine omp_do1
integer, save :: i, j, k
!$omp threadprivate(k,j,i)
!$omp do
- !ERROR: Loop iteration variable i is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do i = 1, 10
do j = 1, 10
print *, "Hello"
@@ -40,7 +40,7 @@ subroutine omp_do2
contains
subroutine compute()
!$omp do ordered(1) collapse(1)
- !ERROR: Loop iteration variable k is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
foo: do k = 1, 10
do i = 1, 10
print *, "Hello"
@@ -58,7 +58,7 @@ subroutine omp_do3
print *, "parallel"
!$omp end parallel
!$omp do
- !ERROR: Loop iteration variable i is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do i = 1, 10
do j = 1, 10
print *, "Hello"
@@ -82,7 +82,7 @@ end module usetp
subroutine main
use usetp
!$omp do
- !ERROR: Loop iteration variable i is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do i = 1, 10
do j = 1, 10
print *, "Hello"
@@ -94,7 +94,7 @@ subroutine main
subroutine main1
use tp
!$omp do
- !ERROR: Loop iteration variable j is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do j = 1, 10
do i = 1, 10
print *, "Hello"
diff --git a/flang/test/Semantics/OpenMP/do10.f90 b/flang/test/Semantics/OpenMP/do10.f90
index b609567c4d93d..1878864a4a5db 100644
--- a/flang/test/Semantics/OpenMP/do10.f90
+++ b/flang/test/Semantics/OpenMP/do10.f90
@@ -8,7 +8,6 @@ program omp_do
!$omp do
!ERROR: The DO loop iteration variable must be of integer type
do i = 1, 10
- !ERROR: The DO loop iteration variable must be of integer type
do j = 1, 10
print *, "it", i, j
end do
@@ -18,9 +17,7 @@ program omp_do
!ERROR: This construct requires a perfect nest of depth 3, but the associated nest is a perfect nest of depth 2
!BECAUSE: COLLAPSE clause was specified with argument 3
!$omp do collapse(3)
- !ERROR: The DO loop iteration variable must be of integer type
do i = 1, 10
- !ERROR: The DO loop iteration variable must be of integer type
do j = 1, 10
print *, "it", i, j
end do
diff --git a/flang/test/Semantics/OpenMP/linear-clause03.f90 b/flang/test/Semantics/OpenMP/linear-clause03.f90
index 124eb65701e26..7143db5927d46 100644
--- a/flang/test/Semantics/OpenMP/linear-clause03.f90
+++ b/flang/test/Semantics/OpenMP/linear-clause03.f90
@@ -15,7 +15,9 @@ subroutine f(x, y)
subroutine g
integer :: i
!ERROR: Clause LINEAR is not allowed if clause ORDERED appears on the DO directive
+ !ERROR: Loop iteration variable with a predetermined data sharing attribute cannot appear in a LINEAR clause
!$omp do ordered(1) linear(i)
+ !BECAUSE: 'i' is an iteration variable of an affected loop
do i = 1, 10
end do
end
diff --git a/flang/test/Semantics/OpenMP/linear-iter.f90 b/flang/test/Semantics/OpenMP/linear-iter.f90
index a46a3411fab34..d810bc26c3606 100644
--- a/flang/test/Semantics/OpenMP/linear-iter.f90
+++ b/flang/test/Semantics/OpenMP/linear-iter.f90
@@ -76,8 +76,12 @@ SUBROUTINE LINEAR_BAD(N)
!$omp end distribute simd
!WARNING: `DISTRIBUTE` must be dynamically enclosed in a `TEAMS` region.
+ !ERROR: Loop iteration variable with a predetermined data sharing attribute cannot appear in a LINEAR clause
+ !ERROR: Loop iteration variable with a predetermined data sharing attribute cannot appear in a LINEAR clause
!$omp distribute simd linear(i,j) collapse(2)
+ !BECAUSE: 'i' is an iteration variable of an affected loop
do i = 1, N
+ !BECAUSE: 'j' is an iteration variable of an affected loop
do j = 1, N
a = 3.14
enddo
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.h b/llvm/include/llvm/Frontend/OpenMP/OMP.h
index c7ad54ef3ed1b..c153707961d64 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.h
@@ -69,6 +69,33 @@ static constexpr inline bool isPrivatizingClause(Clause C, unsigned Version) {
}
}
+static constexpr inline bool isDataSharingAttributeClause(Clause C,
+ unsigned Version) {
+ // The "Version" parameter is in case the result is version-depenent
+ // in the future.
+ (void)Version;
+ switch (C) {
+ case OMPC_detach:
+ case OMPC_firstprivate:
+ case OMPC_has_device_addr:
+ case OMPC_induction:
+ case OMPC_in_reduction:
+ case OMPC_is_device_ptr:
+ case OMPC_lastprivate:
+ case OMPC_linear:
+ case OMPC_private:
+ case OMPC_reduction:
+ case OMPC_shared:
+ case OMPC_task_reduction:
+ case OMPC_use_device_addr:
+ case OMPC_use_device_ptr:
+ case OMPC_uses_allocators:
+ return true;
+ default:
+ return false;
+ }
+}
+
static constexpr unsigned FallbackVersion = 52;
LLVM_ABI ArrayRef<unsigned> getOpenMPVersions();
More information about the flang-commits
mailing list