[flang-commits] [flang] a1b86bd - [Flang][OpenMP] Optimize target updates of derived-type scalars (#219488)
via flang-commits
flang-commits at lists.llvm.org
Fri Sep 4 08:51:10 PDT 2026
Author: Akash Banerjee
Date: 2026-09-04T16:51:05+01:00
New Revision: a1b86bdaef6b0b0e0d6b4dbb3354fa024de2f1b2
URL: https://github.com/llvm/llvm-project/commit/a1b86bdaef6b0b0e0d6b4dbb3354fa024de2f1b2
DIFF: https://github.com/llvm/llvm-project/commit/a1b86bdaef6b0b0e0d6b4dbb3354fa024de2f1b2.diff
LOG: [Flang][OpenMP] Optimize target updates of derived-type scalars (#219488)
Pack AMDGPU derived-type scalar updates into a single transfer and
generated target region, avoiding one costly runtime transfer per
component. Preserve existing lowering for unsupported clauses, pointer
components, and non-AMDGPU targets.
Added:
flang/test/Lower/OpenMP/target-update-derived-type-usm.f90
flang/test/Lower/OpenMP/target-update-derived-type.f90
Modified:
flang/lib/Lower/OpenMP/OpenMP.cpp
flang/lib/Lower/OpenMP/Utils.cpp
flang/lib/Lower/OpenMP/Utils.h
Removed:
################################################################################
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index becb05b5af2c2..870955b189245 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -4358,6 +4358,168 @@ static mlir::omp::TargetDataOp genTargetDataOp(
return targetDataOp;
}
+struct TargetUpdateKernelEntry {
+ mlir::omp::MapInfoOp mapInfo;
+ mlir::Value hostPtr;
+ mlir::Type componentType;
+};
+
+static std::optional<TargetUpdateKernelEntry>
+getTargetUpdateKernelEntry(mlir::Value mapVar) {
+ auto mapInfo = mapVar.getDefiningOp<mlir::omp::MapInfoOp>();
+ if (!mapInfo)
+ return std::nullopt;
+
+ // Keep the fast path to plain synchronous H2D motion. In particular, do not
+ // silently weaken `present` motion modifiers.
+ if (mapInfo.getMapType() != mlir::omp::ClauseMapFlags::to ||
+ mapInfo.getVarPtrPtr() || !mapInfo.getMembers().empty() ||
+ !mapInfo.getBounds().empty() || mapInfo.getMapperId())
+ return std::nullopt;
+
+ mlir::Value hostPtr = mapInfo.getVarPtr();
+ auto designate = hostPtr.getDefiningOp<hlfir::DesignateOp>();
+ if (!designate || !designate.getComponent() ||
+ designate.getComponentShape() || !designate.getIndices().empty() ||
+ !designate.getSubstring().empty() || designate.getComplexPart() ||
+ designate.getShape() || !designate.getTypeparams().empty())
+ return std::nullopt;
+
+ mlir::Type baseType = fir::unwrapRefType(designate.getMemref().getType());
+ auto recordType = mlir::dyn_cast<fir::RecordType>(baseType);
+ if (!recordType || recordType.getNumLenParams() != 0)
+ return std::nullopt;
+
+ llvm::StringRef component = designate.getComponent()->getValue();
+ mlir::Type componentType = recordType.getType(component);
+ if (!componentType || !fir::isa_trivial(componentType))
+ return std::nullopt;
+
+ return TargetUpdateKernelEntry{mapInfo, hostPtr, componentType};
+}
+
+/// Replace several scalar H2D updates with one packed transfer and a target
+/// region that scatters the values to their original device addresses. The
+/// source tuple has one `to` map, while each destination uses a `storage` map
+/// so it resolves an existing device association without copying host data.
+static mlir::omp::TargetOp
+genTargetUpdateKernel(lower::AbstractConverter &converter, mlir::Location loc,
+ llvm::ArrayRef<TargetUpdateKernelEntry> entries) {
+ fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+ mlir::omp::TargetExtOperands targetClauseOps;
+ targetClauseOps.kernelType = mlir::omp::TargetExecModeAttr::get(
+ builder.getContext(), mlir::omp::TargetExecMode::generic);
+
+ llvm::SmallVector<mlir::Value> destinationMaps;
+ destinationMaps.reserve(entries.size());
+
+ llvm::SmallVector<mlir::Type> sourceTypes;
+ llvm::transform(
+ entries, std::back_inserter(sourceTypes),
+ [](const TargetUpdateKernelEntry &entry) { return entry.componentType; });
+ mlir::TupleType sourceType =
+ mlir::TupleType::get(builder.getContext(), sourceTypes);
+ mlir::Value sourcePack = builder.createTemporary(loc, sourceType);
+
+ for (auto [i, entry] : llvm::enumerate(entries)) {
+ mlir::Value sourceValue = fir::LoadOp::create(builder, loc, entry.hostPtr);
+ mlir::Value index =
+ builder.createIntegerConstant(loc, builder.getI32Type(), i);
+ mlir::Value sourceAddr = fir::CoordinateOp::create(
+ builder, loc, builder.getRefType(entry.componentType), sourcePack,
+ index);
+ fir::StoreOp::create(builder, loc, sourceValue, sourceAddr);
+
+ mlir::Value destinationMap = createMapInfoOp(
+ builder, loc, entry.hostPtr, /*varPtrPtr=*/mlir::Value{},
+ /*name=*/"", /*bounds=*/{}, /*members=*/{},
+ /*membersIndex=*/mlir::ArrayAttr{}, mlir::omp::ClauseMapFlags::storage,
+ mlir::omp::VariableCaptureKind::ByRef, entry.hostPtr.getType());
+ destinationMaps.push_back(destinationMap);
+ }
+
+ mlir::Value sourceMap = createMapInfoOp(
+ builder, loc, sourcePack, /*varPtrPtr=*/mlir::Value{},
+ ".omp.target.update.source", /*bounds=*/{}, /*members=*/{},
+ /*membersIndex=*/mlir::ArrayAttr{}, mlir::omp::ClauseMapFlags::to,
+ mlir::omp::VariableCaptureKind::ByRef, sourcePack.getType());
+ targetClauseOps.mapVars.push_back(sourceMap);
+ targetClauseOps.mapVars.append(destinationMaps);
+
+ auto targetOp = mlir::omp::TargetOp::create(builder, loc, targetClauseOps);
+ llvm::SmallVector<mlir::Value> mapBaseValues;
+ extractMappedBaseValues(targetClauseOps.mapVars, mapBaseValues);
+ ObjectEntryBlockArgs args;
+ args.map.vars = mapBaseValues;
+ genEntryBlock(builder, args.asEntryBlockArgs(), targetOp.getRegion());
+
+ auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*targetOp);
+ llvm::ArrayRef<mlir::BlockArgument> mapBlockArgs = argIface.getMapBlockArgs();
+ assert(mapBlockArgs.size() == entries.size() + 1 &&
+ "expected source and destination map arguments");
+ builder.setInsertionPointToEnd(&targetOp.getRegion().front());
+ for (auto [i, entry] : llvm::enumerate(entries)) {
+ mlir::Value index =
+ builder.createIntegerConstant(loc, builder.getI32Type(), i);
+ mlir::Value sourceAddr = fir::CoordinateOp::create(
+ builder, loc, builder.getRefType(entry.componentType),
+ mapBlockArgs.front(), index);
+ mlir::Value sourceValue = fir::LoadOp::create(builder, loc, sourceAddr);
+ fir::StoreOp::create(builder, loc, sourceValue, mapBlockArgs[i + 1]);
+ }
+ mlir::omp::TerminatorOp::create(builder, loc);
+ builder.setInsertionPointAfter(targetOp);
+ return targetOp;
+}
+
+static mlir::Operation *tryGenTargetUpdateKernel(
+ lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
+ mlir::Location loc,
+ mlir::omp::TargetEnterExitUpdateDataOperands &clauseOps) {
+ // Updating several small, discontiguous fields issues one device transfer
+ // for every map entry. Pack their host values and use one target region so
+ // that the runtime performs one H2D transfer followed by the scalar stores.
+ // This addresses the AMDGPU runtime transfer cost and is only enabled when
+ // an AMDGPU image will actually be emitted.
+ mlir::ModuleOp module = converter.getModuleOp();
+ if (!hasOnlyAMDGCNTargets(module) ||
+ requiresUnifiedSharedMemory(module, semaCtx) ||
+ clauseOps.mapVars.size() < 2 || !clauseOps.dependVars.empty() ||
+ !clauseOps.dependIterated.empty() || !clauseOps.mapIterated.empty() ||
+ clauseOps.nowait || clauseOps.device)
+ return nullptr;
+
+ llvm::SmallVector<TargetUpdateKernelEntry> entries;
+ entries.reserve(clauseOps.mapVars.size());
+ for (mlir::Value mapVar : clauseOps.mapVars) {
+ std::optional<TargetUpdateKernelEntry> entry =
+ getTargetUpdateKernelEntry(mapVar);
+ if (!entry)
+ return nullptr;
+ entries.push_back(*entry);
+ }
+
+ fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+ mlir::Operation *firstGenerated = nullptr;
+
+ if (mlir::Value ifExpr = clauseOps.ifExpr) {
+ auto ifOp = fir::IfOp::create(builder, loc, ifExpr,
+ /*withElseRegion=*/false);
+ firstGenerated = ifOp;
+ builder.setInsertionPoint(ifOp.getThenRegion().front().getTerminator());
+ genTargetUpdateKernel(converter, loc, entries);
+ builder.setInsertionPointAfter(ifOp);
+ } else {
+ firstGenerated = genTargetUpdateKernel(converter, loc, entries);
+ }
+
+ for (TargetUpdateKernelEntry &entry : entries)
+ if (entry.mapInfo->use_empty())
+ entry.mapInfo.erase();
+
+ return firstGenerated;
+}
+
template <typename OpTy>
static OpTy genTargetEnterExitUpdateDataOp(
lower::AbstractConverter &converter, lower::SymMap &symTable,
@@ -4385,6 +4547,25 @@ static OpTy genTargetEnterExitUpdateDataOp(
return OpTy::create(firOpBuilder, loc, clauseOps);
}
+static mlir::Operation *
+genTargetUpdateDataOp(lower::AbstractConverter &converter,
+ lower::SymMap &symTable, lower::StatementContext &stmtCtx,
+ semantics::SemanticsContext &semaCtx, mlir::Location loc,
+ const ConstructQueue &queue,
+ ConstructQueue::const_iterator item) {
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+ mlir::omp::TargetEnterExitUpdateDataOperands clauseOps;
+ genTargetEnterExitUpdateDataClauses(
+ converter, semaCtx, symTable, stmtCtx, item->clauses, loc,
+ llvm::omp::Directive::OMPD_target_update, clauseOps);
+
+ if (mlir::Operation *op =
+ tryGenTargetUpdateKernel(converter, semaCtx, loc, clauseOps))
+ return op;
+
+ return mlir::omp::TargetUpdateOp::create(firOpBuilder, loc, clauseOps);
+}
+
static mlir::omp::TaskOp
genTaskOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
lower::StatementContext &stmtCtx,
@@ -5569,8 +5750,8 @@ genOMPDispatch(lower::AbstractConverter &converter, lower::SymMap &symTable,
converter, symTable, stmtCtx, semaCtx, loc, queue, item);
break;
case llvm::omp::Directive::OMPD_target_update:
- newOp = genTargetEnterExitUpdateDataOp<mlir::omp::TargetUpdateOp>(
- converter, symTable, stmtCtx, semaCtx, loc, queue, item);
+ newOp = genTargetUpdateDataOp(converter, symTable, stmtCtx, semaCtx, loc,
+ queue, item);
break;
case llvm::omp::Directive::OMPD_task:
newOp = genTaskOp(converter, symTable, stmtCtx, semaCtx, eval, loc, queue,
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index e3d8d658b39a1..4244662ad4290 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -42,6 +42,7 @@
#include <llvm/ADT/SmallPtrSet.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/CommandLine.h>
+#include <llvm/TargetParser/Triple.h>
#include <functional>
#include <iterator>
@@ -1377,6 +1378,48 @@ static llvm::Triple getOffloadTargetTriple(mlir::ModuleOp module) {
return llvm::Triple();
}
+bool hasOnlyAMDGCNTargets(mlir::ModuleOp module) {
+ auto offloadModule =
+ llvm::cast<mlir::omp::OffloadModuleInterface>(module.getOperation());
+ if (offloadModule.getIsTargetDevice())
+ return fir::getTargetTriple(module).isAMDGCN();
+ llvm::ArrayRef<mlir::Attribute> targetTriples =
+ offloadModule.getTargetTriples();
+ return !targetTriples.empty() &&
+ llvm::all_of(targetTriples, [](mlir::Attribute attr) {
+ auto tripleAttr = llvm::dyn_cast<mlir::StringAttr>(attr);
+ return tripleAttr && llvm::Triple(tripleAttr.getValue()).isAMDGCN();
+ });
+}
+
+static bool scopeRequiresUnifiedSharedMemory(const semantics::Scope &scope) {
+ if (const semantics::Symbol *symbol = scope.symbol()) {
+ bool requiresUSM = common::visit(
+ [](const auto &details) {
+ using Details = std::decay_t<decltype(details)>;
+ if constexpr (std::is_base_of_v<semantics::WithOmpDeclarative,
+ Details>)
+ return details.ompRequires().test(
+ llvm::omp::Clause::OMPC_unified_shared_memory);
+ return false;
+ },
+ symbol->details());
+ if (requiresUSM)
+ return true;
+ }
+
+ return llvm::any_of(scope.children(), scopeRequiresUnifiedSharedMemory);
+}
+
+bool requiresUnifiedSharedMemory(mlir::ModuleOp module,
+ semantics::SemanticsContext &semaCtx) {
+ auto offloadModule = llvm::cast<mlir::omp::OffloadModuleInterface>(*module);
+ return mlir::omp::bitEnumContainsAny(
+ offloadModule.getRequires(),
+ mlir::omp::ClauseRequires::unified_shared_memory) ||
+ scopeRequiresUnifiedSharedMemory(semaCtx.globalScope());
+}
+
semantics::omp::OmpVariantMatchContext makeVariantMatchContext(
mlir::ModuleOp module,
llvm::ArrayRef<llvm::omp::TraitProperty> constructTraits) {
diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index 256e928eb0f6c..7fde1825b006a 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -29,6 +29,7 @@ class RecordType;
namespace Fortran {
namespace semantics {
+class SemanticsContext;
class Symbol;
namespace omp {
class OmpVariantMatchContext;
@@ -269,6 +270,15 @@ void collectEnclosingConstructTraits(
mlir::Operation *op,
llvm::SmallVectorImpl<llvm::omp::TraitProperty> &constructTraits);
+/// Return true when \p module is being compiled for an AMDGPU device or all of
+/// its offload targets are AMDGPU devices.
+bool hasOnlyAMDGCNTargets(mlir::ModuleOp module);
+
+/// Return true when unified shared memory is required by either the OpenMP
+/// module attributes or a source-level `requires` directive.
+bool requiresUnifiedSharedMemory(mlir::ModuleOp module,
+ semantics::SemanticsContext &semaCtx);
+
/// Build the OpenMP variant-matching context for \p module. The device flag,
/// host triple, offload triple, and target features are read from the module;
/// \p constructTraits seeds the enclosing-construct traits.
diff --git a/flang/test/Lower/OpenMP/target-update-derived-type-usm.f90 b/flang/test/Lower/OpenMP/target-update-derived-type-usm.f90
new file mode 100644
index 0000000000000..7271a10a3ad64
--- /dev/null
+++ b/flang/test/Lower/OpenMP/target-update-derived-type-usm.f90
@@ -0,0 +1,27 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa %s -o - | FileCheck %s
+
+! Verify that unified shared memory keeps the regular target update because a
+! packed transfer and target region would add overhead to directly accessible
+! storage.
+
+module target_update_derived_type_usm
+ !$omp requires unified_shared_memory
+ type :: aggregate
+ real(8) :: first
+ real(8) :: gap
+ integer :: last
+ end type
+contains
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_type_usmPupdate(
+subroutine update(value)
+ type(aggregate) :: value
+
+ ! CHECK: %[[FIRST_MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
+ ! CHECK: %[[LAST_MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
+ ! CHECK-NOT: omp.target kernel_type(generic)
+ ! CHECK: omp.target_update map_entries(%[[FIRST_MAP]], %[[LAST_MAP]]
+ !$omp target update to(value%first, value%last)
+end subroutine
+
+end module
diff --git a/flang/test/Lower/OpenMP/target-update-derived-type.f90 b/flang/test/Lower/OpenMP/target-update-derived-type.f90
new file mode 100644
index 0000000000000..cdf81aa477330
--- /dev/null
+++ b/flang/test/Lower/OpenMP/target-update-derived-type.f90
@@ -0,0 +1,174 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s --check-prefix=HOST
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-targets=nvptx64-nvidia-cuda %s -o - | FileCheck %s --check-prefix=NONAMD
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda %s -o - | FileCheck %s --check-prefix=MIXED
+! RUN: %flang_fc1 -triple amdgcn-amd-amdhsa -emit-hlfir -fopenmp -fopenmp-is-target-device %s -o - | FileCheck %s --check-prefix=DEVICE
+
+module target_update_derived_type
+ type :: wavefun
+ real(8) :: ferwe
+ real(8) :: aux
+ complex(8) :: celen
+ integer :: pad1
+ integer :: nb
+ integer :: pad2
+ integer :: isp
+ integer :: pad3
+ logical :: ldo
+ integer, pointer :: ptr
+ end type
+contains
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_typePupdate_with_if(
+! DEVICE-LABEL: func.func @_QMtarget_update_derived_typePupdate_with_if(
+! DEVICE: omp.target kernel_type(generic)
+! DEVICE-NOT: omp.target_update
+! HOST-LABEL: func.func @_QMtarget_update_derived_typePupdate_with_if(
+! HOST-NOT: omp.target kernel_type(generic)
+! HOST: omp.target_update
+! HOST-NOT: omp.target kernel_type(generic)
+! HOST-LABEL: func.func @_QMtarget_update_derived_typePupdate_without_if(
+! NONAMD-LABEL: func.func @_QMtarget_update_derived_typePupdate_with_if(
+! NONAMD-NOT: omp.target kernel_type(generic)
+! NONAMD: omp.target_update
+! NONAMD-NOT: omp.target kernel_type(generic)
+! NONAMD-LABEL: func.func @_QMtarget_update_derived_typePupdate_without_if(
+! MIXED-LABEL: func.func @_QMtarget_update_derived_typePupdate_with_if(
+! MIXED-NOT: omp.target kernel_type(generic)
+! MIXED: omp.target_update
+! MIXED-NOT: omp.target kernel_type(generic)
+! MIXED-LABEL: func.func @_QMtarget_update_derived_typePupdate_without_if(
+subroutine update_with_if(w, enabled)
+ type(wavefun) :: w
+ logical :: enabled
+
+ ! CHECK: %[[SOURCE:.*]] = fir.alloca tuple<f64, complex<f64>, i32, i32, !fir.logical<4>>
+ ! CHECK: %[[COND:.*]] = fir.convert %{{.*}} : (!fir.logical<4>) -> i1
+ ! CHECK: %[[FERWE:.*]] = hlfir.designate %{{.*}}{"ferwe"}
+ ! CHECK: %[[CELEN:.*]] = hlfir.designate %{{.*}}{"celen"}
+ ! CHECK: %[[NB:.*]] = hlfir.designate %{{.*}}{"nb"}
+ ! CHECK: %[[ISP:.*]] = hlfir.designate %{{.*}}{"isp"}
+ ! CHECK: %[[LDO:.*]] = hlfir.designate %{{.*}}{"ldo"}
+ ! CHECK: fir.if %[[COND]] {
+ ! CHECK: %[[FERWE_HOST:.*]] = fir.load %[[FERWE]] : !fir.ref<f64>
+ ! CHECK: %[[PACK0:.*]] = fir.coordinate_of %[[SOURCE]], {{.*}} -> !fir.ref<f64>
+ ! CHECK: fir.store %[[FERWE_HOST]] to %[[PACK0]] : !fir.ref<f64>
+ ! CHECK: %[[FERWE_MAP:.*]] = omp.map.info var_ptr(%[[FERWE]] : !fir.ref<f64>, f64) map_clauses(storage) capture(ByRef)
+ ! CHECK: %[[CELEN_HOST:.*]] = fir.load %[[CELEN]] : !fir.ref<complex<f64>>
+ ! CHECK: %[[PACK1:.*]] = fir.coordinate_of %[[SOURCE]], {{.*}} -> !fir.ref<complex<f64>>
+ ! CHECK: fir.store %[[CELEN_HOST]] to %[[PACK1]] : !fir.ref<complex<f64>>
+ ! CHECK: %[[CELEN_MAP:.*]] = omp.map.info var_ptr(%[[CELEN]] : !fir.ref<complex<f64>>, complex<f64>) map_clauses(storage) capture(ByRef)
+ ! CHECK: %[[NB_HOST:.*]] = fir.load %[[NB]] : !fir.ref<i32>
+ ! CHECK: %[[PACK2:.*]] = fir.coordinate_of %[[SOURCE]], {{.*}} -> !fir.ref<i32>
+ ! CHECK: fir.store %[[NB_HOST]] to %[[PACK2]] : !fir.ref<i32>
+ ! CHECK: %[[NB_MAP:.*]] = omp.map.info var_ptr(%[[NB]] : !fir.ref<i32>, i32) map_clauses(storage) capture(ByRef)
+ ! CHECK: %[[ISP_HOST:.*]] = fir.load %[[ISP]] : !fir.ref<i32>
+ ! CHECK: %[[PACK3:.*]] = fir.coordinate_of %[[SOURCE]], {{.*}} -> !fir.ref<i32>
+ ! CHECK: fir.store %[[ISP_HOST]] to %[[PACK3]] : !fir.ref<i32>
+ ! CHECK: %[[ISP_MAP:.*]] = omp.map.info var_ptr(%[[ISP]] : !fir.ref<i32>, i32) map_clauses(storage) capture(ByRef)
+ ! CHECK: %[[LDO_HOST:.*]] = fir.load %[[LDO]] : !fir.ref<!fir.logical<4>>
+ ! CHECK: %[[PACK4:.*]] = fir.coordinate_of %[[SOURCE]], {{.*}} -> !fir.ref<!fir.logical<4>>
+ ! CHECK: fir.store %[[LDO_HOST]] to %[[PACK4]] : !fir.ref<!fir.logical<4>>
+ ! CHECK: %[[LDO_MAP:.*]] = omp.map.info var_ptr(%[[LDO]] : !fir.ref<!fir.logical<4>>, !fir.logical<4>) map_clauses(storage) capture(ByRef)
+ ! CHECK: %[[SOURCE_MAP:.*]] = omp.map.info var_ptr(%[[SOURCE]] {{.*}}) map_clauses(to) capture(ByRef) name(".omp.target.update.source")
+ ! CHECK: omp.target kernel_type(generic) map_entries(%[[SOURCE_MAP]] -> [[SOURCE_ARG:%[^, ]+]], %[[FERWE_MAP]] -> [[FERWE_ARG:%[^, ]+]], %[[CELEN_MAP]] -> [[CELEN_ARG:%[^, ]+]], %[[NB_MAP]] -> [[NB_ARG:%[^, ]+]], %[[ISP_MAP]] -> [[ISP_ARG:%[^, ]+]], %[[LDO_MAP]] -> [[LDO_ARG:%[^, ]+]]
+ ! CHECK: %[[FERWE_SOURCE:.*]] = fir.coordinate_of [[SOURCE_ARG]], {{.*}} -> !fir.ref<f64>
+ ! CHECK: %[[FERWE_VALUE:.*]] = fir.load %[[FERWE_SOURCE]] : !fir.ref<f64>
+ ! CHECK: fir.store %[[FERWE_VALUE]] to [[FERWE_ARG]] : !fir.ref<f64>
+ ! CHECK: %[[CELEN_SOURCE:.*]] = fir.coordinate_of [[SOURCE_ARG]], {{.*}} -> !fir.ref<complex<f64>>
+ ! CHECK: %[[CELEN_VALUE:.*]] = fir.load %[[CELEN_SOURCE]] : !fir.ref<complex<f64>>
+ ! CHECK: fir.store %[[CELEN_VALUE]] to [[CELEN_ARG]] : !fir.ref<complex<f64>>
+ ! CHECK: %[[NB_SOURCE:.*]] = fir.coordinate_of [[SOURCE_ARG]], {{.*}} -> !fir.ref<i32>
+ ! CHECK: %[[NB_VALUE:.*]] = fir.load %[[NB_SOURCE]] : !fir.ref<i32>
+ ! CHECK: fir.store %[[NB_VALUE]] to [[NB_ARG]] : !fir.ref<i32>
+ ! CHECK: %[[ISP_SOURCE:.*]] = fir.coordinate_of [[SOURCE_ARG]], {{.*}} -> !fir.ref<i32>
+ ! CHECK: %[[ISP_VALUE:.*]] = fir.load %[[ISP_SOURCE]] : !fir.ref<i32>
+ ! CHECK: fir.store %[[ISP_VALUE]] to [[ISP_ARG]] : !fir.ref<i32>
+ ! CHECK: %[[LDO_SOURCE:.*]] = fir.coordinate_of [[SOURCE_ARG]], {{.*}} -> !fir.ref<!fir.logical<4>>
+ ! CHECK: %[[LDO_VALUE:.*]] = fir.load %[[LDO_SOURCE]] : !fir.ref<!fir.logical<4>>
+ ! CHECK: fir.store %[[LDO_VALUE]] to [[LDO_ARG]] : !fir.ref<!fir.logical<4>>
+ ! CHECK-NEXT: omp.terminator
+ ! CHECK-NOT: omp.target_update
+ ! CHECK: return
+ !$omp target update to(w%ferwe, w%celen, w%nb, w%isp, w%ldo) if(enabled)
+end subroutine
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_typePupdate_without_if(
+! DEVICE-LABEL: func.func @_QMtarget_update_derived_typePupdate_without_if(
+subroutine update_without_if(w)
+ type(wavefun) :: w
+
+ ! CHECK: %[[SOURCE:.*]] = fir.alloca tuple<complex<f64>, i32, i32, !fir.logical<4>>
+ ! CHECK: %[[CELEN:.*]] = hlfir.designate %{{.*}}{"celen"}
+ ! CHECK: %[[CELEN_MAP:.*]] = omp.map.info var_ptr(%[[CELEN]] : !fir.ref<complex<f64>>, complex<f64>) map_clauses(storage) capture(ByRef)
+ ! CHECK: %[[SOURCE_MAP:.*]] = omp.map.info var_ptr(%[[SOURCE]] {{.*}}) map_clauses(to) capture(ByRef) name(".omp.target.update.source")
+ ! CHECK: omp.target kernel_type(generic) map_entries(%[[SOURCE_MAP]] -> [[SOURCE_ARG:%[^, ]+]], %[[CELEN_MAP]] -> [[CELEN_ARG:%[^, ]+]]
+ ! CHECK: %[[CELEN_SOURCE:.*]] = fir.coordinate_of [[SOURCE_ARG]], {{.*}} -> !fir.ref<complex<f64>>
+ ! CHECK: %[[CELEN_VALUE:.*]] = fir.load %[[CELEN_SOURCE]] : !fir.ref<complex<f64>>
+ ! CHECK: fir.store %[[CELEN_VALUE]] to [[CELEN_ARG]] : !fir.ref<complex<f64>>
+ ! CHECK-NOT: omp.target_update
+ ! CHECK: return
+ !$omp target update to(w%celen, w%nb, w%isp, w%ldo)
+end subroutine
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_typePupdate_pointer(
+subroutine update_pointer(w)
+ type(wavefun) :: w
+
+ ! CHECK: %[[FERWE_MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
+ ! CHECK: %[[PTR_MAP:.*]] = omp.map.info {{.*}} map_clauses(to) {{.*}}name("w%ptr")
+ ! CHECK: omp.target_update map_entries(%[[FERWE_MAP]], %[[PTR_MAP]],
+ !$omp target update to(w%ferwe, w%ptr)
+end subroutine
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_typePupdate_device(
+subroutine update_device(w)
+ type(wavefun) :: w
+
+ ! CHECK: %[[FERWE_MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
+ ! CHECK: %[[NB_MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
+ ! CHECK: omp.target_update device({{.*}}) map_entries(%[[FERWE_MAP]], %[[NB_MAP]]
+ !$omp target update to(w%ferwe, w%nb) device(0)
+end subroutine
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_typePupdate_single(
+subroutine update_single(w)
+ type(wavefun) :: w
+
+ ! CHECK: %[[MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
+ ! CHECK-NOT: omp.target kernel_type(generic)
+ ! CHECK: omp.target_update map_entries(%[[MAP]]
+ !$omp target update to(w%ferwe)
+end subroutine
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_typePupdate_array_element(
+subroutine update_array_element(w)
+ type(wavefun) :: w(2)
+
+ ! CHECK: fir.alloca tuple<f64, i32>
+ ! CHECK: omp.target kernel_type(generic)
+ ! CHECK-NOT: omp.target_update
+ !$omp target update to(w(2)%ferwe, w(2)%nb)
+end subroutine
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_typePupdate_from(
+subroutine update_from(w)
+ type(wavefun) :: w
+
+ ! CHECK: %[[FERWE_MAP:.*]] = omp.map.info {{.*}} map_clauses(from)
+ ! CHECK: %[[NB_MAP:.*]] = omp.map.info {{.*}} map_clauses(from)
+ ! CHECK: omp.target_update map_entries(%[[FERWE_MAP]], %[[NB_MAP]]
+ !$omp target update from(w%ferwe, w%nb)
+end subroutine
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_typePupdate_nowait(
+subroutine update_nowait(w)
+ type(wavefun) :: w
+
+ ! CHECK: %[[FERWE_MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
+ ! CHECK: %[[NB_MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
+ ! CHECK: omp.target_update map_entries(%[[FERWE_MAP]], %[[NB_MAP]]{{.*}}) nowait
+ !$omp target update to(w%ferwe, w%nb) nowait
+end subroutine
+
+end module
More information about the flang-commits
mailing list