Skip to content

Commit 58f45d9

Browse files
[flang][openmp] - depend clause support in target, target enter/update/exit data constructs (#81610)
This patch adds support in flang for the depend clause in target and target enter/update/exit constructs. Previously, the following line in a fortran program would have resulted in the error shown below it. !$omp target map(to:a) depend(in:a) "not yet implemented: Unhandled clause DEPEND in TARGET construct"
1 parent 71441ed commit 58f45d9

File tree

4 files changed

+113
-11
lines changed

4 files changed

+113
-11
lines changed

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,8 @@ genEnterExitUpdateDataOp(Fortran::lower::AbstractConverter &converter,
761761
Fortran::lower::StatementContext stmtCtx;
762762
mlir::Value ifClauseOperand, deviceOperand;
763763
mlir::UnitAttr nowaitAttr;
764-
llvm::SmallVector<mlir::Value> mapOperands;
764+
llvm::SmallVector<mlir::Value> mapOperands, dependOperands;
765+
llvm::SmallVector<mlir::Attribute> dependTypeOperands;
765766

766767
Fortran::parser::OmpIfClause::DirectiveNameModifier directiveName;
767768
llvm::omp::Directive directive;
@@ -784,6 +785,7 @@ genEnterExitUpdateDataOp(Fortran::lower::AbstractConverter &converter,
784785
ClauseProcessor cp(converter, semaCtx, clauseList);
785786
cp.processIf(directiveName, ifClauseOperand);
786787
cp.processDevice(stmtCtx, deviceOperand);
788+
cp.processDepend(dependTypeOperands, dependOperands);
787789
cp.processNowait(nowaitAttr);
788790

789791
if constexpr (std::is_same_v<OpTy, mlir::omp::UpdateDataOp>) {
@@ -796,12 +798,13 @@ genEnterExitUpdateDataOp(Fortran::lower::AbstractConverter &converter,
796798
cp.processMap(currentLocation, directive, stmtCtx, mapOperands);
797799
}
798800

799-
cp.processTODO<Fortran::parser::OmpClause::Depend>(currentLocation,
800-
directive);
801-
802-
return firOpBuilder.create<OpTy>(currentLocation, ifClauseOperand,
803-
deviceOperand, nullptr, mlir::ValueRange(),
804-
nowaitAttr, mapOperands);
801+
return firOpBuilder.create<OpTy>(
802+
currentLocation, ifClauseOperand, deviceOperand,
803+
dependTypeOperands.empty()
804+
? nullptr
805+
: mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(),
806+
dependTypeOperands),
807+
dependOperands, nowaitAttr, mapOperands);
805808
}
806809

807810
// This functions creates a block for the body of the targetOp's region. It adds
@@ -968,7 +971,8 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
968971
Fortran::lower::StatementContext stmtCtx;
969972
mlir::Value ifClauseOperand, deviceOperand, threadLimitOperand;
970973
mlir::UnitAttr nowaitAttr;
971-
llvm::SmallVector<mlir::Value> mapOperands;
974+
llvm::SmallVector<mlir::Attribute> dependTypeOperands;
975+
llvm::SmallVector<mlir::Value> mapOperands, dependOperands;
972976
llvm::SmallVector<mlir::Type> mapSymTypes;
973977
llvm::SmallVector<mlir::Location> mapSymLocs;
974978
llvm::SmallVector<const Fortran::semantics::Symbol *> mapSymbols;
@@ -978,11 +982,12 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
978982
ifClauseOperand);
979983
cp.processDevice(stmtCtx, deviceOperand);
980984
cp.processThreadLimit(stmtCtx, threadLimitOperand);
985+
cp.processDepend(dependTypeOperands, dependOperands);
981986
cp.processNowait(nowaitAttr);
982987
cp.processMap(currentLocation, directive, stmtCtx, mapOperands, &mapSymTypes,
983988
&mapSymLocs, &mapSymbols);
989+
984990
cp.processTODO<Fortran::parser::OmpClause::Private,
985-
Fortran::parser::OmpClause::Depend,
986991
Fortran::parser::OmpClause::Firstprivate,
987992
Fortran::parser::OmpClause::IsDevicePtr,
988993
Fortran::parser::OmpClause::HasDeviceAddr,
@@ -992,7 +997,6 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
992997
Fortran::parser::OmpClause::UsesAllocators,
993998
Fortran::parser::OmpClause::Defaultmap>(
994999
currentLocation, llvm::omp::Directive::OMPD_target);
995-
9961000
// 5.8.1 Implicit Data-Mapping Attribute Rules
9971001
// The following code follows the implicit data-mapping rules to map all the
9981002
// symbols used inside the region that have not been explicitly mapped using
@@ -1066,7 +1070,11 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
10661070

10671071
auto targetOp = converter.getFirOpBuilder().create<mlir::omp::TargetOp>(
10681072
currentLocation, ifClauseOperand, deviceOperand, threadLimitOperand,
1069-
nullptr, mlir::ValueRange(), nowaitAttr, mapOperands);
1073+
dependTypeOperands.empty()
1074+
? nullptr
1075+
: mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(),
1076+
dependTypeOperands),
1077+
dependOperands, nowaitAttr, mapOperands);
10701078

10711079
genBodyOfTargetOp(converter, semaCtx, eval, genNested, targetOp, mapSymTypes,
10721080
mapSymLocs, mapSymbols, currentLocation);

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2815,6 +2815,14 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Device &x) {
28152815

28162816
void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
28172817
CheckAllowed(llvm::omp::Clause::OMPC_depend);
2818+
if ((std::holds_alternative<parser::OmpDependClause::Source>(x.v.u) ||
2819+
std::holds_alternative<parser::OmpDependClause::Sink>(x.v.u)) &&
2820+
GetContext().directive != llvm::omp::OMPD_ordered) {
2821+
context_.Say(GetContext().clauseSource,
2822+
"DEPEND(SOURCE) or DEPEND(SINK : vec) can be used only with the ordered"
2823+
" directive. Used here in the %s construct."_err_en_US,
2824+
parser::ToUpperCaseLetters(getDirectiveName(GetContext().directive)));
2825+
}
28182826
if (const auto *inOut{std::get_if<parser::OmpDependClause::InOut>(&x.v.u)}) {
28192827
const auto &designators{std::get<std::list<parser::Designator>>(inOut->t)};
28202828
for (const auto &ele : designators) {

flang/test/Lower/OpenMP/target.f90

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,26 @@ subroutine omp_target_enter_simple
1414
return
1515
end subroutine omp_target_enter_simple
1616

17+
!===============================================================================
18+
! Target_Enter `depend` clause
19+
!===============================================================================
20+
21+
!CHECK-LABEL: func.func @_QPomp_target_enter_depend() {
22+
subroutine omp_target_enter_depend
23+
!CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFomp_target_enter_dependEa"} : (!fir.ref<!fir.array<1024xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1024xi32>>, !fir.ref<!fir.array<1024xi32>>)
24+
integer :: a(1024)
25+
26+
!CHECK: omp.task depend(taskdependout -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
27+
!$omp task depend(out: a)
28+
call foo(a)
29+
!$omp end task
30+
!CHECK: %[[BOUNDS:.*]] = omp.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}})
31+
!CHECK: %[[MAP:.*]] = omp.map_info var_ptr({{.*}}) map_clauses(to) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
32+
!CHECK: omp.target_enter_data map_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>) depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>)
33+
!$omp target enter data map(to: a) depend(in: a)
34+
return
35+
end subroutine omp_target_enter_depend
36+
1737
!===============================================================================
1838
! Target_Enter Map types
1939
!===============================================================================
@@ -134,6 +154,45 @@ subroutine omp_target_exit_device
134154
!$omp target exit data map(from: a) device(d)
135155
end subroutine omp_target_exit_device
136156

157+
!===============================================================================
158+
! Target_Exit `depend` clause
159+
!===============================================================================
160+
161+
!CHECK-LABEL: func.func @_QPomp_target_exit_depend() {
162+
subroutine omp_target_exit_depend
163+
!CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFomp_target_exit_dependEa"} : (!fir.ref<!fir.array<1024xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1024xi32>>, !fir.ref<!fir.array<1024xi32>>)
164+
integer :: a(1024)
165+
!CHECK: omp.task depend(taskdependout -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
166+
!$omp task depend(out: a)
167+
call foo(a)
168+
!$omp end task
169+
!CHECK: %[[BOUNDS:.*]] = omp.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}})
170+
!CHECK: %[[MAP:.*]] = omp.map_info var_ptr({{.*}}) map_clauses(from) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
171+
!CHECK: omp.target_exit_data map_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>) depend(taskdependout -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>)
172+
!$omp target exit data map(from: a) depend(out: a)
173+
end subroutine omp_target_exit_depend
174+
175+
176+
!===============================================================================
177+
! Target_Update `depend` clause
178+
!===============================================================================
179+
180+
!CHECK-LABEL: func.func @_QPomp_target_update_depend() {
181+
subroutine omp_target_update_depend
182+
!CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFomp_target_update_dependEa"} : (!fir.ref<!fir.array<1024xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1024xi32>>, !fir.ref<!fir.array<1024xi32>>)
183+
integer :: a(1024)
184+
185+
!CHECK: omp.task depend(taskdependout -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
186+
!$omp task depend(out: a)
187+
call foo(a)
188+
!$omp end task
189+
190+
!CHECK: %[[BOUNDS:.*]] = omp.bounds
191+
!CHECK: %[[MAP:.*]] = omp.map_info var_ptr(%[[A]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(to) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
192+
!CHECK: omp.target_update_data motion_entries(%[[MAP]] : !fir.ref<!fir.array<1024xi32>>) depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>)
193+
!$omp target update to(a) depend(in:a)
194+
end subroutine omp_target_update_depend
195+
137196
!===============================================================================
138197
! Target_Update `to` clause
139198
!===============================================================================
@@ -295,6 +354,32 @@ subroutine omp_target
295354
!CHECK: }
296355
end subroutine omp_target
297356

357+
!===============================================================================
358+
! Target with region `depend` clause
359+
!===============================================================================
360+
361+
!CHECK-LABEL: func.func @_QPomp_target_depend() {
362+
subroutine omp_target_depend
363+
!CHECK: %[[EXTENT_A:.*]] = arith.constant 1024 : index
364+
!CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFomp_target_dependEa"} : (!fir.ref<!fir.array<1024xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<1024xi32>>, !fir.ref<!fir.array<1024xi32>>)
365+
integer :: a(1024)
366+
!CHECK: omp.task depend(taskdependout -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
367+
!$omp task depend(out: a)
368+
call foo(a)
369+
!$omp end task
370+
!CHECK: %[[STRIDE_A:.*]] = arith.constant 1 : index
371+
!CHECK: %[[LBOUND_A:.*]] = arith.constant 0 : index
372+
!CHECK: %[[UBOUND_A:.*]] = arith.subi %c1024, %c1 : index
373+
!CHECK: %[[BOUNDS_A:.*]] = omp.bounds lower_bound(%[[LBOUND_A]] : index) upper_bound(%[[UBOUND_A]] : index) extent(%[[EXTENT_A]] : index) stride(%[[STRIDE_A]] : index) start_idx(%[[STRIDE_A]] : index)
374+
!CHECK: %[[MAP_A:.*]] = omp.map_info var_ptr(%[[A]]#0 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_A]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
375+
!CHECK: omp.target map_entries(%[[MAP_A]] -> %[[BB0_ARG:.*]] : !fir.ref<!fir.array<1024xi32>>) depend(taskdependin -> %[[A]]#1 : !fir.ref<!fir.array<1024xi32>>) {
376+
!$omp target map(tofrom: a) depend(in: a)
377+
a(1) = 10
378+
!CHECK: omp.terminator
379+
!$omp end target
380+
!CHECK: }
381+
end subroutine omp_target_depend
382+
298383
!===============================================================================
299384
! Target implicit capture
300385
!===============================================================================

flang/test/Semantics/OpenMP/clause-validity01.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@
481481
!$omp taskyield
482482
!$omp barrier
483483
!$omp taskwait
484+
!ERROR: DEPEND(SOURCE) or DEPEND(SINK : vec) can be used only with the ordered directive. Used here in the TASKWAIT construct.
484485
!$omp taskwait depend(source)
485486
! !$omp taskwait depend(sink:i-1)
486487
! !$omp target enter data map(to:arrayA) map(alloc:arrayB)

0 commit comments

Comments
 (0)