[flang][OpenMP] Support custom mappers in target update to/from clauses#169673
[flang][OpenMP] Support custom mappers in target update to/from clauses#169673
Conversation
|
@llvm/pr-subscribers-flang-semantics @llvm/pr-subscribers-flang-openmp Author: Krish Gupta (KrxGu) ChangesFixes #168701 This patch adds support for custom mappers in OpenMP Previously, custom mappers were only supported in
Testing:
Full diff: https://github.com/llvm/llvm-project/pull/169673.diff 3 Files Affected:
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
|
|
@llvm/pr-subscribers-flang-fir-hlfir Author: Krish Gupta (KrxGu) ChangesFixes #168701 This patch adds support for custom mappers in OpenMP Previously, custom mappers were only supported in
Testing:
Full diff: https://github.com/llvm/llvm-project/pull/169673.diff 3 Files Affected:
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
|
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) FlangFlang.Lower/CUDA/cuda-gpu-managed.cufFlang.Semantics/bug175207.f90If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
There was a problem hiding this comment.
Pull request overview
This PR extends OpenMP custom mapper support to target update directives' to() and from() clauses, implementing the OpenMP 5.2 specification. Previously, custom mappers were only available in map clauses.
Key Changes:
- Added mapper resolution for
to()andfrom()clauses in target update directives - Introduced semantic validation for undefined mappers and non-mapper symbols
- Added comprehensive test coverage for both semantic analysis and MLIR lowering
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| flang/lib/Semantics/resolve-names.cpp | Adds Pre(OmpClause::To) and Pre(OmpClause::From) handlers to resolve mapper names in target update clauses |
| flang/test/Semantics/OpenMP/target-update-mapper.f90 | Semantic tests verifying custom/default mapper usage and error detection in target update constructs |
| flang/test/Lower/OpenMP/target-update-mapper.f90 | Lowering tests verifying correct MLIR generation with mapper attributes for target update operations |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
TIFitis
left a comment
There was a problem hiding this comment.
Thanks for the PR. I've added some review comments below...
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
|
@TIFitis @kparzysz.
Also fixed the test expectations - they were using incorrect mangled names for program-scoped mappers. CI all green, Good To Merge!! |
a770cf2 to
c620237
Compare
|
What happened to the offloading test? Please resolve the merge conflict so I can test it. |
Support mapper modifier in processMotionClauses for to/from clauses
Extract ResolveMapperModifier helper and simplify tests
- Use early return in getMapperIdentifier to reduce nesting - Remove redundant if constexpr with identical branches - Make ResolveMapperModifier parameter const - Remove unnecessary const_cast at call sites
The symbol field is already marked mutable in the Name struct, so it can be modified directly through a const reference.
e4af0a2 to
e5a71f3
Compare
Use separate objects (obj1, obj2) for custom and default mapper tests to avoid device memory mapping conflicts.
🪟 Windows x64 Test Results
Failed Tests(click on a test name to see its output) FlangFlang.Lower/CUDA/cuda-gpu-managed.cufFlang.Semantics/bug175207.f90If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
DeclarationTypeSpec::Type is a WRAPPER_CLASS with member 'v', not 'derived'. Corrects build failure on CI.
|
@TIFitis I have adressed all the reviews and have added the required test too(which you can test at your end and lemme know if something needs to be changed). CI all green, Good To Merge!! |
TIFitis
left a comment
There was a problem hiding this comment.
LGTM overall minus the nit. Please allow another +1.
The offload test is passing on my end, thanks for the PR.
Per review feedback, removed all pointer-style and indentation changes that were picked up during rebase. Kept only functional changes for mapper support in target update.
|
The CI failures (CUDA managed memory and namelist tests) are unrelated to this PR's The failures appear to be from commits that came in during rebase. Could you please Files actually modified by this PR:
|
CI Failures are Unrelated to This PRThe failing tests are in areas not touched by this PR: Failing Tests:
This PR's Scope:
These failures appear to be from recent CUDA commits on main (e.g., #175243, #175225) Could you please either:
The OpenMP-specific changes in this PR are ready for review. |
|
I've already accepted the PR. Parser/semantics isn't my area, so please feel to merge it once one other reviewer has accepted as well 👍🏽 |
Fixes #168701
This patch adds support for custom mappers in OpenMP
target updateto()andfrom()clauses, implementing the OpenMP 5.2 specification.Previously, custom mappers were only supported in
mapclauses. This change extends mapper resolution totarget updateconstructs by:Pre(OmpClause::To)andPre(OmpClause::From)handlers inresolve-names.cppOmpMapClausehandlerdefaultmapperTesting: