diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 89107097e560a..29a0c79267143 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -297,6 +297,10 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) { llvm::omp::teamSet.test(GetContextParent().directive)) { HasInvalidTeamsNesting(beginDir.v, beginDir.source); } + 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) { @@ -465,6 +469,77 @@ void OmpStructureChecker::CheckCycleConstraints( 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)}; + + semantics::UnorderedSymbolSet indexVars; + + // Collect symbols of all the variables from linear clauses + 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) { + indexVars.insert(*(v.symbol)); + } + } + } + + if (!indexVars.empty()) { + // 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; + + // Match the loop index variables with the collected symbols from linear + // clauses. + 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) { + // Remove the symbol from the collcted set + indexVars.erase(*(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; + } + } + + // Show error for the remaining variables + for (auto var : indexVars) { + const Symbol &root{GetAssociationRoot(var)}; + context_.Say(parser::FindSourceLocation(x), + "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, + root.name()); + } + } +} + void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) { if (llvm::omp::simdSet.test(GetContext().directive)) { ExitSIMDNest(); diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 009c0850380eb..9ca69eb14c33e 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -219,6 +219,7 @@ class OmpStructureChecker void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); void CheckDoWhile(const parser::OpenMPLoopConstruct &x); void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); + void CheckDistLinear(const parser::OpenMPLoopConstruct &x); void CheckSIMDNest(const parser::OpenMPConstruct &x); std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv); diff --git a/flang/test/Semantics/omp-linear-iter.f90 b/flang/test/Semantics/omp-linear-iter.f90 new file mode 100644 index 0000000000000..c8932d32a55fd --- /dev/null +++ b/flang/test/Semantics/omp-linear-iter.f90 @@ -0,0 +1,85 @@ +! 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: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. + !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: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. + !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 + + !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. + !$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