diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp index 8ed31766725e1..c3a570bf15ea0 100644 --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -607,6 +607,12 @@ class ClauseProcessor { llvm::SmallVectorImpl &useDeviceSymbols) const; + template + bool + processMotionClauses(Fortran::semantics::SemanticsContext &semanticsContext, + Fortran::lower::StatementContext &stmtCtx, + llvm::SmallVectorImpl &mapOperands); + // Call this method for these clauses that should be supported but are not // implemented yet. It triggers a compilation error if any of the given // clauses is found. @@ -1893,6 +1899,47 @@ bool ClauseProcessor::processUseDevicePtr( }); } +template +bool ClauseProcessor::processMotionClauses( + Fortran::semantics::SemanticsContext &semanticsContext, + Fortran::lower::StatementContext &stmtCtx, + llvm::SmallVectorImpl &mapOperands) { + return findRepeatableClause( + [&](const T *motionClause, const Fortran::parser::CharBlock &source) { + mlir::Location clauseLocation = converter.genLocation(source); + fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + + static_assert(std::is_same_v || + std::is_same_v); + + // TODO Support motion modifiers: present, mapper, iterator. + constexpr llvm::omp::OpenMPOffloadMappingFlags mapTypeBits = + std::is_same_v + ? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO + : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM; + + for (const Fortran::parser::OmpObject &ompObject : motionClause->v.v) { + llvm::SmallVector bounds; + std::stringstream asFortran; + Fortran::lower::AddrAndBoundsInfo info = + Fortran::lower::gatherDataOperandAddrAndBounds< + Fortran::parser::OmpObject, mlir::omp::DataBoundsOp, + mlir::omp::DataBoundsType>( + converter, firOpBuilder, semanticsContext, stmtCtx, ompObject, + clauseLocation, asFortran, bounds, treatIndexAsSection); + + mlir::Value mapOp = createMapInfoOp( + firOpBuilder, clauseLocation, info.addr, asFortran, bounds, + static_cast< + std::underlying_type_t>( + mapTypeBits), + mlir::omp::VariableCaptureKind::ByRef, info.addr.getType()); + + mapOperands.push_back(mapOp); + } + }); +} + template void ClauseProcessor::processTODO(mlir::Location currentLocation, llvm::omp::Directive directive) const { @@ -2416,10 +2463,10 @@ genDataOp(Fortran::lower::AbstractConverter &converter, template static OpTy -genEnterExitDataOp(Fortran::lower::AbstractConverter &converter, - Fortran::semantics::SemanticsContext &semanticsContext, - mlir::Location currentLocation, - const Fortran::parser::OmpClauseList &clauseList) { +genEnterExitUpdateDataOp(Fortran::lower::AbstractConverter &converter, + Fortran::semantics::SemanticsContext &semanticsContext, + mlir::Location currentLocation, + const Fortran::parser::OmpClauseList &clauseList) { fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); Fortran::lower::StatementContext stmtCtx; mlir::Value ifClauseOperand, deviceOperand; @@ -2436,6 +2483,10 @@ genEnterExitDataOp(Fortran::lower::AbstractConverter &converter, directiveName = Fortran::parser::OmpIfClause::DirectiveNameModifier::TargetExitData; directive = llvm::omp::Directive::OMPD_target_exit_data; + } else if constexpr (std::is_same_v) { + directiveName = + Fortran::parser::OmpIfClause::DirectiveNameModifier::TargetUpdate; + directive = llvm::omp::Directive::OMPD_target_update; } else { return nullptr; } @@ -2444,8 +2495,18 @@ genEnterExitDataOp(Fortran::lower::AbstractConverter &converter, cp.processIf(directiveName, ifClauseOperand); cp.processDevice(stmtCtx, deviceOperand); cp.processNowait(nowaitAttr); - cp.processMap(currentLocation, directive, semanticsContext, stmtCtx, - mapOperands); + + if constexpr (std::is_same_v) { + cp.processMotionClauses( + semanticsContext, stmtCtx, mapOperands); + cp.processMotionClauses( + semanticsContext, stmtCtx, mapOperands); + + } else { + cp.processMap(currentLocation, directive, semanticsContext, stmtCtx, + mapOperands); + } + cp.processTODO(currentLocation, directive); @@ -2847,15 +2908,17 @@ genOmpSimpleStandalone(Fortran::lower::AbstractConverter &converter, genDataOp(converter, eval, semanticsContext, currentLocation, opClauseList); break; case llvm::omp::Directive::OMPD_target_enter_data: - genEnterExitDataOp(converter, semanticsContext, - currentLocation, opClauseList); + genEnterExitUpdateDataOp( + converter, semanticsContext, currentLocation, opClauseList); break; case llvm::omp::Directive::OMPD_target_exit_data: - genEnterExitDataOp(converter, semanticsContext, - currentLocation, opClauseList); + genEnterExitUpdateDataOp( + converter, semanticsContext, currentLocation, opClauseList); break; case llvm::omp::Directive::OMPD_target_update: - TODO(currentLocation, "OMPD_target_update"); + genEnterExitUpdateDataOp( + converter, semanticsContext, currentLocation, opClauseList); + break; case llvm::omp::Directive::OMPD_ordered: TODO(currentLocation, "OMPD_ordered"); } diff --git a/flang/test/Lower/OpenMP/FIR/target.f90 b/flang/test/Lower/OpenMP/FIR/target.f90 index 2034ac84334e5..5d36699bf0e90 100644 --- a/flang/test/Lower/OpenMP/FIR/target.f90 +++ b/flang/test/Lower/OpenMP/FIR/target.f90 @@ -133,6 +133,100 @@ subroutine omp_target_exit_device !$omp target exit data map(from: a) device(d) end subroutine omp_target_exit_device +!=============================================================================== +! Target_Update `to` clause +!=============================================================================== + +subroutine omp_target_update_to + integer :: a(1024) + + !CHECK-DAG: %[[A_ALLOC:.*]] = fir.alloca !fir.array<1024xi32> {bindc_name = "a", uniq_name = "_QFomp_target_update_toEa"} + !CHECK-DAG: %[[BOUNDS:.*]] = omp.bounds + + !CHECK: %[[TO_MAP:.*]] = omp.map_info var_ptr(%[[A_ALLOC]] : !fir.ref>, !fir.array<1024xi32>) + !CHECK-SAME: map_clauses(to) capture(ByRef) + !CHECK-SAME: bounds(%[[BOUNDS]]) -> !fir.ref> {name = "a"} + + !CHECK: omp.target_update_data + !CHECK-SAME: motion_entries(%[[TO_MAP]] : !fir.ref>) + !$omp target update to(a) +end subroutine omp_target_update_to + +!=============================================================================== +! Target_Update `from` clause +!=============================================================================== + +subroutine omp_target_update_from + integer :: a(1024) + + !CHECK-DAG: %[[A_ALLOC:.*]] = fir.alloca !fir.array<1024xi32> {bindc_name = "a", uniq_name = "_QFomp_target_update_fromEa"} + !CHECK-DAG: %[[BOUNDS:.*]] = omp.bounds + + !CHECK: %[[FROM_MAP:.*]] = omp.map_info var_ptr(%[[A_ALLOC]] : !fir.ref>, !fir.array<1024xi32>) + !CHECK-SAME: map_clauses(from) capture(ByRef) + !CHECK-SAME: bounds(%[[BOUNDS]]) -> !fir.ref> {name = "a"} + + !CHECK: omp.target_update_data + !CHECK-SAME: motion_entries(%[[FROM_MAP]] : !fir.ref>) + !$omp target update from(a) +end subroutine omp_target_update_from + +!=============================================================================== +! Target_Update `if` clause +!=============================================================================== + +subroutine omp_target_update_if + integer :: a(1024) + logical :: i + + !CHECK-DAG: %[[A_ALLOC:.*]] = fir.alloca + !CHECK-DAG: %[[BOUNDS:.*]] = omp.bounds + !CHECK-DAG: %[[COND:.*]] = fir.convert %{{.*}} : (!fir.logical<4>) -> i1 + + !CHECK: %[[TO_MAP:.*]] = omp.map_info + + !CHECK: omp.target_update_data if(%[[COND]] : i1) + !CHECK-SAME: motion_entries(%[[TO_MAP]] : !fir.ref>) + !$omp target update to(a) if(i) +end subroutine omp_target_update_if + +!=============================================================================== +! Target_Update `device` clause +!=============================================================================== + +subroutine omp_target_update_device + integer :: a(1024) + + !CHECK-DAG: %[[A_ALLOC:.*]] = fir.alloca + !CHECK-DAG: %[[BOUNDS:.*]] = omp.bounds + !CHECK-DAG: %[[DEVICE:.*]] = arith.constant 1 : i32 + + !CHECK: %[[TO_MAP:.*]] = omp.map_info + + !CHECK: omp.target_update_data + !CHECK-SAME: device(%[[DEVICE]] : i32) + !CHECK-SAME: motion_entries(%[[TO_MAP]] : !fir.ref>) + !$omp target update to(a) device(1) +end subroutine omp_target_update_device + +!=============================================================================== +! Target_Update `nowait` clause +!=============================================================================== + +subroutine omp_target_update_nowait + integer :: a(1024) + + !CHECK-DAG: %[[A_ALLOC:.*]] = fir.alloca + !CHECK-DAG: %[[BOUNDS:.*]] = omp.bounds + + !CHECK: %[[TO_MAP:.*]] = omp.map_info + + !CHECK: omp.target_update_data + !CHECK-SAME: nowait + !CHECK-SAME: motion_entries(%[[TO_MAP]] : !fir.ref>) + !$omp target update to(a) nowait +end subroutine omp_target_update_nowait + !=============================================================================== ! Target_Data with region !=============================================================================== diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90 index 26b4d595d5229..5ca3a08d8a8b2 100644 --- a/flang/test/Lower/OpenMP/target.f90 +++ b/flang/test/Lower/OpenMP/target.f90 @@ -134,6 +134,94 @@ subroutine omp_target_exit_device !$omp target exit data map(from: a) device(d) end subroutine omp_target_exit_device +!=============================================================================== +! Target_Update `to` clause +!=============================================================================== + +!CHECK-LABEL: func.func @_QPomp_target_update_to() { +subroutine omp_target_update_to + integer :: a(1024) + + !CHECK-DAG: %[[A_DECL:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) + !CHECK-DAG: %[[BOUNDS:.*]] = omp.bounds + + !CHECK: %[[TO_MAP:.*]] = omp.map_info var_ptr(%[[A_DECL]]#1 : !fir.ref>, !fir.array<1024xi32>) + !CHECK-SAME: map_clauses(to) capture(ByRef) + !CHECK-SAME: bounds(%[[BOUNDS]]) -> !fir.ref> {name = "a"} + + !CHECK: omp.target_update_data motion_entries(%[[TO_MAP]] : !fir.ref>) + !$omp target update to(a) +end subroutine omp_target_update_to + +!=============================================================================== +! Target_Update `from` clause +!=============================================================================== + +!CHECK-LABEL: func.func @_QPomp_target_update_from() { +subroutine omp_target_update_from + integer :: a(1024) + + !CHECK-DAG: %[[A_DECL:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) + !CHECK-DAG: %[[BOUNDS:.*]] = omp.bounds + + !CHECK: %[[FROM_MAP:.*]] = omp.map_info var_ptr(%[[A_DECL]]#1 : !fir.ref>, !fir.array<1024xi32>) + !CHECK-SAME: map_clauses(from) capture(ByRef) + !CHECK-SAME: bounds(%[[BOUNDS]]) -> !fir.ref> {name = "a"} + + !CHECK: omp.target_update_data motion_entries(%[[FROM_MAP]] : !fir.ref>) + !$omp target update from(a) +end subroutine omp_target_update_from + +!=============================================================================== +! Target_Update `if` clause +!=============================================================================== + +!CHECK-LABEL: func.func @_QPomp_target_update_if() { +subroutine omp_target_update_if + integer :: a(1024) + logical :: i + + !CHECK-DAG: %[[A_DECL:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) + !CHECK-DAG: %[[BOUNDS:.*]] = omp.bounds + !CHECK-DAG: %[[COND:.*]] = fir.convert %{{.*}} : (!fir.logical<4>) -> i1 + + !CHECK: omp.target_update_data if(%[[COND]] : i1) motion_entries + !$omp target update from(a) if(i) +end subroutine omp_target_update_if + +!=============================================================================== +! Target_Update `device` clause +!=============================================================================== + +!CHECK-LABEL: func.func @_QPomp_target_update_device() { +subroutine omp_target_update_device + integer :: a(1024) + logical :: i + + !CHECK-DAG: %[[A_DECL:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) + !CHECK-DAG: %[[BOUNDS:.*]] = omp.bounds + !CHECK-DAG: %[[DEVICE:.*]] = arith.constant 1 : i32 + + !CHECK: omp.target_update_data device(%[[DEVICE]] : i32) motion_entries + !$omp target update from(a) device(1) +end subroutine omp_target_update_device + +!=============================================================================== +! Target_Update `nowait` clause +!=============================================================================== + +!CHECK-LABEL: func.func @_QPomp_target_update_nowait() { +subroutine omp_target_update_nowait + integer :: a(1024) + logical :: i + + !CHECK-DAG: %[[A_DECL:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) + !CHECK-DAG: %[[BOUNDS:.*]] = omp.bounds + + !CHECK: omp.target_update_data nowait motion_entries + !$omp target update from(a) nowait +end subroutine omp_target_update_nowait + !=============================================================================== ! Target_Data with region !===============================================================================