[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