Skip to content
Closed
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
14 changes: 14 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,9 +189,16 @@ 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,
};

static const OmpDirectiveSet allWorkdistributeSet{
Directive::OMPD_workdistribute,
Directive::OMPD_teams_workdistribute,
Directive::OMPD_target_teams_workdistribute,
};

//===----------------------------------------------------------------------===//
// Directive sets for groups of multiple directives
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -230,6 +239,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 @@ -294,6 +306,7 @@ static const OmpDirectiveSet workShareSet{
Directive::OMPD_scope,
Directive::OMPD_sections,
Directive::OMPD_single,
Directive::OMPD_workdistribute,
} | allDoSet,
};

Expand Down Expand Up @@ -376,6 +389,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
23 changes: 22 additions & 1 deletion flang/lib/Lower/OpenMP/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,13 @@ static void processHostEvalClauses(lower::AbstractConverter &converter,
cp.processCollapse(loc, eval, hostInfo->ops, hostInfo->iv);
break;

case OMPD_teams_workdistribute:
cp.processThreadLimit(stmtCtx, hostInfo->ops);
[[fallthrough]];
case OMPD_target_teams_workdistribute:
cp.processNumTeams(stmtCtx, hostInfo->ops);
break;

// Standalone 'target' case.
case OMPD_target: {
processSingleNestedIf(
Expand Down Expand Up @@ -2818,6 +2825,17 @@ genTeamsOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
queue, item, clauseOps);
}

static mlir::omp::WorkdistributeOp genWorkdistributeOp(
lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
mlir::Location loc, const ConstructQueue &queue,
ConstructQueue::const_iterator item) {
return genOpWithBody<mlir::omp::WorkdistributeOp>(
OpWithBodyGenInfo(converter, symTable, semaCtx, loc, eval,
llvm::omp::Directive::OMPD_workdistribute),
queue, item);
}

//===----------------------------------------------------------------------===//
// Code generation functions for the standalone version of constructs that can
// also be a leaf of a composite construct
Expand Down Expand Up @@ -3454,7 +3472,10 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
case llvm::omp::Directive::OMPD_unroll:
genUnrollOp(converter, symTable, stmtCtx, semaCtx, eval, loc, queue, item);
break;
// case llvm::omp::Directive::OMPD_workdistribute:
case llvm::omp::Directive::OMPD_workdistribute:
newOp = genWorkdistributeOp(converter, symTable, semaCtx, eval, loc, queue,
item);
break;
case llvm::omp::Directive::OMPD_workshare:
newOp = genWorkshareOp(converter, symTable, stmtCtx, semaCtx, eval, loc,
queue, item);
Expand Down
6 changes: 5 additions & 1 deletion flang/lib/Parser/openmp-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1845,11 +1845,15 @@ TYPE_PARSER( //
MakeBlockConstruct(llvm::omp::Directive::OMPD_target_data) ||
MakeBlockConstruct(llvm::omp::Directive::OMPD_target_parallel) ||
MakeBlockConstruct(llvm::omp::Directive::OMPD_target_teams) ||
MakeBlockConstruct(
llvm::omp::Directive::OMPD_target_teams_workdistribute) ||
MakeBlockConstruct(llvm::omp::Directive::OMPD_target) ||
MakeBlockConstruct(llvm::omp::Directive::OMPD_task) ||
MakeBlockConstruct(llvm::omp::Directive::OMPD_taskgroup) ||
MakeBlockConstruct(llvm::omp::Directive::OMPD_teams) ||
MakeBlockConstruct(llvm::omp::Directive::OMPD_workshare))
MakeBlockConstruct(llvm::omp::Directive::OMPD_teams_workdistribute) ||
MakeBlockConstruct(llvm::omp::Directive::OMPD_workshare) ||
MakeBlockConstruct(llvm::omp::Directive::OMPD_workdistribute))
#undef MakeBlockConstruct

// OMP SECTIONS Directive
Expand Down
95 changes: 95 additions & 0 deletions flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,67 @@ 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)}) {
for (const Symbol &symbol : evaluate::CollectSymbols(*e)) {
const Symbol &root{GetAssociationRoot(symbol)};
if (IsFunction(root)) {
std::string attrs{""};
if (!IsElementalProcedure(root)) {
attrs = " non-ELEMENTAL";
}
if (root.attrs().test(Attr::IMPURE)) {
if (attrs != "") {
attrs = "," + attrs;
}
attrs = " IMPURE" + attrs;
}
if (attrs != "") {
context_.Say(expr.source,
"User defined%s function '%s' is not allowed in a "
"WORKDISTRIBUTE construct"_err_en_US,
attrs, 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 @@ -809,6 +870,13 @@ 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(x.BeginDir().DirName().source,
"%s region can only be strictly nested within the "
"teams region"_err_en_US,
ContextDirectiveAsFortran());
}
}

CheckNoBranching(block, beginSpec.DirId(), beginSpec.source);
Expand Down Expand Up @@ -892,6 +960,17 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
HasInvalidWorksharingNesting(
beginSpec.source, llvm::omp::nestedWorkshareErrSet);
break;
case llvm::omp::OMPD_workdistribute:
if (!CurrentDirectiveIsNested()) {
context_.Say(beginSpec.source,
"A workdistribute region must be nested inside teams region only."_err_en_US);
}
CheckWorkdistributeBlockStmts(block, beginSpec.source);
break;
case llvm::omp::OMPD_teams_workdistribute:
case llvm::omp::OMPD_target_teams_workdistribute:
CheckWorkdistributeBlockStmts(block, beginSpec.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 @@ -4470,6 +4549,22 @@ void OmpStructureChecker::CheckWorkshareBlockStmts(
}
}

void OmpStructureChecker::CheckWorkdistributeBlockStmts(
const parser::Block &block, parser::CharBlock source) {
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 @@ -1735,10 +1735,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(dirSpec.source, dirId);
break;
default:
Expand Down Expand Up @@ -1768,9 +1771,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
30 changes: 30 additions & 0 deletions flang/test/Lower/OpenMP/workdistribute.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s

! CHECK-LABEL: func @_QPtarget_teams_workdistribute
subroutine target_teams_workdistribute()
integer :: aa(10), bb(10)
! CHECK: omp.target
! CHECK: omp.teams
! CHECK: omp.workdistribute
!$omp target teams workdistribute
aa = bb
! CHECK: omp.terminator
! CHECK: omp.terminator
! CHECK: omp.terminator
!$omp end target teams workdistribute
end subroutine target_teams_workdistribute

! CHECK-LABEL: func @_QPteams_workdistribute
subroutine teams_workdistribute()
use iso_fortran_env
real(kind=real32) :: a
real(kind=real32), dimension(10) :: x
real(kind=real32), dimension(10) :: y
! CHECK: omp.teams
! CHECK: omp.workdistribute
!$omp teams workdistribute
y = a * x + y
! CHECK: omp.terminator
! CHECK: omp.terminator
!$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
! 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
! 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
! 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
Loading