[flang-commits] [flang] [flang][OpenMP] NFC: Extract intrinsic reduction shadow lookup (PR #218389)
Tom Eccles via flang-commits
flang-commits at lists.llvm.org
Tue Aug 25 03:52:52 PDT 2026
https://github.com/tblah updated https://github.com/llvm/llvm-project/pull/218389
>From 2b0356789055d3687be9621ab84457384d2de063 Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Mon, 24 Aug 2026 13:04:37 +0100
Subject: [PATCH 1/2] [flang][OpenMP] NFC: Extract intrinsic reduction shadow
lookup
Centralize lookup of user-defined reductions that shadow supported
intrinsic procedure reductions. Keep existing behavior while making the
classification available to other OpenMP lowering paths.
This will help with #215997
Assisted-by: Codex
---
.../flang/Lower/Support/ReductionProcessor.h | 8 ++
.../lib/Lower/Support/ReductionProcessor.cpp | 131 ++++++++++--------
2 files changed, 81 insertions(+), 58 deletions(-)
diff --git a/flang/include/flang/Lower/Support/ReductionProcessor.h b/flang/include/flang/Lower/Support/ReductionProcessor.h
index b86cc07159246..fdc1e7320684b 100644
--- a/flang/include/flang/Lower/Support/ReductionProcessor.h
+++ b/flang/include/flang/Lower/Support/ReductionProcessor.h
@@ -33,6 +33,7 @@ namespace lower {
class AbstractConverter;
} // namespace lower
namespace semantics {
+class Scope;
class SemanticsContext;
} // namespace semantics
} // namespace Fortran
@@ -93,6 +94,13 @@ class ReductionProcessor {
static bool
supportedIntrinsicProcReduction(const omp::clause::ProcedureDesignator &pd);
+ /// Find a user-defined reduction that shadows a supported intrinsic
+ /// procedure reduction for \p type in \p scope.
+ static const semantics::Symbol *findUserDefinedReductionForIntrinsic(
+ const semantics::Scope &scope,
+ const omp::clause::ProcedureDesignator &reductionIntrinsic,
+ const semantics::DeclTypeSpec *type);
+
static const semantics::SourceName
getRealName(const semantics::Symbol *symbol);
diff --git a/flang/lib/Lower/Support/ReductionProcessor.cpp b/flang/lib/Lower/Support/ReductionProcessor.cpp
index de6aeefa48fc4..7b502880f50f3 100644
--- a/flang/lib/Lower/Support/ReductionProcessor.cpp
+++ b/flang/lib/Lower/Support/ReductionProcessor.cpp
@@ -195,6 +195,26 @@ bool ReductionProcessor::supportedIntrinsicProcReduction(
return redType;
}
+const semantics::Symbol *
+ReductionProcessor::findUserDefinedReductionForIntrinsic(
+ const semantics::Scope &scope,
+ const omp::clause::ProcedureDesignator &reductionIntrinsic,
+ const semantics::DeclTypeSpec *type) {
+ const semantics::Symbol *symbol = reductionIntrinsic.v.sym();
+ if (!symbol || !type)
+ return nullptr;
+
+ std::string mangledName = "op." + getRealName(symbol).ToString();
+ const semantics::Symbol *reductionSymbol =
+ scope.FindSymbol(parser::CharBlock{mangledName});
+ if (!reductionSymbol)
+ return nullptr;
+
+ const semantics::Symbol &ultimate = reductionSymbol->GetUltimate();
+ const auto *details = ultimate.detailsIf<semantics::UserReductionDetails>();
+ return details && details->SupportsType(*type) ? &ultimate : nullptr;
+}
+
std::string
ReductionProcessor::getReductionName(llvm::StringRef name,
const fir::KindMapping &kindMap,
@@ -1344,70 +1364,65 @@ bool ReductionProcessor::processReductionArguments(
// resolve-names). If one is visible in the current scope and supports
// the variable's type, bind to the omp.declare_reduction op the
// directive materialized for it instead of generating the intrinsic.
- semantics::Symbol *sym = reductionIntrinsic->v.sym();
- std::string mangledName = "op." + getRealName(sym).ToString();
- if (const semantics::Symbol *redSym =
- converter.getCurrentScope().FindSymbol(
- parser::CharBlock{mangledName})) {
- const semantics::Symbol &ultimate = redSym->GetUltimate();
- const semantics::UserReductionDetails *userDetails =
- ultimate.detailsIf<semantics::UserReductionDetails>();
- const semantics::DeclTypeSpec *varType =
- reductionSymbols[idx]->GetUltimate().GetType();
+ const semantics::DeclTypeSpec *varType =
+ reductionSymbols[idx]->GetUltimate().GetType();
+ if (const semantics::Symbol *userReduction =
+ findUserDefinedReductionForIntrinsic(
+ converter.getCurrentScope(), *reductionIntrinsic,
+ varType)) {
+ const semantics::Symbol &ultimate = *userReduction;
// A user-defined reduction shadows the intrinsic only for the types
// it is declared for. If it does not cover this variable's type, the
// user has not redefined the reduction for that type and the
// implicit intrinsic reduction still applies, so fall through to it.
- if (userDetails && varType && userDetails->SupportsType(*varType)) {
- // The user declaration takes precedence over the intrinsic for this
- // type. A declaration listing several types (or several merged
- // declarations) is handled the same way as the operator and named
- // paths: the directive emits one op per type and the variable's
- // type selects the matching per-type name below. A USE-associated
- // shadowing reduction is found by FindSymbol as a use wrapper;
- // naming from its ultimate (name, owner) below binds the source
- // module's op, materialized on demand here for separate
- // compilation, exactly as the named path does. A renamed shadowing
- // intrinsic does not reach here: the renamed name resolves to the
- // intrinsic rather than the user reduction, so semantics rejects
- // the clause with a type-incompatibility error before lowering.
- std::string opName = ReductionProcessor::getScopedUserReductionName(
- converter, ultimate, namingType, isByRef);
- mlir::ModuleOp module = builder.getModule();
- auto existingDecl = module.lookupSymbol<OpType>(opName);
- // Separate compilation: materialize the imported shadowing
- // reduction on demand when its defining module is a mod file, then
- // re-look it up (same-file ops already exist here).
- if (!existingDecl && semaCtx && ultimate.owner().symbol() &&
- ultimate.owner().symbol()->test(
- semantics::Symbol::Flag::ModFile)) {
- Fortran::lower::materializeUserReduction(
- converter, *semaCtx, ultimate, opName, namingType, isByRef);
- existingDecl = module.lookupSymbol<OpType>(opName);
- }
- if (isBoxedTrivialElemReduction) {
- // Trivial-element allocatable/pointer: synthesize the boxed op.
- if (OpType boxedDecl = getOrCreateBoxedUserReduction<OpType>(
- converter, semaCtx, ultimate, redType, currentLocation)) {
- reductionDeclSymbols.push_back(mlir::SymbolRefAttr::get(
- builder.getContext(), boxedDecl.getSymName()));
- ++idx;
- continue;
- }
- }
- if (!existingDecl ||
- fir::unwrapRefType(existingDecl.getType()) !=
- fir::unwrapRefType(namingType) ||
- isBoxedTrivialReduction) {
- TODO(currentLocation,
- "OpenMP user-defined reduction declaration was not "
- "materialized for this type");
+ // The user declaration takes precedence over the intrinsic for this
+ // type. A declaration listing several types (or several merged
+ // declarations) is handled the same way as the operator and named
+ // paths: the directive emits one op per type and the variable's
+ // type selects the matching per-type name below. A USE-associated
+ // shadowing reduction is found by FindSymbol as a use wrapper;
+ // naming from its ultimate (name, owner) below binds the source
+ // module's op, materialized on demand here for separate
+ // compilation, exactly as the named path does. A renamed shadowing
+ // intrinsic does not reach here: the renamed name resolves to the
+ // intrinsic rather than the user reduction, so semantics rejects
+ // the clause with a type-incompatibility error before lowering.
+ std::string opName = ReductionProcessor::getScopedUserReductionName(
+ converter, ultimate, namingType, isByRef);
+ mlir::ModuleOp module = builder.getModule();
+ auto existingDecl = module.lookupSymbol<OpType>(opName);
+ // Separate compilation: materialize the imported shadowing
+ // reduction on demand when its defining module is a mod file, then
+ // re-look it up (same-file ops already exist here).
+ if (!existingDecl && semaCtx && ultimate.owner().symbol() &&
+ ultimate.owner().symbol()->test(
+ semantics::Symbol::Flag::ModFile)) {
+ Fortran::lower::materializeUserReduction(
+ converter, *semaCtx, ultimate, opName, namingType, isByRef);
+ existingDecl = module.lookupSymbol<OpType>(opName);
+ }
+ if (isBoxedTrivialElemReduction) {
+ // Trivial-element allocatable/pointer: synthesize the boxed op.
+ if (OpType boxedDecl = getOrCreateBoxedUserReduction<OpType>(
+ converter, semaCtx, ultimate, redType, currentLocation)) {
+ reductionDeclSymbols.push_back(mlir::SymbolRefAttr::get(
+ builder.getContext(), boxedDecl.getSymName()));
+ ++idx;
+ continue;
}
- reductionDeclSymbols.push_back(mlir::SymbolRefAttr::get(
- builder.getContext(), existingDecl.getSymName()));
- ++idx;
- continue;
}
+ if (!existingDecl ||
+ fir::unwrapRefType(existingDecl.getType()) !=
+ fir::unwrapRefType(namingType) ||
+ isBoxedTrivialReduction) {
+ TODO(currentLocation,
+ "OpenMP user-defined reduction declaration was not "
+ "materialized for this type");
+ }
+ reductionDeclSymbols.push_back(mlir::SymbolRefAttr::get(
+ builder.getContext(), existingDecl.getSymName()));
+ ++idx;
+ continue;
}
redId = getReductionType(*reductionIntrinsic);
>From debc066eb15c91931a5deac6e97dfa25b0cac2c3 Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Tue, 25 Aug 2026 11:52:19 +0100
Subject: [PATCH 2/2] Improve documentation comment
---
flang/include/flang/Lower/Support/ReductionProcessor.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/flang/include/flang/Lower/Support/ReductionProcessor.h b/flang/include/flang/Lower/Support/ReductionProcessor.h
index fdc1e7320684b..bc6e86a729604 100644
--- a/flang/include/flang/Lower/Support/ReductionProcessor.h
+++ b/flang/include/flang/Lower/Support/ReductionProcessor.h
@@ -94,8 +94,9 @@ class ReductionProcessor {
static bool
supportedIntrinsicProcReduction(const omp::clause::ProcedureDesignator &pd);
- /// Find a user-defined reduction that shadows a supported intrinsic
- /// procedure reduction for \p type in \p scope.
+ /// Return the user-defined reduction that processReductionArguments would
+ /// bind instead of \p reductionIntrinsic for \p type in \p scope, or null if
+ /// it would bind the supported intrinsic.
static const semantics::Symbol *findUserDefinedReductionForIntrinsic(
const semantics::Scope &scope,
const omp::clause::ProcedureDesignator &reductionIntrinsic,
More information about the flang-commits
mailing list