Compare commits
4 Commits
main
...
users/skc7
Author | SHA1 | Date | |
---|---|---|---|
![]() |
029719370c | ||
![]() |
4442fced82 | ||
![]() |
f53da4fa4f | ||
![]() |
d534a638f1 |
@ -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};
|
||||
@ -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{
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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{
|
||||
@ -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,
|
||||
|
@ -1870,11 +1870,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
|
||||
|
@ -141,6 +141,64 @@ private:
|
||||
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 {
|
||||
@ -813,6 +871,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(x.BeginDir().DirName().source,
|
||||
"%s region can only be strictly nested within TEAMS region"_err_en_US,
|
||||
ContextDirectiveAsFortran());
|
||||
}
|
||||
}
|
||||
|
||||
CheckNoBranching(block, beginSpec.DirId(), beginSpec.source);
|
||||
@ -896,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
|
||||
@ -4497,6 +4572,25 @@ void OmpStructureChecker::CheckWorkshareBlockStmts(
|
||||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::CheckWorkdistributeBlockStmts(
|
||||
const parser::Block &block, parser::CharBlock source) {
|
||||
unsigned version{context_.langOptions().OpenMPVersion};
|
||||
if (version < 60)
|
||||
context_.Say(source,
|
||||
"WORKDISTRIBUTE construct is only supported from openMP 6.0"_err_en_US);
|
||||
|
||||
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)};
|
||||
|
@ -245,6 +245,7 @@ private:
|
||||
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);
|
||||
|
@ -1736,10 +1736,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:
|
||||
@ -1769,9 +1772,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;
|
||||
|
27
flang/test/Parser/OpenMP/workdistribute.f90
Normal file
27
flang/test/Parser/OpenMP/workdistribute.f90
Normal file
@ -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: | | | OmpBeginDirective
|
||||
!PARSE-TREE: | | | | OmpDirectiveName -> llvm::omp::Directive = teams workdistribute
|
||||
!PARSE-TREE: | | | OmpEndDirective
|
||||
!PARSE-TREE: | | | | OmpDirectiveName -> 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
flang/test/Semantics/OpenMP/workdistribute01.f90
Normal file
16
flang/test/Semantics/OpenMP/workdistribute01.f90
Normal file
@ -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
flang/test/Semantics/OpenMP/workdistribute02.f90
Normal file
34
flang/test/Semantics/OpenMP/workdistribute02.f90
Normal file
@ -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
flang/test/Semantics/OpenMP/workdistribute03.f90
Normal file
34
flang/test/Semantics/OpenMP/workdistribute03.f90
Normal file
@ -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
flang/test/Semantics/OpenMP/workdistribute04.f90
Normal file
15
flang/test/Semantics/OpenMP/workdistribute04.f90
Normal file
@ -0,0 +1,15 @@
|
||||
! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=50
|
||||
! OpenMP Version 6.0
|
||||
! workdistribute Construct
|
||||
! Invalid do construct inside !$omp workdistribute
|
||||
|
||||
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 only supported from openMP 6.0
|
||||
!$omp teams workdistribute
|
||||
y = a * x + y
|
||||
!$omp end teams workdistribute
|
||||
end subroutine teams_workdistribute
|
@ -1322,6 +1322,17 @@ def OMP_EndWorkshare : Directive<[Spelling<"end workshare">]> {
|
||||
let category = OMP_Workshare.category;
|
||||
let languages = [L_Fortran];
|
||||
}
|
||||
def OMP_Workdistribute : Directive<[Spelling<"workdistribute">]> {
|
||||
let association = AS_Block;
|
||||
let category = CA_Executable;
|
||||
let languages = [L_Fortran];
|
||||
}
|
||||
def OMP_EndWorkdistribute : Directive<[Spelling<"end workdistribute">]> {
|
||||
let leafConstructs = OMP_Workdistribute.leafConstructs;
|
||||
let association = OMP_Workdistribute.association;
|
||||
let category = OMP_Workdistribute.category;
|
||||
let languages = [L_Fortran];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Definitions of OpenMP compound directives
|
||||
@ -2482,6 +2493,35 @@ def OMP_TargetTeamsDistributeSimd
|
||||
let leafConstructs = [OMP_Target, OMP_Teams, OMP_Distribute, OMP_Simd];
|
||||
let category = CA_Executable;
|
||||
}
|
||||
def OMP_TargetTeamsWorkdistribute : Directive<[Spelling<"target teams workdistribute">]> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_HasDeviceAddr, 51>,
|
||||
VersionedClause<OMPC_If>,
|
||||
VersionedClause<OMPC_IsDevicePtr>,
|
||||
VersionedClause<OMPC_Map>,
|
||||
VersionedClause<OMPC_OMPX_Attribute>,
|
||||
VersionedClause<OMPC_Private>,
|
||||
VersionedClause<OMPC_Reduction>,
|
||||
VersionedClause<OMPC_Shared>,
|
||||
VersionedClause<OMPC_UsesAllocators, 50>,
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_DefaultMap>,
|
||||
VersionedClause<OMPC_Device>,
|
||||
VersionedClause<OMPC_NoWait>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_OMPX_DynCGroupMem>,
|
||||
VersionedClause<OMPC_OMPX_Bare>,
|
||||
VersionedClause<OMPC_ThreadLimit>,
|
||||
];
|
||||
let leafConstructs = [OMP_Target, OMP_Teams, OMP_Workdistribute];
|
||||
let category = CA_Executable;
|
||||
let languages = [L_Fortran];
|
||||
}
|
||||
def OMP_target_teams_loop : Directive<[Spelling<"target teams loop">]> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
@ -2723,6 +2763,25 @@ def OMP_TeamsDistributeSimd : Directive<[Spelling<"teams distribute simd">]> {
|
||||
let leafConstructs = [OMP_Teams, OMP_Distribute, OMP_Simd];
|
||||
let category = CA_Executable;
|
||||
}
|
||||
def OMP_TeamsWorkdistribute : Directive<[Spelling<"teams workdistribute">]> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
VersionedClause<OMPC_FirstPrivate>,
|
||||
VersionedClause<OMPC_OMPX_Attribute>,
|
||||
VersionedClause<OMPC_Private>,
|
||||
VersionedClause<OMPC_Reduction>,
|
||||
VersionedClause<OMPC_Shared>,
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_Default>,
|
||||
VersionedClause<OMPC_If, 52>,
|
||||
VersionedClause<OMPC_NumTeams>,
|
||||
VersionedClause<OMPC_ThreadLimit>,
|
||||
];
|
||||
let leafConstructs = [OMP_Teams, OMP_Workdistribute];
|
||||
let category = CA_Executable;
|
||||
let languages = [L_Fortran];
|
||||
}
|
||||
def OMP_teams_loop : Directive<[Spelling<"teams loop">]> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Allocate>,
|
||||
|
@ -2209,4 +2209,27 @@ def TargetFreeMemOp : OpenMP_Op<"target_freemem",
|
||||
let assemblyFormat = "$device `,` $heapref attr-dict `:` type($device) `,` qualified(type($heapref))";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// workdistribute Construct
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def WorkdistributeOp : OpenMP_Op<"workdistribute"> {
|
||||
let summary = "workdistribute directive";
|
||||
let description = [{
|
||||
workdistribute divides execution of the enclosed structured block into
|
||||
separate units of work, each executed only once by each
|
||||
initial thread in the league.
|
||||
```
|
||||
!$omp target teams
|
||||
!$omp workdistribute
|
||||
y = a * x + y
|
||||
!$omp end workdistribute
|
||||
!$omp end target teams
|
||||
```
|
||||
}];
|
||||
let regions = (region AnyRegion:$region);
|
||||
let hasVerifier = 1;
|
||||
let assemblyFormat = "$region attr-dict";
|
||||
}
|
||||
|
||||
#endif // OPENMP_OPS
|
||||
|
@ -3975,6 +3975,58 @@ llvm::LogicalResult omp::TargetAllocMemOp::verify() {
|
||||
return mlir::success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// WorkdistributeOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
LogicalResult WorkdistributeOp::verify() {
|
||||
// Check that region exists and is not empty
|
||||
Region ®ion = getRegion();
|
||||
if (region.empty())
|
||||
return emitOpError("region cannot be empty");
|
||||
// Verify single entry point.
|
||||
Block &entryBlock = region.front();
|
||||
if (entryBlock.empty())
|
||||
return emitOpError("region must contain a structured block");
|
||||
// Verify single exit point.
|
||||
bool hasTerminator = false;
|
||||
for (Block &block : region) {
|
||||
if (isa<TerminatorOp>(block.back())) {
|
||||
if (hasTerminator) {
|
||||
return emitOpError("region must have exactly one terminator");
|
||||
}
|
||||
hasTerminator = true;
|
||||
}
|
||||
}
|
||||
if (!hasTerminator) {
|
||||
return emitOpError("region must be terminated with omp.terminator");
|
||||
}
|
||||
auto walkResult = region.walk([&](Operation *op) -> WalkResult {
|
||||
// No implicit barrier at end
|
||||
if (isa<BarrierOp>(op)) {
|
||||
return emitOpError(
|
||||
"explicit barriers are not allowed in workdistribute region");
|
||||
}
|
||||
// Check for invalid nested constructs
|
||||
if (isa<ParallelOp>(op)) {
|
||||
return emitOpError(
|
||||
"nested parallel constructs not allowed in workdistribute");
|
||||
}
|
||||
if (isa<TeamsOp>(op)) {
|
||||
return emitOpError(
|
||||
"nested teams constructs not allowed in workdistribute");
|
||||
}
|
||||
return WalkResult::advance();
|
||||
});
|
||||
if (walkResult.wasInterrupted())
|
||||
return failure();
|
||||
|
||||
Operation *parentOp = (*this)->getParentOp();
|
||||
if (!llvm::dyn_cast<TeamsOp>(parentOp))
|
||||
return emitOpError("workdistribute must be nested under teams");
|
||||
return success();
|
||||
}
|
||||
|
||||
#define GET_ATTRDEF_CLASSES
|
||||
#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
|
||||
|
||||
|
@ -3017,3 +3017,110 @@ func.func @invalid_allocate_allocator(%arg0 : memref<i32>) -> () {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
func.func @invalid_workdistribute_empty_region() -> () {
|
||||
omp.teams {
|
||||
// expected-error @below {{region cannot be empty}}
|
||||
omp.workdistribute {
|
||||
}
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
func.func @invalid_workdistribute_no_terminator() -> () {
|
||||
omp.teams {
|
||||
// expected-error @below {{region must be terminated with omp.terminator}}
|
||||
omp.workdistribute {
|
||||
%c0 = arith.constant 0 : i32
|
||||
}
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
func.func @invalid_workdistribute_wrong_terminator() -> () {
|
||||
omp.teams {
|
||||
// expected-error @below {{region must be terminated with omp.terminator}}
|
||||
omp.workdistribute {
|
||||
%c0 = arith.constant 0 : i32
|
||||
func.return
|
||||
}
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
func.func @invalid_workdistribute_multiple_terminators() -> () {
|
||||
omp.teams {
|
||||
// expected-error @below {{region must have exactly one terminator}}
|
||||
omp.workdistribute {
|
||||
%cond = arith.constant true
|
||||
cf.cond_br %cond, ^bb1, ^bb2
|
||||
^bb1:
|
||||
omp.terminator
|
||||
^bb2:
|
||||
omp.terminator
|
||||
}
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
func.func @invalid_workdistribute_with_barrier() -> () {
|
||||
omp.teams {
|
||||
// expected-error @below {{explicit barriers are not allowed in workdistribute region}}
|
||||
omp.workdistribute {
|
||||
%c0 = arith.constant 0 : i32
|
||||
omp.barrier
|
||||
omp.terminator
|
||||
}
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
func.func @invalid_workdistribute_nested_parallel() -> () {
|
||||
omp.teams {
|
||||
// expected-error @below {{nested parallel constructs not allowed in workdistribute}}
|
||||
omp.workdistribute {
|
||||
omp.parallel {
|
||||
omp.terminator
|
||||
}
|
||||
omp.terminator
|
||||
}
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
// Test: nested teams not allowed in workdistribute
|
||||
func.func @invalid_workdistribute_nested_teams() -> () {
|
||||
omp.teams {
|
||||
// expected-error @below {{nested teams constructs not allowed in workdistribute}}
|
||||
omp.workdistribute {
|
||||
omp.teams {
|
||||
omp.terminator
|
||||
}
|
||||
omp.terminator
|
||||
}
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
func.func @invalid_workdistribute() -> () {
|
||||
// expected-error @below {{workdistribute must be nested under teams}}
|
||||
omp.workdistribute {
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -3238,3 +3238,15 @@ func.func @omp_allocate_dir(%arg0 : memref<i32>, %arg1 : memref<i32>) -> () {
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: func.func @omp_workdistribute
|
||||
func.func @omp_workdistribute() {
|
||||
// CHECK: omp.teams
|
||||
omp.teams {
|
||||
// CHECK: omp.workdistribute
|
||||
omp.workdistribute {
|
||||
omp.terminator
|
||||
}
|
||||
omp.terminator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user