Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions flang/include/flang/Semantics/openmp-directive-sets.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ static const OmpDirectiveSet topTargetSet{
Directive::OMPD_target_teams_distribute_parallel_do_simd,
Directive::OMPD_target_teams_distribute_simd,
Directive::OMPD_target_teams_loop,
Directive::OMPD_target_teams_workdistribute,
};

static const OmpDirectiveSet allTargetSet{topTargetSet};
Expand Down Expand Up @@ -172,6 +173,7 @@ static const OmpDirectiveSet topTeamsSet{
Directive::OMPD_teams_distribute_parallel_do_simd,
Directive::OMPD_teams_distribute_simd,
Directive::OMPD_teams_loop,
Directive::OMPD_teams_workdistribute,
};

static const OmpDirectiveSet bottomTeamsSet{
Expand All @@ -187,6 +189,7 @@ static const OmpDirectiveSet allTeamsSet{
Directive::OMPD_target_teams_distribute_parallel_do_simd,
Directive::OMPD_target_teams_distribute_simd,
Directive::OMPD_target_teams_loop,
Directive::OMPD_target_teams_workdistribute,
} | topTeamsSet,
};

Expand Down Expand Up @@ -230,6 +233,9 @@ static const OmpDirectiveSet blockConstructSet{
Directive::OMPD_taskgroup,
Directive::OMPD_teams,
Directive::OMPD_workshare,
Directive::OMPD_target_teams_workdistribute,
Directive::OMPD_teams_workdistribute,
Directive::OMPD_workdistribute,
};

static const OmpDirectiveSet loopConstructSet{
Expand Down Expand Up @@ -376,6 +382,7 @@ static const OmpDirectiveSet nestedReduceWorkshareAllowedSet{
};

static const OmpDirectiveSet nestedTeamsAllowedSet{
Directive::OMPD_workdistribute,
Directive::OMPD_distribute,
Directive::OMPD_distribute_parallel_do,
Directive::OMPD_distribute_parallel_do_simd,
Expand Down
7 changes: 7 additions & 0 deletions flang/lib/Parser/openmp-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1567,11 +1567,16 @@ TYPE_PARSER(
"TARGET DATA" >> pure(llvm::omp::Directive::OMPD_target_data),
"TARGET_DATA" >> pure(llvm::omp::Directive::OMPD_target_data),
"TARGET PARALLEL" >> pure(llvm::omp::Directive::OMPD_target_parallel),
"TARGET TEAMS WORKDISTRIBUTE" >>
pure(llvm::omp::Directive::OMPD_target_teams_workdistribute),
"TARGET TEAMS" >> pure(llvm::omp::Directive::OMPD_target_teams),
"TARGET" >> pure(llvm::omp::Directive::OMPD_target),
"TASK"_id >> pure(llvm::omp::Directive::OMPD_task),
"TASKGROUP" >> pure(llvm::omp::Directive::OMPD_taskgroup),
"TEAMS WORKDISTRIBUTE" >>
pure(llvm::omp::Directive::OMPD_teams_workdistribute),
"TEAMS" >> pure(llvm::omp::Directive::OMPD_teams),
"WORKDISTRIBUTE" >> pure(llvm::omp::Directive::OMPD_workdistribute),
"WORKSHARE" >> pure(llvm::omp::Directive::OMPD_workshare))))

TYPE_PARSER(sourced(construct<OmpBeginBlockDirective>(
Expand Down Expand Up @@ -1729,6 +1734,8 @@ TYPE_PARSER(sourced(
TYPE_PARSER(construct<OpenMPBlockConstruct>(
Parser<OmpBeginBlockDirective>{} / endOmpLine, block,
Parser<OmpEndBlockDirective>{} / endOmpLine))
#define MakeBlockConstruct(dir) \
construct<OpenMPBlockConstruct>(OmpBlockConstructParser{dir})

// OMP SECTIONS Directive
TYPE_PARSER(construct<OmpSectionsDirective>(first(
Expand Down
9 changes: 9 additions & 0 deletions flang/lib/Parser/unparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2561,6 +2561,15 @@ class UnparseVisitor {
case llvm::omp::Directive::OMPD_workshare:
Word("WORKSHARE ");
break;
case llvm::omp::Directive::OMPD_workdistribute:
Word("WORKDISTRIBUTE ");
break;
case llvm::omp::Directive::OMPD_teams_workdistribute:
Word("TEAMS WORKDISTRIBUTE ");
break;
case llvm::omp::Directive::OMPD_target_teams_workdistribute:
Word("TARGET TEAMS WORKDISTRIBUTE ");
break;
default:
// Nothing to be done
break;
Expand Down
97 changes: 97 additions & 0 deletions flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Frontend/OpenMP/OMP.h"

Expand Down Expand Up @@ -141,6 +142,64 @@ class OmpWorkshareBlockChecker {
parser::CharBlock source_;
};

// 'OmpWorkdistributeBlockChecker' is used to check the validity of the
// assignment statements and the expressions enclosed in an OpenMP
// WORKDISTRIBUTE construct
class OmpWorkdistributeBlockChecker {
public:
OmpWorkdistributeBlockChecker(
SemanticsContext &context, parser::CharBlock source)
: context_{context}, source_{source} {}

template <typename T> bool Pre(const T &) { return true; }
template <typename T> void Post(const T &) {}

bool Pre(const parser::AssignmentStmt &assignment) {
const auto &var{std::get<parser::Variable>(assignment.t)};
const auto &expr{std::get<parser::Expr>(assignment.t)};
const auto *lhs{GetExpr(context_, var)};
const auto *rhs{GetExpr(context_, expr)};
if (lhs && rhs) {
Tristate isDefined{semantics::IsDefinedAssignment(
lhs->GetType(), lhs->Rank(), rhs->GetType(), rhs->Rank())};
if (isDefined == Tristate::Yes) {
context_.Say(expr.source,
"Defined assignment statement is not allowed in a WORKDISTRIBUTE construct"_err_en_US);
}
}
return true;
}

bool Pre(const parser::Expr &expr) {
if (const auto *e{GetExpr(context_, expr)}) {
if (!e)
return false;
for (const Symbol &symbol : evaluate::CollectSymbols(*e)) {
const Symbol &root{GetAssociationRoot(symbol)};
if (IsFunction(root)) {
std::vector<std::string> attrs;
if (!IsElementalProcedure(root)) {
attrs.push_back("non-ELEMENTAL");
}
if (root.attrs().test(Attr::IMPURE)) {
attrs.push_back("IMPURE");
}
std::string attrsStr =
attrs.empty() ? "" : " " + llvm::join(attrs, ", ");
context_.Say(expr.source,
"User defined%s function '%s' is not allowed in a WORKDISTRIBUTE construct"_err_en_US,
attrsStr, root.name());
}
}
}
return false;
}

private:
SemanticsContext &context_;
parser::CharBlock source_;
};

// `OmpUnitedTaskDesignatorChecker` is used to check if the designator
// can appear within the TASK construct
class OmpUnitedTaskDesignatorChecker {
Expand Down Expand Up @@ -819,6 +878,12 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
"TARGET construct with nested TEAMS region contains statements or "
"directives outside of the TEAMS construct"_err_en_US);
}
if (GetContext().directive == llvm::omp::Directive::OMPD_workdistribute &&
GetContextParent().directive != llvm::omp::Directive::OMPD_teams) {
context_.Say(parser::FindSourceLocation(x),
"%s region can only be strictly nested within TEAMS region"_err_en_US,
ContextDirectiveAsFortran());
}
}

CheckNoBranching(block, beginDir.v, beginDir.source);
Expand Down Expand Up @@ -900,6 +965,17 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
HasInvalidWorksharingNesting(
beginDir.source, llvm::omp::nestedWorkshareErrSet);
break;
case llvm::omp::OMPD_workdistribute:
if (!CurrentDirectiveIsNested()) {
context_.Say(beginDir.source,
"A WORKDISTRIBUTE region must be nested inside TEAMS region only."_err_en_US);
}
CheckWorkdistributeBlockStmts(block, beginDir.source);
break;
case llvm::omp::OMPD_teams_workdistribute:
case llvm::omp::OMPD_target_teams_workdistribute:
CheckWorkdistributeBlockStmts(block, beginDir.source);
break;
case llvm::omp::Directive::OMPD_scope:
case llvm::omp::Directive::OMPD_single:
// TODO: This check needs to be extended while implementing nesting of
Expand Down Expand Up @@ -4385,6 +4461,27 @@ void OmpStructureChecker::CheckWorkshareBlockStmts(
}
}

void OmpStructureChecker::CheckWorkdistributeBlockStmts(
const parser::Block &block, parser::CharBlock source) {
unsigned version{context_.langOptions().OpenMPVersion};
unsigned since{60};
if (version < since)
context_.Say(source,
"WORKDISTRIBUTE construct is not allowed in %s, %s"_err_en_US,
ThisVersion(version), TryVersion(since));

OmpWorkdistributeBlockChecker ompWorkdistributeBlockChecker{context_, source};

for (auto it{block.begin()}; it != block.end(); ++it) {
if (parser::Unwrap<parser::AssignmentStmt>(*it)) {
parser::Walk(*it, ompWorkdistributeBlockChecker);
} else {
context_.Say(source,
"The structured block in a WORKDISTRIBUTE construct may consist of only SCALAR or ARRAY assignments"_err_en_US);
}
}
}

void OmpStructureChecker::CheckIfContiguous(const parser::OmpObject &object) {
if (auto contig{IsContiguous(context_, object)}; contig && !*contig) {
const parser::Name *name{GetObjectName(object)};
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Semantics/check-omp-structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ class OmpStructureChecker
llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
bool CheckTargetBlockOnlyTeams(const parser::Block &);
void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);

void CheckIteratorRange(const parser::OmpIteratorSpecifier &x);
void CheckIteratorModifier(const parser::OmpIterator &x);
Expand Down
8 changes: 7 additions & 1 deletion flang/lib/Semantics/resolve-directives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1680,10 +1680,13 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) {
case llvm::omp::Directive::OMPD_task:
case llvm::omp::Directive::OMPD_taskgroup:
case llvm::omp::Directive::OMPD_teams:
case llvm::omp::Directive::OMPD_workdistribute:
case llvm::omp::Directive::OMPD_workshare:
case llvm::omp::Directive::OMPD_parallel_workshare:
case llvm::omp::Directive::OMPD_target_teams:
case llvm::omp::Directive::OMPD_target_teams_workdistribute:
case llvm::omp::Directive::OMPD_target_parallel:
case llvm::omp::Directive::OMPD_teams_workdistribute:
PushContext(beginDir.source, beginDir.v);
break;
default:
Expand Down Expand Up @@ -1713,9 +1716,12 @@ void OmpAttributeVisitor::Post(const parser::OpenMPBlockConstruct &x) {
case llvm::omp::Directive::OMPD_target:
case llvm::omp::Directive::OMPD_task:
case llvm::omp::Directive::OMPD_teams:
case llvm::omp::Directive::OMPD_workdistribute:
case llvm::omp::Directive::OMPD_parallel_workshare:
case llvm::omp::Directive::OMPD_target_teams:
case llvm::omp::Directive::OMPD_target_parallel: {
case llvm::omp::Directive::OMPD_target_parallel:
case llvm::omp::Directive::OMPD_target_teams_workdistribute:
case llvm::omp::Directive::OMPD_teams_workdistribute: {
bool hasPrivate;
for (const auto *allocName : allocateNames_) {
hasPrivate = false;
Expand Down
27 changes: 27 additions & 0 deletions flang/test/Parser/OpenMP/workdistribute.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s | FileCheck --check-prefix="PARSE-TREE" %s

!UNPARSE: SUBROUTINE teams_workdistribute
!UNPARSE: USE :: iso_fortran_env
!UNPARSE: REAL(KIND=4_4) a
!UNPARSE: REAL(KIND=4_4), DIMENSION(10_4) :: x
!UNPARSE: REAL(KIND=4_4), DIMENSION(10_4) :: y
!UNPARSE: !$OMP TEAMS WORKDISTRIBUTE
!UNPARSE: y=a*x+y
!UNPARSE: !$OMP END TEAMS WORKDISTRIBUTE
!UNPARSE: END SUBROUTINE teams_workdistribute

!PARSE-TREE: | | | OmpBeginBlockDirective
!PARSE-TREE: | | | | OmpBlockDirective -> llvm::omp::Directive = teams workdistribute
!PARSE-TREE: | | | OmpEndBlockDirective
!PARSE-TREE: | | | | OmpBlockDirective -> llvm::omp::Directive = teams workdistribute

subroutine teams_workdistribute()
use iso_fortran_env
real(kind=real32) :: a
real(kind=real32), dimension(10) :: x
real(kind=real32), dimension(10) :: y
!$omp teams workdistribute
y = a * x + y
!$omp end teams workdistribute
end subroutine teams_workdistribute
16 changes: 16 additions & 0 deletions flang/test/Semantics/OpenMP/workdistribute01.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
! OpenMP Version 6.0
! workdistribute Construct
! Invalid do construct inside !$omp workdistribute

subroutine workdistribute()
integer n, i
!ERROR: A WORKDISTRIBUTE region must be nested inside TEAMS region only.
!ERROR: The structured block in a WORKDISTRIBUTE construct may consist of only SCALAR or ARRAY assignments
!$omp workdistribute
do i = 1, n
print *, "omp workdistribute"
end do
!$omp end workdistribute

end subroutine workdistribute
34 changes: 34 additions & 0 deletions flang/test/Semantics/OpenMP/workdistribute02.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
! OpenMP Version 6.0
! workdistribute Construct
! The !omp workdistribute construct must not contain any user defined
! function calls unless the function is ELEMENTAL.

module my_mod
contains
integer function my_func()
my_func = 10
end function my_func

impure integer function impure_my_func()
impure_my_func = 20
end function impure_my_func

impure elemental integer function impure_ele_my_func()
impure_ele_my_func = 20
end function impure_ele_my_func
end module my_mod

subroutine workdistribute(aa, bb, cc, n)
use my_mod
integer n
real aa(n), bb(n), cc(n)
!$omp teams
!$omp workdistribute
!ERROR: User defined non-ELEMENTAL function 'my_func' is not allowed in a WORKDISTRIBUTE construct
aa = my_func()
aa = bb * cc
!$omp end workdistribute
!$omp end teams

end subroutine workdistribute
34 changes: 34 additions & 0 deletions flang/test/Semantics/OpenMP/workdistribute03.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=60
! OpenMP Version 6.0
! workdistribute Construct
! All array assignments, scalar assignments, and masked array assignments
! must be intrinsic assignments.

module defined_assign
interface assignment(=)
module procedure work_assign
end interface

contains
subroutine work_assign(a,b)
integer, intent(out) :: a
logical, intent(in) :: b(:)
end subroutine work_assign
end module defined_assign

program omp_workdistribute
use defined_assign

integer :: a, aa(10), bb(10)
logical :: l(10)
l = .TRUE.

!$omp teams
!$omp workdistribute
!ERROR: Defined assignment statement is not allowed in a WORKDISTRIBUTE construct
a = l
aa = bb
!$omp end workdistribute
!$omp end teams

end program omp_workdistribute
15 changes: 15 additions & 0 deletions flang/test/Semantics/OpenMP/workdistribute04.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=50
! OpenMP Version 6.0
! workdistribute Construct
! Unsuported OpenMP version

subroutine teams_workdistribute()
use iso_fortran_env
real(kind=real32) :: a
real(kind=real32), dimension(10) :: x
real(kind=real32), dimension(10) :: y
!ERROR: WORKDISTRIBUTE construct is not allowed in OpenMP v5.0, try -fopenmp-version=60
!$omp teams workdistribute
y = a * x + y
!$omp end teams workdistribute
end subroutine teams_workdistribute