[flang-commits] [flang] [flang][OpenMP] Support custom mappers in target update to/from clauses (PR #169673)

via flang-commits flang-commits at lists.llvm.org
Wed Nov 26 08:22:08 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: Krish Gupta (KrxGu)

<details>
<summary>Changes</summary>

Fixes #<!-- -->168701

This patch adds support for custom mappers in OpenMP `target update` `to()` and `from()` clauses, implementing the OpenMP 5.2 specification.

Previously, custom mappers were only supported in `map` clauses. This change extends mapper resolution to `target update` constructs by:

- Adding `Pre(OmpClause::To)` and `Pre(OmpClause::From)` handlers in `resolve-names.cpp`
- Following the same pattern as the existing `OmpMapClause` handler
- Supporting both custom mappers and the special `default` mapper
- Adding proper diagnostics for undefined mappers and non-mapper symbols

**Testing:**
- Semantic tests verify custom/default mapper usage and error detection
- Lowering tests verify MLIR generation with mapper attributes
<img width="697" height="202" alt="image" src="https://github.com/user-attachments/assets/b081e118-08ba-4b74-8d61-c313aec4811f" />


---
Full diff: https://github.com/llvm/llvm-project/pull/169673.diff


3 Files Affected:

- (modified) flang/lib/Semantics/resolve-names.cpp (+60) 
- (added) flang/test/Lower/OpenMP/target-update-mapper.f90 (+52) 
- (added) flang/test/Semantics/OpenMP/target-update-mapper.f90 (+54) 


``````````diff
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 2a487a6d39d51..ca17767dce924 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1631,6 +1631,8 @@ class OmpVisitor : public virtual DeclarationVisitor {
     return true;
   }
   bool Pre(const parser::OmpMapClause &);
+  bool Pre(const parser::OmpClause::To &);
+  bool Pre(const parser::OmpClause::From &);
 
   bool Pre(const parser::OpenMPSectionsConstruct &) {
     PushScope(Scope::Kind::OtherConstruct, nullptr);
@@ -1876,6 +1878,64 @@ bool OmpVisitor::Pre(const parser::OmpMapClause &x) {
   return true;
 }
 
+bool OmpVisitor::Pre(const parser::OmpClause::To &x) {
+  // Resolve mapper names in "to" clauses (e.g., for target update)
+  auto &mods{OmpGetModifiers(x.v)};
+  if (auto *mapper{OmpGetUniqueModifier<parser::OmpMapper>(mods)}) {
+    if (auto *symbol{FindSymbol(currScope(), mapper->v)}) {
+      auto &ultimate{symbol->GetUltimate()};
+      auto *misc{ultimate.detailsIf<MiscDetails>()};
+      auto *md{ultimate.detailsIf<MapperDetails>()};
+      if (!md && (!misc || misc->kind() != MiscDetails::Kind::ConstructName))
+        context().Say(mapper->v.source,
+            "Name '%s' should be a mapper name"_err_en_US, mapper->v.source);
+      else
+        mapper->v.symbol = symbol;
+    } else {
+      // Allow the special 'default' mapper identifier without prior
+      // declaration so lowering can recognize and handle it. Emit an
+      // error for any other missing mapper identifier.
+      if (mapper->v.source.ToString() == "default") {
+        mapper->v.symbol = &MakeSymbol(
+            mapper->v, MiscDetails{MiscDetails::Kind::ConstructName});
+      } else {
+        context().Say(
+            mapper->v.source, "'%s' not declared"_err_en_US, mapper->v.source);
+      }
+    }
+  }
+  return true;
+}
+
+bool OmpVisitor::Pre(const parser::OmpClause::From &x) {
+  // Resolve mapper names in "from" clauses (e.g., for target update)
+  auto &mods{OmpGetModifiers(x.v)};
+  if (auto *mapper{OmpGetUniqueModifier<parser::OmpMapper>(mods)}) {
+    if (auto *symbol{FindSymbol(currScope(), mapper->v)}) {
+      auto &ultimate{symbol->GetUltimate()};
+      auto *misc{ultimate.detailsIf<MiscDetails>()};
+      auto *md{ultimate.detailsIf<MapperDetails>()};
+      if (!md && (!misc || misc->kind() != MiscDetails::Kind::ConstructName))
+        context().Say(mapper->v.source,
+            "Name '%s' should be a mapper name"_err_en_US, mapper->v.source);
+      else
+        mapper->v.symbol = symbol;
+    } else {
+      // Allow the special 'default' mapper identifier without prior
+      // declaration so lowering can recognize and handle it. Emit an
+      // error for any other missing mapper identifier.
+      if (mapper->v.source.ToString() == "default") {
+        mapper->v.symbol = &MakeSymbol(
+            mapper->v, MiscDetails{MiscDetails::Kind::ConstructName});
+      } else {
+        context().Say(
+            mapper->v.source, "'%s' not declared"_err_en_US, mapper->v.source);
+      }
+    }
+  }
+  return true;
+}
+
 void OmpVisitor::ProcessMapperSpecifier(const parser::OmpMapperSpecifier &spec,
     const parser::OmpClauseList &clauses) {
   // This "manually" walks the tree of the construct, because we need
diff --git a/flang/test/Lower/OpenMP/target-update-mapper.f90 b/flang/test/Lower/OpenMP/target-update-mapper.f90
new file mode 100644
index 0000000000000..d49ad51343679
--- /dev/null
+++ b/flang/test/Lower/OpenMP/target-update-mapper.f90
@@ -0,0 +1,52 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s
+
+! Test mapper usage in target update to/from clauses
+
+program target_update_mapper
+  implicit none
+
+  integer, parameter :: n = 4
+
+  type :: typ
+    integer, allocatable :: a(:)
+    integer, allocatable :: b(:)
+  end type typ
+
+  !$omp declare mapper(custom: typ :: t) map(t%a)
+
+  ! CHECK-LABEL: omp.declare_mapper @_QQFcustom : !fir.type<_QFTtyp{a:!fir.box<!fir.heap<!fir.array<?xi32>>>,b:!fir.box<!fir.heap<!fir.array<?xi32>>>}>
+
+  type(typ) :: t
+
+  allocate(t%a(n), source=1)
+  allocate(t%b(n), source=2)
+
+  !$omp target enter data map(alloc: t)
+
+  ! Test target update to with custom mapper
+  ! CHECK: %[[T_VAR:.*]] = fir.declare %{{.*}} {uniq_name = "_QFtarget_update_mapperEt"} : (!fir.ref<!fir.type<_QFTtyp{a:!fir.box<!fir.heap<!fir.array<?xi32>>>,b:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.ref<!fir.type<_QFTtyp{a:!fir.box<!fir.heap<!fir.array<?xi32>>>,b:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+  ! CHECK: %[[MAP_INFO:.*]] = omp.map.info var_ptr(%[[T_VAR]] : {{.*}}, {{.*}}) map_clauses(to) capture(ByRef) mapper(@_QQFcustom) -> {{.*}}
+  ! CHECK: omp.target_update motion_entries(%[[MAP_INFO]] : {{.*}})
+  t%a = 42
+  !$omp target update to(mapper(custom): t)
+
+  !$omp target
+    t%a(:) = t%a(:) / 2
+    t%b(:) = -1
+  !$omp end target
+
+  ! Test target update from with custom mapper
+  ! CHECK: %[[MAP_INFO2:.*]] = omp.map.info var_ptr(%{{.*}} : {{.*}}, {{.*}}) map_clauses(from) capture(ByRef) mapper(@_QQFcustom) -> {{.*}}
+  ! CHECK: omp.target_update motion_entries(%[[MAP_INFO2]] : {{.*}})
+  !$omp target update from(mapper(custom): t)
+
+  ! Test target update to with default mapper
+  ! CHECK: %[[MAP_INFO3:.*]] = omp.map.info var_ptr(%{{.*}} : {{.*}}, {{.*}}) map_clauses(to) capture(ByRef) mapper(@_QQFtyp_omp_default_mapper) -> {{.*}}
+  ! CHECK: omp.target_update motion_entries(%[[MAP_INFO3]] : {{.*}})
+  !$omp target update to(mapper(default): t)
+
+  !$omp target exit data map(delete: t)
+  deallocate(t%a)
+  deallocate(t%b)
+
+end program target_update_mapper
diff --git a/flang/test/Semantics/OpenMP/target-update-mapper.f90 b/flang/test/Semantics/OpenMP/target-update-mapper.f90
new file mode 100644
index 0000000000000..f03496e155568
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/target-update-mapper.f90
@@ -0,0 +1,54 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+
+! Test mapper usage in target update to/from clauses
+
+program target_update_mapper
+  implicit none
+
+  integer, parameter :: n = 4
+
+  type :: typ
+    integer, allocatable :: a(:)
+    integer, allocatable :: b(:)
+  end type typ
+
+  !$omp declare mapper(custom: typ :: t) map(t%a)
+
+  type(typ) :: t
+  integer :: not_a_mapper
+  allocate(t%a(n), source=1)
+  allocate(t%b(n), source=2)
+
+  !$omp target enter data map(alloc: t)
+
+  ! Valid: using custom mapper with target update to
+  t%a = 42
+  !$omp target update to(mapper(custom): t)
+
+  !$omp target
+    t%a(:) = t%a(:) / 2
+    t%b(:) = -1
+  !$omp end target
+
+  ! Valid: using custom mapper with target update from
+  !$omp target update from(mapper(custom): t)
+
+  ! Valid: using default mapper explicitly
+  !$omp target update to(mapper(default): t)
+
+  print*, t%a
+  print*, t%b
+
+  !$omp target exit data map(delete: t)
+  deallocate(t%a)
+  deallocate(t%b)
+
+  ! Test error case: undefined mapper
+  !ERROR: 'undefined_mapper' not declared
+  !$omp target update to(mapper(undefined_mapper): t)
+
+  ! Test error case: wrong kind of symbol
+  !ERROR: Name 'not_a_mapper' should be a mapper name
+  !$omp target update from(mapper(not_a_mapper): t)
+
+end program target_update_mapper

``````````

</details>


https://github.com/llvm/llvm-project/pull/169673


More information about the flang-commits mailing list