[flang-commits] [flang] [flang][OpenMP] Fix host-associated user-defined operator reduction (PR #207413)
Carlos Seo via flang-commits
flang-commits at lists.llvm.org
Fri Jul 3 08:26:58 PDT 2026
https://github.com/ceseo created https://github.com/llvm/llvm-project/pull/207413
A DECLARE REDUCTION for a user-defined operator (e.g. reduction(.myadd.:x)) was rejected with "Invalid reduction operator in REDUCTION clause" when the operator was host-associated.
CheckReductionOperator looked up the mangled reduction name in the scope that owns the operator symbol (the scope where the operator interface is declared) instead of the scope where the reduction clause appears. The user-defined reduction is stored in the latter (a child scope), so the lookup in the operator's owning scope could not find it and the clause was reported as invalid.
Look up the reduction in the scope of the clause via context_.FindScope(source). FindUserReduction already searches enclosing scopes, so this both finds a locally declared reduction and continues to find one that is host- or use-associated. The lowering side already resolves the reduction in the current scope, so no lowering change is needed.
This is a follow-up of PR #202474.
>From d53b630413cd1e690f0a69c266184ef0c6a828d5 Mon Sep 17 00:00:00 2001
From: Carlos Seo <carlos.seo at linaro.org>
Date: Thu, 2 Jul 2026 21:53:06 -0300
Subject: [PATCH] [flang][OpenMP] Fix host-associated user-defined operator
reduction
A DECLARE REDUCTION for a user-defined operator (e.g.
reduction(.myadd.:x)) was rejected with "Invalid reduction operator in
REDUCTION clause" when the operator was host-associated.
CheckReductionOperator looked up the mangled reduction name in the scope
that owns the operator symbol (the scope where the operator interface is
declared) instead of the scope where the reduction clause appears. The
user-defined reduction is stored in the latter (a child scope), so the
lookup in the operator's owning scope could not find it and the clause
was reported as invalid.
Look up the reduction in the scope of the clause via
context_.FindScope(source). FindUserReduction already searches enclosing
scopes, so this both finds a locally declared reduction and continues to find
one that is host- or use-associated. The lowering side already resolves the
reduction in the current scope, so no lowering change is needed.
This is a follow-up of PR #202474.
---
flang/lib/Semantics/check-omp-structure.cpp | 7 +++-
.../declare-reduction-operator-host-assoc.f90 | 38 +++++++++++++++++++
2 files changed, 44 insertions(+), 1 deletion(-)
create mode 100644 flang/test/Lower/OpenMP/declare-reduction-operator-host-assoc.f90
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 4e514223b388a..02928401a382a 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -3974,7 +3974,12 @@ bool OmpStructureChecker::CheckReductionOperator(
// for that. We mangle those names to store the user details.
if (const auto *definedOp{std::get_if<parser::DefinedOpName>(&dOpr.u)}) {
std::string mangled{MangleDefinedOperator(definedOp->v.symbol->name())};
- const Scope &scope{definedOp->v.symbol->owner()};
+ // Look up the user-defined reduction in the scope where the clause
+ // appears (FindUserReduction searches enclosing scopes for host
+ // association), not in the scope where the operator itself is declared:
+ // the DECLARE REDUCTION may be local to a procedure that host-associates
+ // the operator from an enclosing module or program unit.
+ const Scope &scope{context_.FindScope(source)};
if (FindUserReduction(scope, mangled)) {
return true;
}
diff --git a/flang/test/Lower/OpenMP/declare-reduction-operator-host-assoc.f90 b/flang/test/Lower/OpenMP/declare-reduction-operator-host-assoc.f90
new file mode 100644
index 0000000000000..ea1167e2bbdd4
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-reduction-operator-host-assoc.f90
@@ -0,0 +1,38 @@
+!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
+
+! Test a user-defined operator reduction (reduction(.myadd.:x)) declared in a
+! procedure that host-associates the operator from its enclosing module.
+
+module m
+ interface operator(.myadd.)
+ procedure add_t
+ end interface
+ type t
+ integer :: i
+ end type
+contains
+ function add_t(x, y)
+ type(t), intent(in) :: x, y
+ type(t) :: add_t
+ add_t%i = x%i + y%i
+ end function
+ subroutine s(r, a)
+ type(t) :: r, a(10)
+ integer :: k
+!$omp declare reduction(.myadd.:t:omp_out=omp_out.myadd.omp_in) initializer(omp_priv=t(0))
+ r = t(0)
+!$omp parallel do reduction(.myadd.:r)
+ do k=1,10
+ r = r .myadd. a(k)
+ end do
+ end subroutine
+end module
+
+! The reduction is materialized with a name qualified by the declaring scope
+! (module m, subroutine s), and the clause binds to it.
+
+! CHECK: omp.declare_reduction @[[RED:_QQMmFsop.myadd.]] : !fir.ref<!fir.type<{{.*}}>>
+
+! CHECK-LABEL: func.func @_QMmPs
+! CHECK: omp.wsloop {{.*}}reduction(byref @[[RED]] %{{.*}} -> %{{.*}} : !fir.ref<!fir.type<{{.*}}>>)
+
More information about the flang-commits
mailing list