[flang-commits] [flang] [Flang][OpenMP] Initial defaultmap(none) implementation (PR #166715)
via flang-commits
flang-commits at lists.llvm.org
Thu Nov 6 09:11:07 PST 2025
https://github.com/agozillon updated https://github.com/llvm/llvm-project/pull/166715
>From 2c0281a7615347144a9ffba0d916a7d2d39eb092 Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Wed, 5 Nov 2025 23:01:14 -0600
Subject: [PATCH] [Flang][OpenMP] Initial defaultmap(none) implementation
This PR adds defaultmap(none) behaviour to Flang, where we emit a semantic error if variables within the target construct do not have an associated data attribute. Similar to the way default behaves, as described by the OpenMP specification.
---
flang/lib/Lower/OpenMP/OpenMP.cpp | 7 +-
flang/lib/Semantics/resolve-directives.cpp | 96 +++++++++++++++++++
.../Todo/defaultmap-clause-firstprivate.f90 | 2 +-
.../OpenMP/Todo/defaultmap-clause-none.f90 | 11 ---
.../OpenMP/defaultmap-clause-none.f90 | 96 +++++++++++++++++++
5 files changed, 196 insertions(+), 16 deletions(-)
delete mode 100644 flang/test/Lower/OpenMP/Todo/defaultmap-clause-none.f90
create mode 100644 flang/test/Semantics/OpenMP/defaultmap-clause-none.f90
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index ad456d89bc432..0467b6b46e9f3 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -1008,9 +1008,7 @@ getImplicitMapTypeAndKind(fir::FirOpBuilder &firOpBuilder,
mlir::omp::VariableCaptureKind::ByRef);
break;
case DefMap::ImplicitBehavior::Firstprivate:
- case DefMap::ImplicitBehavior::None:
- TODO(loc, "Firstprivate and None are currently unsupported defaultmap "
- "behaviour");
+ TODO(loc, "Firstprivate currently unsupported defaultmap behaviour");
break;
case DefMap::ImplicitBehavior::From:
return std::make_pair(mapFlag |= mlir::omp::ClauseMapFlags::from,
@@ -1032,8 +1030,9 @@ getImplicitMapTypeAndKind(fir::FirOpBuilder &firOpBuilder,
mlir::omp::VariableCaptureKind::ByRef);
break;
case DefMap::ImplicitBehavior::Default:
+ case DefMap::ImplicitBehavior::None:
llvm_unreachable(
- "Implicit None Behaviour Should Have Been Handled Earlier");
+ "Implicit None and Default behaviour should have been handled earlier");
break;
}
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index deb57e005a352..e66c53043e0f5 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2965,6 +2965,72 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
}
}
+static bool IsOpenMPPointer(const Symbol &symbol) {
+ if (IsPointer(symbol) || IsBuiltinCPtr(symbol))
+ return true;
+ return false;
+}
+
+static bool IsOpenMPAggregate(const Symbol &symbol) {
+ if (IsAllocatable(symbol) || IsOpenMPPointer(symbol))
+ return false;
+
+ const auto *type{symbol.GetType()};
+ // OpenMP categorizes Fortran characters as aggregates.
+ if (type->category() == Fortran::semantics::DeclTypeSpec::Category::Character)
+ return true;
+
+ if (const auto *det = symbol.GetUltimate()
+ .detailsIf<Fortran::semantics::ObjectEntityDetails>())
+ if (det->IsArray())
+ return true;
+
+ if (type->AsDerived())
+ return true;
+
+ if (IsDeferredShape(symbol) || IsAssumedRank(symbol) ||
+ IsAssumedShape(symbol))
+ return true;
+ return false;
+}
+
+static bool IsOpenMPScalar(const Symbol &symbol) {
+ if (IsOpenMPAggregate(symbol) || IsOpenMPPointer(symbol) ||
+ IsAllocatable(symbol))
+ return false;
+ const auto *type{symbol.GetType()};
+ if ((!symbol.GetShape() || symbol.GetShape()->empty()) &&
+ (type->category() ==
+ Fortran::semantics::DeclTypeSpec::Category::Numeric ||
+ type->category() ==
+ Fortran::semantics::DeclTypeSpec::Category::Logical))
+ return true;
+ return false;
+}
+
+static bool DefaultMapCategoryMatchesSymbol(
+ parser::OmpVariableCategory::Value category, const Symbol &symbol) {
+ using varCat = parser::OmpVariableCategory::Value;
+ switch (category) {
+ case varCat::Scalar:
+ return IsOpenMPScalar(symbol);
+ break;
+ case varCat::Allocatable:
+ return IsAllocatable(symbol);
+ break;
+ case varCat::Aggregate:
+ return IsOpenMPAggregate(symbol);
+ break;
+ case varCat::Pointer:
+ return IsOpenMPPointer(symbol);
+ break;
+ case varCat::All:
+ return true;
+ break;
+ }
+ return false;
+}
+
// For OpenMP constructs, check all the data-refs within the constructs
// and adjust the symbol for each Name if necessary
void OmpAttributeVisitor::Post(const parser::Name &name) {
@@ -3000,6 +3066,36 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
}
}
+ // TODO: handle case where default and defaultmap are present on the same
+ // construct and conflict, defaultmap should supersede default if they
+ // conflict.
+ if (!GetContext().defaultMap.empty()) {
+ // Checked before implicit data sharing attributes as this rule ignores
+ // them and expects explicit predetermined/specified attributes to be in
+ // place for the types specified.
+ if (Symbol * found{currScope().FindSymbol(name.source)}) {
+ // If the variable has declare target applied to it (enter or link) it
+ // is exempt from defaultmap(none) restrictions
+ if (!symbol->GetUltimate().test(Symbol::Flag::OmpDeclareTarget)) {
+ auto &dMap = GetContext().defaultMap;
+ for (auto defaults : dMap) {
+ if (defaults.second ==
+ parser::OmpDefaultmapClause::ImplicitBehavior::None) {
+ if (DefaultMapCategoryMatchesSymbol(defaults.first, *found)) {
+ if (!IsObjectWithDSA(*symbol)) {
+ context_.Say(name.source,
+ "The DEFAULTMAP(NONE) clause requires that '%s' must be "
+ "listed in a "
+ "data-sharing attribute, data-mapping attribute, or is_device_ptr clause"_err_en_US,
+ symbol->name());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
if (Symbol * found{currScope().FindSymbol(name.source)}) {
if (found->GetUltimate().test(semantics::Symbol::Flag::OmpThreadprivate))
return;
diff --git a/flang/test/Lower/OpenMP/Todo/defaultmap-clause-firstprivate.f90 b/flang/test/Lower/OpenMP/Todo/defaultmap-clause-firstprivate.f90
index 6818c39f63a3c..ce36dd45e3ab9 100644
--- a/flang/test/Lower/OpenMP/Todo/defaultmap-clause-firstprivate.f90
+++ b/flang/test/Lower/OpenMP/Todo/defaultmap-clause-firstprivate.f90
@@ -6,7 +6,7 @@ subroutine f00
! NOTE: This is implemented for scalars as it is the default behaviour, so we utilise
! a different data type.
integer, allocatable :: i
- !CHECK: not yet implemented: Firstprivate and None are currently unsupported defaultmap behaviour
+ !CHECK: not yet implemented: Firstprivate currently unsupported defaultmap behaviour
!$omp target defaultmap(firstprivate)
i = 10
!$omp end target
diff --git a/flang/test/Lower/OpenMP/Todo/defaultmap-clause-none.f90 b/flang/test/Lower/OpenMP/Todo/defaultmap-clause-none.f90
deleted file mode 100644
index 287eb4a9dfe8f..0000000000000
--- a/flang/test/Lower/OpenMP/Todo/defaultmap-clause-none.f90
+++ /dev/null
@@ -1,11 +0,0 @@
-!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
-!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
-
-subroutine f00
- implicit none
- integer :: i
- !CHECK: not yet implemented: Firstprivate and None are currently unsupported defaultmap behaviour
- !$omp target defaultmap(none)
- i = 10
- !$omp end target
-end
diff --git a/flang/test/Semantics/OpenMP/defaultmap-clause-none.f90 b/flang/test/Semantics/OpenMP/defaultmap-clause-none.f90
new file mode 100644
index 0000000000000..08e8ebc995097
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/defaultmap-clause-none.f90
@@ -0,0 +1,96 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51
+
+subroutine defaultmap_all_none_no_errors
+ implicit none
+ real :: array(10)
+ integer, pointer :: ptr(:)
+ real, allocatable :: alloca
+ integer :: index
+
+ !$omp target defaultmap(none) map(to: index, alloca) map(tofrom: array, ptr)
+ do index = 1, 10
+ ptr(index) = array(index) + alloca
+ end do
+ !$omp end target
+end subroutine defaultmap_all_none_no_errors
+
+subroutine defaultmap_all_none
+ implicit none
+ real :: array(10)
+ integer, pointer :: ptr(:)
+ real, allocatable :: alloca
+ integer :: index
+ !$omp target defaultmap(none)
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'index' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+ do index = 1, 10
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'ptr' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'index' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'array' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'index' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'alloca' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+ ptr(index) = array(index) + alloca
+ end do
+ !$omp end target
+end subroutine defaultmap_all_none
+
+subroutine defaultmap_scalar_none
+ implicit none
+ real :: array(10)
+ integer, pointer :: ptr(:)
+ real, allocatable :: alloca
+ integer :: index
+
+ !$omp target defaultmap(none: scalar)
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'index' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+ do index = 1, 10
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'index' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'index' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+ ptr(index) = array(index) + alloca
+ end do
+ !$omp end target
+end subroutine defaultmap_scalar_none
+
+subroutine defaultmap_pointer_none
+ implicit none
+ real :: array(10)
+ integer, pointer :: ptr(:)
+ real, allocatable :: alloca
+ integer :: index
+
+ !$omp target defaultmap(none: pointer)
+ do index = 1, 10
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'ptr' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+ ptr(index) = array(index) + alloca
+ end do
+ !$omp end target
+end subroutine defaultmap_pointer_none
+
+subroutine defaultmap_allocatable_none
+ implicit none
+ real :: array(10)
+ integer, pointer :: ptr(:)
+ real, allocatable :: alloca
+ integer :: index
+
+ !$omp target defaultmap(none: allocatable)
+ do index = 1, 10
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'alloca' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+ ptr(index) = array(index) + alloca
+ end do
+ !$omp end target
+end subroutine defaultmap_allocatable_none
+
+subroutine defaultmap_aggregate_none
+ implicit none
+ real :: array(10)
+ integer, pointer :: ptr(:)
+ real, allocatable :: alloca
+ integer :: index
+
+ !$omp target defaultmap(none: aggregate)
+ do index = 1, 10
+!ERROR: The DEFAULTMAP(NONE) clause requires that 'array' must be listed in a data-sharing attribute, data-mapping attribute, or is_device_ptr clause
+ ptr(index) = array(index) + alloca
+ end do
+ !$omp end target
+end subroutine defaultmap_aggregate_none
More information about the flang-commits
mailing list