[flang-commits] [flang] [Flang][OpenMP] Optimize target updates of derived-type scalars (PR #219488)
Akash Banerjee via flang-commits
flang-commits at lists.llvm.org
Tue Sep 1 05:50:53 PDT 2026
https://github.com/TIFitis updated https://github.com/llvm/llvm-project/pull/219488
>From ef03c3ccf2d6b223551f06a2b819857b3dae58b0 Mon Sep 17 00:00:00 2001
From: Akash Banerjee <Akash.Banerjee at amd.com>
Date: Tue, 25 Aug 2026 17:21:31 +0100
Subject: [PATCH 1/3] [Flang][OpenMP] Optimize target updates of derived-type
scalars
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.
---
flang/lib/Lower/OpenMP/OpenMP.cpp | 191 +++++++++++++++++-
.../OpenMP/target-update-derived-type.f90 | 114 +++++++++++
2 files changed, 303 insertions(+), 2 deletions(-)
create mode 100644 flang/test/Lower/OpenMP/target-update-derived-type.f90
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 7503d33c8df38..684db4340e5d4 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -39,6 +39,7 @@
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/HLFIR/HLFIROps.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "flang/Parser/openmp-utils.h"
@@ -65,6 +66,7 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Frontend/OpenMP/OMP.h"
+#include "llvm/TargetParser/Triple.h"
#include <atomic>
using namespace Fortran::lower::omp;
@@ -4300,6 +4302,173 @@ static mlir::omp::TargetDataOp genTargetDataOp(
return targetDataOp;
}
+struct TargetUpdateKernelEntry {
+ mlir::omp::MapInfoOp mapInfo;
+ mlir::Value hostPtr;
+ mlir::Type componentType;
+};
+
+static bool hasAMDGCNTarget(mlir::ModuleOp module) {
+ auto offloadModule = llvm::cast<mlir::omp::OffloadModuleInterface>(*module);
+ if (offloadModule.getIsTargetDevice())
+ return fir::getTargetTriple(module).isAMDGCN();
+ return llvm::any_of(
+ offloadModule.getTargetTriples(), [](mlir::Attribute attr) {
+ auto tripleAttr = llvm::dyn_cast<mlir::StringAttr>(attr);
+ return tripleAttr && llvm::Triple(tripleAttr.getValue()).isAMDGCN();
+ });
+}
+
+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};
+}
+
+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 indexedEntry : llvm::enumerate(entries)) {
+ std::size_t i = indexedEntry.index();
+ const TargetUpdateKernelEntry &entry = indexedEntry.value();
+ 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 (unsigned i = 0; i < entries.size(); ++i) {
+ mlir::Value index =
+ builder.createIntegerConstant(loc, builder.getI32Type(), i);
+ mlir::Value sourceAddr = fir::CoordinateOp::create(
+ builder, loc, builder.getRefType(entries[i].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, 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.
+ if (!hasAMDGCNTarget(converter.getModuleOp()) || clauseOps.mapVars.empty() ||
+ !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,
@@ -4327,6 +4496,24 @@ 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, 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,
@@ -5501,8 +5688,8 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
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/test/Lower/OpenMP/target-update-derived-type.f90 b/flang/test/Lower/OpenMP/target-update-derived-type.f90
new file mode 100644
index 0000000000000..4552e14ffb8ee
--- /dev/null
+++ b/flang/test/Lower/OpenMP/target-update-derived-type.f90
@@ -0,0 +1,114 @@
+! 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 -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 :: nb
+ integer :: isp
+ 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
+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: fir.if %[[COND]] {
+ ! CHECK: fir.store {{.*}} to {{.*}} : !fir.ref<f64>
+ ! CHECK: %[[FERWE_MAP:.*]] = omp.map.info var_ptr(%[[FERWE]] : !fir.ref<f64>, f64) map_clauses(storage) capture(ByRef)
+ ! CHECK: fir.store {{.*}} to {{.*}} : !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: %[[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:%[^, ]+]]
+ ! 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-NOT: omp.target_update
+ ! CHECK: return
+ ! HOST: omp.target_update
+ ! NONAMD: omp.target_update
+ !$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: omp.map.info {{.*}} map_clauses(to)
+ ! CHECK: omp.target_update map_entries(
+ !$omp target update to(w%ptr)
+end subroutine
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_typePupdate_device(
+subroutine update_device(w)
+ type(wavefun) :: w
+
+ ! CHECK: %[[MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
+ ! CHECK: omp.target_update device({{.*}}) map_entries(%[[MAP]]
+ !$omp target update to(w%ferwe) device(0)
+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: %[[MAP:.*]] = omp.map.info {{.*}} map_clauses(from)
+ ! CHECK: omp.target_update map_entries(%[[MAP]]
+ !$omp target update from(w%ferwe)
+end subroutine
+
+! CHECK-LABEL: func.func @_QMtarget_update_derived_typePupdate_nowait(
+subroutine update_nowait(w)
+ type(wavefun) :: w
+
+ ! CHECK: %[[MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
+ ! CHECK: omp.target_update map_entries(%[[MAP]]{{.*}}) nowait
+ !$omp target update to(w%ferwe) nowait
+end subroutine
+
+end module
>From eda4599f6109f33efeafa5d146ce49ef34bbfe3c Mon Sep 17 00:00:00 2001
From: Akash Banerjee <Akash.Banerjee at amd.com>
Date: Fri, 28 Aug 2026 21:13:11 +0100
Subject: [PATCH 2/3] Address reviewer comments.
---
flang/lib/Lower/OpenMP/OpenMP.cpp | 40 +++++++---------
flang/lib/Lower/OpenMP/Utils.cpp | 41 ++++++++++++++++
flang/lib/Lower/OpenMP/Utils.h | 10 ++++
.../OpenMP/target-update-derived-type-usm.f90 | 27 +++++++++++
.../OpenMP/target-update-derived-type.f90 | 48 +++++++++++++++++--
5 files changed, 140 insertions(+), 26 deletions(-)
create mode 100644 flang/test/Lower/OpenMP/target-update-derived-type-usm.f90
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 684db4340e5d4..457149430bfc8 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -39,7 +39,6 @@
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Optimizer/Dialect/FIRType.h"
-#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/HLFIR/HLFIROps.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "flang/Parser/openmp-utils.h"
@@ -66,7 +65,6 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Frontend/OpenMP/OMP.h"
-#include "llvm/TargetParser/Triple.h"
#include <atomic>
using namespace Fortran::lower::omp;
@@ -4308,17 +4306,6 @@ struct TargetUpdateKernelEntry {
mlir::Type componentType;
};
-static bool hasAMDGCNTarget(mlir::ModuleOp module) {
- auto offloadModule = llvm::cast<mlir::omp::OffloadModuleInterface>(*module);
- if (offloadModule.getIsTargetDevice())
- return fir::getTargetTriple(module).isAMDGCN();
- return llvm::any_of(
- offloadModule.getTargetTriples(), [](mlir::Attribute attr) {
- auto tripleAttr = llvm::dyn_cast<mlir::StringAttr>(attr);
- return tripleAttr && llvm::Triple(tripleAttr.getValue()).isAMDGCN();
- });
-}
-
static std::optional<TargetUpdateKernelEntry>
getTargetUpdateKernelEntry(mlir::Value mapVar) {
auto mapInfo = mapVar.getDefiningOp<mlir::omp::MapInfoOp>();
@@ -4353,6 +4340,10 @@ getTargetUpdateKernelEntry(mlir::Value mapVar) {
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) {
@@ -4372,9 +4363,7 @@ genTargetUpdateKernel(lower::AbstractConverter &converter, mlir::Location loc,
mlir::TupleType::get(builder.getContext(), sourceTypes);
mlir::Value sourcePack = builder.createTemporary(loc, sourceType);
- for (auto indexedEntry : llvm::enumerate(entries)) {
- std::size_t i = indexedEntry.index();
- const TargetUpdateKernelEntry &entry = indexedEntry.value();
+ 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);
@@ -4411,11 +4400,11 @@ genTargetUpdateKernel(lower::AbstractConverter &converter, mlir::Location loc,
assert(mapBlockArgs.size() == entries.size() + 1 &&
"expected source and destination map arguments");
builder.setInsertionPointToEnd(&targetOp.getRegion().front());
- for (unsigned i = 0; i < entries.size(); ++i) {
+ 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(entries[i].componentType),
+ 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]);
@@ -4426,16 +4415,20 @@ genTargetUpdateKernel(lower::AbstractConverter &converter, mlir::Location loc,
}
static mlir::Operation *tryGenTargetUpdateKernel(
- lower::AbstractConverter &converter, mlir::Location loc,
+ 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.
- if (!hasAMDGCNTarget(converter.getModuleOp()) || clauseOps.mapVars.empty() ||
- !clauseOps.dependVars.empty() || !clauseOps.dependIterated.empty() ||
- !clauseOps.mapIterated.empty() || clauseOps.nowait || clauseOps.device)
+ mlir::ModuleOp module = converter.getModuleOp();
+ if (!hasAMDGCNTarget(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;
@@ -4508,7 +4501,8 @@ genTargetUpdateDataOp(lower::AbstractConverter &converter,
converter, semaCtx, symTable, stmtCtx, item->clauses, loc,
llvm::omp::Directive::OMPD_target_update, clauseOps);
- if (mlir::Operation *op = tryGenTargetUpdateKernel(converter, loc, clauseOps))
+ if (mlir::Operation *op =
+ tryGenTargetUpdateKernel(converter, semaCtx, loc, clauseOps))
return op;
return mlir::omp::TargetUpdateOp::create(firOpBuilder, loc, clauseOps);
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index 4e7cf5ca34cc3..71f29b298c09d 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>
@@ -1383,6 +1384,46 @@ static llvm::Triple getOffloadTargetTriple(mlir::ModuleOp module) {
return llvm::Triple();
}
+bool hasAMDGCNTarget(mlir::ModuleOp module) {
+ auto offloadModule =
+ llvm::cast<mlir::omp::OffloadModuleInterface>(module.getOperation());
+ if (offloadModule.getIsTargetDevice())
+ return fir::getTargetTriple(module).isAMDGCN();
+ return llvm::any_of(
+ offloadModule.getTargetTriples(), [](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 94f85c43f7033..3c600757e1633 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;
@@ -267,6 +268,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 has
+/// at least one AMDGPU offload target.
+bool hasAMDGCNTarget(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
index 4552e14ffb8ee..9047a2f4b5367 100644
--- a/flang/test/Lower/OpenMP/target-update-derived-type.f90
+++ b/flang/test/Lower/OpenMP/target-update-derived-type.f90
@@ -8,8 +8,11 @@ module target_update_derived_type
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
@@ -27,19 +30,48 @@ subroutine update_with_if(w, enabled)
! 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: fir.store {{.*}} to {{.*}} : !fir.ref<f64>
+ ! 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: fir.store {{.*}} to {{.*}} : !fir.ref<complex<f64>>
+ ! 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:%[^, ]+]]
+ ! 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
! HOST: omp.target_update
@@ -83,6 +115,16 @@ subroutine update_device(w)
!$omp target update to(w%ferwe) 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)
>From 4c7d31a6c82f741f5a512da39c8f65af52aee4d6 Mon Sep 17 00:00:00 2001
From: Akash Banerjee <Akash.Banerjee at amd.com>
Date: Tue, 1 Sep 2026 13:50:30 +0100
Subject: [PATCH 3/3] Address review comments.
---
flang/lib/Lower/OpenMP/OpenMP.cpp | 2 +-
flang/lib/Lower/OpenMP/Utils.cpp | 14 +++---
flang/lib/Lower/OpenMP/Utils.h | 6 +--
.../OpenMP/target-update-derived-type.f90 | 46 +++++++++++++------
4 files changed, 44 insertions(+), 24 deletions(-)
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 457149430bfc8..c03b5d410f2e6 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -4424,7 +4424,7 @@ static mlir::Operation *tryGenTargetUpdateKernel(
// 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 (!hasAMDGCNTarget(module) ||
+ if (!hasOnlyAMDGCNTargets(module) ||
requiresUnifiedSharedMemory(module, semaCtx) ||
clauseOps.mapVars.size() < 2 || !clauseOps.dependVars.empty() ||
!clauseOps.dependIterated.empty() || !clauseOps.mapIterated.empty() ||
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index 71f29b298c09d..e28117c759973 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -1384,16 +1384,18 @@ static llvm::Triple getOffloadTargetTriple(mlir::ModuleOp module) {
return llvm::Triple();
}
-bool hasAMDGCNTarget(mlir::ModuleOp module) {
+bool hasOnlyAMDGCNTargets(mlir::ModuleOp module) {
auto offloadModule =
llvm::cast<mlir::omp::OffloadModuleInterface>(module.getOperation());
if (offloadModule.getIsTargetDevice())
return fir::getTargetTriple(module).isAMDGCN();
- return llvm::any_of(
- offloadModule.getTargetTriples(), [](mlir::Attribute attr) {
- auto tripleAttr = llvm::dyn_cast<mlir::StringAttr>(attr);
- return tripleAttr && llvm::Triple(tripleAttr.getValue()).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) {
diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index 3c600757e1633..42c70a478f304 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -268,9 +268,9 @@ void collectEnclosingConstructTraits(
mlir::Operation *op,
llvm::SmallVectorImpl<llvm::omp::TraitProperty> &constructTraits);
-/// Return true when \p module is being compiled for an AMDGPU device or has
-/// at least one AMDGPU offload target.
-bool hasAMDGCNTarget(mlir::ModuleOp module);
+/// 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.
diff --git a/flang/test/Lower/OpenMP/target-update-derived-type.f90 b/flang/test/Lower/OpenMP/target-update-derived-type.f90
index 9047a2f4b5367..cdf81aa477330 100644
--- a/flang/test/Lower/OpenMP/target-update-derived-type.f90
+++ b/flang/test/Lower/OpenMP/target-update-derived-type.f90
@@ -1,6 +1,7 @@
! 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
@@ -22,6 +23,21 @@ module target_update_derived_type
! 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
@@ -74,8 +90,6 @@ subroutine update_with_if(w, enabled)
! CHECK-NEXT: omp.terminator
! CHECK-NOT: omp.target_update
! CHECK: return
- ! HOST: omp.target_update
- ! NONAMD: omp.target_update
!$omp target update to(w%ferwe, w%celen, w%nb, w%isp, w%ldo) if(enabled)
end subroutine
@@ -101,18 +115,20 @@ subroutine update_without_if(w)
subroutine update_pointer(w)
type(wavefun) :: w
- ! CHECK: omp.map.info {{.*}} map_clauses(to)
- ! CHECK: omp.target_update map_entries(
- !$omp target update to(w%ptr)
+ ! 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: %[[MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
- ! CHECK: omp.target_update device({{.*}}) map_entries(%[[MAP]]
- !$omp target update to(w%ferwe) device(0)
+ ! 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(
@@ -139,18 +155,20 @@ subroutine update_array_element(w)
subroutine update_from(w)
type(wavefun) :: w
- ! CHECK: %[[MAP:.*]] = omp.map.info {{.*}} map_clauses(from)
- ! CHECK: omp.target_update map_entries(%[[MAP]]
- !$omp target update from(w%ferwe)
+ ! 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: %[[MAP:.*]] = omp.map.info {{.*}} map_clauses(to)
- ! CHECK: omp.target_update map_entries(%[[MAP]]{{.*}}) nowait
- !$omp target update to(w%ferwe) nowait
+ ! 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