Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -195,6 +195,7 @@ void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); void CheckDoWhile(const parser::OpenMPLoopConstruct &x); void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); + void CheckDistLinear(const parser::OpenMPLoopConstruct &x); std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv); bool CheckReductionOperators(const parser::OmpClause::Reduction &); Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -233,6 +233,10 @@ CheckDoWhile(x); CheckLoopItrVariableIsInt(x); CheckCycleConstraints(x); + if ((beginDir.v == llvm::omp::Directive::OMPD_distribute_parallel_do_simd) || + (beginDir.v == llvm::omp::Directive::OMPD_distribute_simd)) { + CheckDistLinear(x); + } } const parser::Name OmpStructureChecker::GetLoopIndex( const parser::DoConstruct *x) { @@ -329,6 +333,73 @@ parser::Walk(x, ompCycleChecker); } +void OmpStructureChecker::CheckDistLinear( + const parser::OpenMPLoopConstruct &x) { + + const auto &beginLoopDir{std::get(x.t)}; + const auto &clauses{std::get(beginLoopDir.t)}; + + // Get collapse level, if given, to find which loops are "associated." + std::int64_t collapseVal{GetOrdCollapseLevel(x)}; + // Include the top loop if no collapse is specified + if (collapseVal == 0) + collapseVal = 1; + + // Collect the index variables of the "associated" loops. + semantics::UnorderedSymbolSet indexVars; + + if (const auto &loopConstruct{ + std::get>(x.t)}) { + for (const parser::DoConstruct *loop{&*loopConstruct}; loop;) { + if (loop->IsDoNormal()) { + const parser::Name &itrVal{GetLoopIndex(loop)}; + if (itrVal.symbol) { + indexVars.insert(*(itrVal.symbol)); + } + collapseVal--; + if (collapseVal == 0) + break; + } + // Get the next DoConstruct if block is not empty. + const auto &block{std::get(loop->t)}; + const auto it{block.begin()}; + loop = it != block.end() ? parser::Unwrap(*it) + : nullptr; + } + } + + // A variable may not appear in a linear clause, unless it is the + // index variable of the loop associated with the distribute + // construct. + for (const auto &clause : clauses.v) { + if (const auto *linearClause{ + std::get_if(&clause.u)}) { + + std::list values; + // Get the variant type + if (std::holds_alternative( + linearClause->v.u)) { + const auto &withM{ + std::get(linearClause->v.u)}; + values = withM.names; + } else { + const auto &withOutM{std::get( + linearClause->v.u)}; + values = withOutM.names; + } + for (auto const &v : values) { + // Check if the variable is not among the collected index variables + // of the "associated" loop(s). + if (indexVars.count(*(v.symbol)) < 1) { + context_.Say(v.source, + "Variable '%s' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE`"_err_en_US, + v.ToString()); + } + } + } + } +} + void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) { dirContext_.pop_back(); } Index: flang/test/Semantics/omp-linear-iter.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-linear-iter.f90 @@ -0,0 +1,82 @@ +! RUN: %S/test_errors.sh %s %t %flang -fopenmp +! OpenMP Version 4.5 +! Various checks with the ordered construct + +SUBROUTINE LINEAR_GOOD(N) + INTEGER N, i, j, a, b(10) + !$omp target + !$omp teams + !$omp distribute parallel do simd linear(i) + do i = 1, N + a = 3.14 + enddo + !$omp end distribute parallel do simd + !$omp end teams + !$omp end target +END SUBROUTINE LINEAR_GOOD + +SUBROUTINE LINEAR_BAD(N) + INTEGER N, i, j, a, b(10) + + !$omp target + !$omp teams + !ERROR: Variable 'j' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !$omp distribute parallel do simd linear(j) + do i = 1, N + a = 3.14 + enddo + !$omp end distribute parallel do simd + !$omp end teams + !$omp end target + + !$omp target + !$omp teams + !ERROR: Variable 'j' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !ERROR: Variable 'b' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !$omp distribute parallel do simd linear(j) linear(b) + do i = 1, N + a = 3.14 + enddo + !$omp end distribute parallel do simd + !$omp end teams + !$omp end target + + !$omp target + !$omp teams + !ERROR: Variable 'j' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !ERROR: Variable 'b' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !$omp distribute parallel do simd linear(j, b) + do i = 1, N + a = 3.14 + enddo + !$omp end distribute parallel do simd + !$omp end teams + !$omp end target + + !ERROR: Variable 'j' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !$omp distribute simd linear(i,j) + do i = 1, N + do j = 1, N + a = 3.14 + enddo + enddo + !$omp end distribute simd + + !ERROR: Variable 'j' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !$omp distribute simd linear(i,j) collapse(1) + do i = 1, N + do j = 1, N + a = 3.14 + enddo + enddo + !$omp end distribute simd + + !$omp distribute simd linear(i,j) collapse(2) + do i = 1, N + do j = 1, N + a = 3.14 + enddo + enddo + !$omp end distribute simd + +END SUBROUTINE LINEAR_BAD