diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 3aefad6cf0ec1..89bd5ed080b20 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -761,7 +761,8 @@ genEnterExitUpdateDataOp(Fortran::lower::AbstractConverter &converter, Fortran::lower::StatementContext stmtCtx; mlir::Value ifClauseOperand, deviceOperand; mlir::UnitAttr nowaitAttr; - llvm::SmallVector mapOperands; + llvm::SmallVector mapOperands, dependOperands; + llvm::SmallVector dependTypeOperands; Fortran::parser::OmpIfClause::DirectiveNameModifier directiveName; llvm::omp::Directive directive; @@ -784,6 +785,7 @@ genEnterExitUpdateDataOp(Fortran::lower::AbstractConverter &converter, ClauseProcessor cp(converter, semaCtx, clauseList); cp.processIf(directiveName, ifClauseOperand); cp.processDevice(stmtCtx, deviceOperand); + cp.processDepend(dependTypeOperands, dependOperands); cp.processNowait(nowaitAttr); if constexpr (std::is_same_v) { @@ -796,12 +798,13 @@ genEnterExitUpdateDataOp(Fortran::lower::AbstractConverter &converter, cp.processMap(currentLocation, directive, stmtCtx, mapOperands); } - cp.processTODO(currentLocation, - directive); - - return firOpBuilder.create(currentLocation, ifClauseOperand, - deviceOperand, nullptr, mlir::ValueRange(), - nowaitAttr, mapOperands); + return firOpBuilder.create( + currentLocation, ifClauseOperand, deviceOperand, + dependTypeOperands.empty() + ? nullptr + : mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(), + dependTypeOperands), + dependOperands, nowaitAttr, mapOperands); } // This functions creates a block for the body of the targetOp's region. It adds @@ -968,7 +971,8 @@ genTargetOp(Fortran::lower::AbstractConverter &converter, Fortran::lower::StatementContext stmtCtx; mlir::Value ifClauseOperand, deviceOperand, threadLimitOperand; mlir::UnitAttr nowaitAttr; - llvm::SmallVector mapOperands; + llvm::SmallVector dependTypeOperands; + llvm::SmallVector mapOperands, dependOperands; llvm::SmallVector mapSymTypes; llvm::SmallVector mapSymLocs; llvm::SmallVector mapSymbols; @@ -978,11 +982,12 @@ genTargetOp(Fortran::lower::AbstractConverter &converter, ifClauseOperand); cp.processDevice(stmtCtx, deviceOperand); cp.processThreadLimit(stmtCtx, threadLimitOperand); + cp.processDepend(dependTypeOperands, dependOperands); cp.processNowait(nowaitAttr); cp.processMap(currentLocation, directive, stmtCtx, mapOperands, &mapSymTypes, &mapSymLocs, &mapSymbols); + cp.processTODO( currentLocation, llvm::omp::Directive::OMPD_target); - // 5.8.1 Implicit Data-Mapping Attribute Rules // The following code follows the implicit data-mapping rules to map all the // symbols used inside the region that have not been explicitly mapped using @@ -1066,7 +1070,11 @@ genTargetOp(Fortran::lower::AbstractConverter &converter, auto targetOp = converter.getFirOpBuilder().create( currentLocation, ifClauseOperand, deviceOperand, threadLimitOperand, - nullptr, mlir::ValueRange(), nowaitAttr, mapOperands); + dependTypeOperands.empty() + ? nullptr + : mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(), + dependTypeOperands), + dependOperands, nowaitAttr, mapOperands); genBodyOfTargetOp(converter, semaCtx, eval, genNested, targetOp, mapSymTypes, mapSymLocs, mapSymbols, currentLocation); diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 03423de0c6104..54101ab8a42bb 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -2815,6 +2815,14 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Device &x) { void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) { CheckAllowed(llvm::omp::Clause::OMPC_depend); + if ((std::holds_alternative(x.v.u) || + std::holds_alternative(x.v.u)) && + GetContext().directive != llvm::omp::OMPD_ordered) { + context_.Say(GetContext().clauseSource, + "DEPEND(SOURCE) or DEPEND(SINK : vec) can be used only with the ordered" + " directive. Used here in the %s construct."_err_en_US, + parser::ToUpperCaseLetters(getDirectiveName(GetContext().directive))); + } if (const auto *inOut{std::get_if(&x.v.u)}) { const auto &designators{std::get>(inOut->t)}; for (const auto &ele : designators) { diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90 index fa07b7f71d514..030533e1a0455 100644 --- a/flang/test/Lower/OpenMP/target.f90 +++ b/flang/test/Lower/OpenMP/target.f90 @@ -14,6 +14,26 @@ subroutine omp_target_enter_simple return end subroutine omp_target_enter_simple +!=============================================================================== +! Target_Enter `depend` clause +!=============================================================================== + +!CHECK-LABEL: func.func @_QPomp_target_enter_depend() { +subroutine omp_target_enter_depend + !CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFomp_target_enter_dependEa"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) + integer :: a(1024) + + !CHECK: omp.task depend(taskdependout -> %[[A]]#1 : !fir.ref>) { + !$omp task depend(out: a) + call foo(a) + !$omp end task + !CHECK: %[[BOUNDS:.*]] = omp.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) + !CHECK: %[[MAP:.*]] = omp.map_info var_ptr({{.*}}) map_clauses(to) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref> {name = "a"} + !CHECK: omp.target_enter_data map_entries(%[[MAP]] : !fir.ref>) depend(taskdependin -> %[[A]]#1 : !fir.ref>) + !$omp target enter data map(to: a) depend(in: a) + return +end subroutine omp_target_enter_depend + !=============================================================================== ! Target_Enter Map types !=============================================================================== @@ -134,6 +154,45 @@ subroutine omp_target_exit_device !$omp target exit data map(from: a) device(d) end subroutine omp_target_exit_device +!=============================================================================== +! Target_Exit `depend` clause +!=============================================================================== + +!CHECK-LABEL: func.func @_QPomp_target_exit_depend() { +subroutine omp_target_exit_depend + !CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFomp_target_exit_dependEa"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) + integer :: a(1024) + !CHECK: omp.task depend(taskdependout -> %[[A]]#1 : !fir.ref>) { + !$omp task depend(out: a) + call foo(a) + !$omp end task + !CHECK: %[[BOUNDS:.*]] = omp.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) + !CHECK: %[[MAP:.*]] = omp.map_info var_ptr({{.*}}) map_clauses(from) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref> {name = "a"} + !CHECK: omp.target_exit_data map_entries(%[[MAP]] : !fir.ref>) depend(taskdependout -> %[[A]]#1 : !fir.ref>) + !$omp target exit data map(from: a) depend(out: a) +end subroutine omp_target_exit_depend + + +!=============================================================================== +! Target_Update `depend` clause +!=============================================================================== + +!CHECK-LABEL: func.func @_QPomp_target_update_depend() { +subroutine omp_target_update_depend + !CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFomp_target_update_dependEa"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) + integer :: a(1024) + + !CHECK: omp.task depend(taskdependout -> %[[A]]#1 : !fir.ref>) { + !$omp task depend(out: a) + call foo(a) + !$omp end task + + !CHECK: %[[BOUNDS:.*]] = omp.bounds + !CHECK: %[[MAP:.*]] = omp.map_info var_ptr(%[[A]]#0 : !fir.ref>, !fir.array<1024xi32>) map_clauses(to) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref> {name = "a"} + !CHECK: omp.target_update_data motion_entries(%[[MAP]] : !fir.ref>) depend(taskdependin -> %[[A]]#1 : !fir.ref>) + !$omp target update to(a) depend(in:a) +end subroutine omp_target_update_depend + !=============================================================================== ! Target_Update `to` clause !=============================================================================== @@ -295,6 +354,32 @@ subroutine omp_target !CHECK: } end subroutine omp_target +!=============================================================================== +! Target with region `depend` clause +!=============================================================================== + +!CHECK-LABEL: func.func @_QPomp_target_depend() { +subroutine omp_target_depend + !CHECK: %[[EXTENT_A:.*]] = arith.constant 1024 : index + !CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFomp_target_dependEa"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) + integer :: a(1024) + !CHECK: omp.task depend(taskdependout -> %[[A]]#1 : !fir.ref>) { + !$omp task depend(out: a) + call foo(a) + !$omp end task + !CHECK: %[[STRIDE_A:.*]] = arith.constant 1 : index + !CHECK: %[[LBOUND_A:.*]] = arith.constant 0 : index + !CHECK: %[[UBOUND_A:.*]] = arith.subi %c1024, %c1 : index + !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) + !CHECK: %[[MAP_A:.*]] = omp.map_info var_ptr(%[[A]]#0 : !fir.ref>, !fir.array<1024xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_A]]) -> !fir.ref> {name = "a"} + !CHECK: omp.target map_entries(%[[MAP_A]] -> %[[BB0_ARG:.*]] : !fir.ref>) depend(taskdependin -> %[[A]]#1 : !fir.ref>) { + !$omp target map(tofrom: a) depend(in: a) + a(1) = 10 + !CHECK: omp.terminator + !$omp end target + !CHECK: } + end subroutine omp_target_depend + !=============================================================================== ! Target implicit capture !=============================================================================== diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90 index 3fa86ed105a29..d9573a81821f3 100644 --- a/flang/test/Semantics/OpenMP/clause-validity01.f90 +++ b/flang/test/Semantics/OpenMP/clause-validity01.f90 @@ -481,6 +481,7 @@ !$omp taskyield !$omp barrier !$omp taskwait + !ERROR: DEPEND(SOURCE) or DEPEND(SINK : vec) can be used only with the ordered directive. Used here in the TASKWAIT construct. !$omp taskwait depend(source) ! !$omp taskwait depend(sink:i-1) ! !$omp target enter data map(to:arrayA) map(alloc:arrayB)