[flang-commits] [flang] [mlir] [flang][MLIR][OpenMP] Emit `UpdateDataOp` from `!$omp target update` (PR #75345)
Kareem Ergawy via flang-commits
flang-commits at lists.llvm.org
Sun Dec 17 03:12:44 PST 2023
https://github.com/ergawy updated https://github.com/llvm/llvm-project/pull/75345
>From b2161310c18eee5821f1e450482fd0270f20deff Mon Sep 17 00:00:00 2001
From: ergawy <kareem.ergawy at amd.com>
Date: Tue, 12 Dec 2023 01:07:40 -0600
Subject: [PATCH 1/2] [MLIR][OpenMP][Offload] Lower `target update` op to
DeviceRT
Adds support for lowring `UpdateDataOp` to the DeviceRT. This reuses the
existing utils used by other device directive.
---
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 24 ++++++++++--
mlir/test/Target/LLVMIR/omptarget-llvm.mlir | 38 +++++++++++++++++++
2 files changed, 59 insertions(+), 3 deletions(-)
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 4f6200d29a70a6..088e7ae4231bef 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -1915,6 +1915,23 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder,
mapOperands = exitDataOp.getMapOperands();
return success();
})
+ .Case([&](omp::UpdateDataOp updateDataOp) {
+ if (updateDataOp.getNowait())
+ return failure();
+
+ if (auto ifExprVar = updateDataOp.getIfExpr())
+ ifCond = moduleTranslation.lookupValue(ifExprVar);
+
+ if (auto devId = updateDataOp.getDevice())
+ if (auto constOp =
+ dyn_cast<LLVM::ConstantOp>(devId.getDefiningOp()))
+ if (auto intAttr = dyn_cast<IntegerAttr>(constOp.getValue()))
+ deviceID = intAttr.getInt();
+
+ RTLFn = llvm::omp::OMPRTL___tgt_target_data_update_mapper;
+ mapOperands = updateDataOp.getMotionOperands();
+ return success();
+ })
.Default([&](Operation *op) {
return op->emitError("unsupported OpenMP operation: ")
<< op->getName();
@@ -2748,9 +2765,10 @@ LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
.Case([&](omp::ThreadprivateOp) {
return convertOmpThreadprivate(*op, builder, moduleTranslation);
})
- .Case<omp::DataOp, omp::EnterDataOp, omp::ExitDataOp>([&](auto op) {
- return convertOmpTargetData(op, builder, moduleTranslation);
- })
+ .Case<omp::DataOp, omp::EnterDataOp, omp::ExitDataOp, omp::UpdateDataOp>(
+ [&](auto op) {
+ return convertOmpTargetData(op, builder, moduleTranslation);
+ })
.Case([&](omp::TargetOp) {
return convertOmpTarget(*op, builder, moduleTranslation);
})
diff --git a/mlir/test/Target/LLVMIR/omptarget-llvm.mlir b/mlir/test/Target/LLVMIR/omptarget-llvm.mlir
index 9221b410d766ed..b089d47f795df3 100644
--- a/mlir/test/Target/LLVMIR/omptarget-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-llvm.mlir
@@ -441,3 +441,41 @@ llvm.func @_QPopenmp_target_use_dev_both() {
// CHECK: ret void
// -----
+
+llvm.func @_QPopenmp_target_data_update() {
+ %0 = llvm.mlir.constant(1 : i64) : i64
+ %1 = llvm.alloca %0 x i32 {bindc_name = "i", in_type = i32, operand_segment_sizes = array<i32: 0, 0>, uniq_name = "_QFopenmp_target_dataEi"} : (i64) -> !llvm.ptr
+ %2 = omp.map_info var_ptr(%1 : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.target_data map_entries(%2 : !llvm.ptr) {
+ %3 = llvm.mlir.constant(99 : i32) : i32
+ llvm.store %3, %1 : i32, !llvm.ptr
+ omp.terminator
+ }
+
+ omp.target_update_data motion_entries(%2 : !llvm.ptr)
+
+ llvm.return
+}
+
+// CHECK-LABEL: define void @_QPopenmp_target_data_update
+
+// CHECK-DAG: %[[OFFLOAD_BASEPTRS:.*]] = alloca [1 x ptr], align 8
+// CHECK-DAG: %[[OFFLOAD_PTRS:.*]] = alloca [1 x ptr], align 8
+// CHECK-DAG: %[[INT_ALLOCA:.*]] = alloca i32, i64 1, align 4
+// CHECK-DAG: %[[OFFLOAD_MAPPERS:.*]] = alloca [1 x ptr], align 8
+
+// CHECK: call void @__tgt_target_data_begin_mapper
+// CHECK: store i32 99, ptr %[[INT_ALLOCA]], align 4
+// CHECK: call void @__tgt_target_data_end_mapper
+
+// CHECK: %[[BASEPTRS_VAL:.*]] = getelementptr inbounds [1 x ptr], ptr %[[OFFLOAD_BASEPTRS]], i32 0, i32 0
+// CHECK: store ptr %[[INT_ALLOCA]], ptr %[[BASEPTRS_VAL]], align 8
+// CHECK: %[[PTRS_VAL:.*]] = getelementptr inbounds [1 x ptr], ptr %[[OFFLOAD_PTRS]], i32 0, i32 0
+// CHECK: store ptr %[[INT_ALLOCA]], ptr %[[PTRS_VAL]], align 8
+// CHECK: %[[MAPPERS_VAL:.*]] = getelementptr inbounds [1 x ptr], ptr %[[OFFLOAD_MAPPERS]], i64 0, i64 0
+// CHECK: store ptr null, ptr %[[MAPPERS_VAL]], align 8
+// CHECK: %[[BASEPTRS_VAL_2:.*]] = getelementptr inbounds [1 x ptr], ptr %[[OFFLOAD_BASEPTRS]], i32 0, i32 0
+// CHECK: %[[PTRS_VAL_2:.*]] = getelementptr inbounds [1 x ptr], ptr %[[OFFLOAD_PTRS]], i32 0, i32 0
+// CHECK: call void @__tgt_target_data_update_mapper(ptr @2, i64 -1, i32 1, ptr %[[BASEPTRS_VAL_2]], ptr %[[PTRS_VAL_2]], ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr null)
+
+// CHECK: ret void
>From 9202c0686d82f6324f35b92f305063abc8121a6d Mon Sep 17 00:00:00 2001
From: ergawy <kareem.ergawy at amd.com>
Date: Wed, 13 Dec 2023 05:09:08 -0600
Subject: [PATCH 2/2] [flang][MLIR][OpenMP] Emit `UpdateDataOp` from `!$omp
target update`
Emits MLIR op corresponding to `!$omp target update` directive. So far,
only motion types: `to` and `from` are supported. Motion modifiers:
`present`, `mapper`, and `iterator` are not supported yet.
---
flang/lib/Lower/OpenMP.cpp | 103 ++++++++++++++++++++++++++++-
flang/test/Lower/OpenMP/target.f90 | 88 ++++++++++++++++++++++++
2 files changed, 190 insertions(+), 1 deletion(-)
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index 9213cff95d3f11..281097eb61406c 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -606,6 +606,16 @@ class ClauseProcessor {
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&useDeviceSymbols) const;
+ bool
+ processToMotionClauses(Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::StatementContext &stmtCtx,
+ llvm::SmallVectorImpl<mlir::Value> &mapOperands);
+
+ bool processFromMotionClauses(
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::StatementContext &stmtCtx,
+ llvm::SmallVectorImpl<mlir::Value> &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.
@@ -672,6 +682,12 @@ class ClauseProcessor {
return false;
}
+ template <typename T>
+ bool
+ processMotionClauses(Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::StatementContext &stmtCtx,
+ llvm::SmallVectorImpl<mlir::Value> &mapOperands);
+
Fortran::lower::AbstractConverter &converter;
const Fortran::parser::OmpClauseList &clauses;
};
@@ -1892,6 +1908,62 @@ bool ClauseProcessor::processUseDevicePtr(
});
}
+bool ClauseProcessor::processToMotionClauses(
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::StatementContext &stmtCtx,
+ llvm::SmallVectorImpl<mlir::Value> &mapOperands) {
+ return processMotionClauses<ClauseProcessor::ClauseTy::To>(
+ semanticsContext, stmtCtx, mapOperands);
+}
+
+bool ClauseProcessor::processFromMotionClauses(
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::StatementContext &stmtCtx,
+ llvm::SmallVectorImpl<mlir::Value> &mapOperands) {
+ return processMotionClauses<ClauseProcessor::ClauseTy::From>(
+ semanticsContext, stmtCtx, mapOperands);
+}
+
+template <typename T>
+bool ClauseProcessor::processMotionClauses(
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::StatementContext &stmtCtx,
+ llvm::SmallVectorImpl<mlir::Value> &mapOperands) {
+ return findRepeatableClause<T>([&](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<T, ClauseProcessor::ClauseTy::To> ||
+ std::is_same_v<T, ClauseProcessor::ClauseTy::From>);
+
+ // TODO Support motion modifiers: present, mapper, iterator.
+ constexpr llvm::omp::OpenMPOffloadMappingFlags mapTypeBits =
+ std::is_same_v<T, ClauseProcessor::ClauseTy::To>
+ ? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO
+ : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
+
+ for (const Fortran::parser::OmpObject &ompObject : motionClause->v.v) {
+ llvm::SmallVector<mlir::Value> bounds;
+ std::stringstream asFortran;
+ mlir::Value baseAddr = 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, baseAddr, asFortran, bounds,
+ static_cast<
+ std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
+ mapTypeBits),
+ mlir::omp::VariableCaptureKind::ByRef, baseAddr.getType());
+
+ mapOperands.push_back(mapOp);
+ }
+ });
+}
+
template <typename... Ts>
void ClauseProcessor::processTODO(mlir::Location currentLocation,
llvm::omp::Directive directive) const {
@@ -2453,6 +2525,34 @@ genEnterExitDataOp(Fortran::lower::AbstractConverter &converter,
deviceOperand, nowaitAttr, mapOperands);
}
+mlir::omp::UpdateDataOp
+genUpdateDataOp(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;
+ mlir::UnitAttr nowaitAttr;
+ llvm::SmallVector<mlir::Value> motionOperands;
+ llvm::SmallVector<mlir::Value> mapOperands;
+
+ ClauseProcessor cp(converter, clauseList);
+ cp.processIf(
+ Fortran::parser::OmpIfClause::DirectiveNameModifier::TargetUpdate,
+ ifClauseOperand);
+ cp.processDevice(stmtCtx, deviceOperand);
+ cp.processNowait(nowaitAttr);
+ cp.processToMotionClauses(semanticsContext, stmtCtx, mapOperands);
+ cp.processFromMotionClauses(semanticsContext, stmtCtx, mapOperands);
+
+ cp.processTODO<Fortran::parser::OmpClause::Depend>(
+ currentLocation, llvm::omp::Directive::OMPD_target_update);
+
+ return firOpBuilder.create<mlir::omp::UpdateDataOp>(
+ currentLocation, ifClauseOperand, deviceOperand, nowaitAttr, mapOperands);
+}
+
// This functions creates a block for the body of the targetOp's region. It adds
// all the symbols present in mapSymbols as block arguments to this block.
static void genBodyOfTargetOp(
@@ -2856,7 +2956,8 @@ genOmpSimpleStandalone(Fortran::lower::AbstractConverter &converter,
currentLocation, opClauseList);
break;
case llvm::omp::Directive::OMPD_target_update:
- TODO(currentLocation, "OMPD_target_update");
+ genUpdateDataOp(converter, semanticsContext, currentLocation, opClauseList);
+ break;
case llvm::omp::Directive::OMPD_ordered:
TODO(currentLocation, "OMPD_ordered");
}
diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90
index 26b4d595d52291..5500097ee58a9d 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>>, !fir.array<1024xi32>)
+ !CHECK-SAME: map_clauses(to) capture(ByRef)
+ !CHECK-SAME: bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
+
+ !CHECK: omp.target_update_data motion_entries(%[[TO_MAP]] : !fir.ref<!fir.array<1024xi32>>)
+ !$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: %[[TO_MAP:.*]] = omp.map_info var_ptr(%[[A_DECL]]#1 : !fir.ref<!fir.array<1024xi32>>, !fir.array<1024xi32>)
+ !CHECK-SAME: map_clauses(from) capture(ByRef)
+ !CHECK-SAME: bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<1024xi32>> {name = "a"}
+
+ !CHECK: omp.target_update_data motion_entries(%[[TO_MAP]] : !fir.ref<!fir.array<1024xi32>>)
+ !$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
!===============================================================================
More information about the flang-commits
mailing list