[flang-commits] [flang] [flang][OpenMP] Lower multi-type user-defined declare reduction (PR #207494)
via flang-commits
flang-commits at lists.llvm.org
Sat Jul 4 00:22:40 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Matt (MattPD)
<details>
<summary>Changes</summary>
A user-defined declare reduction covering several types silently miscompiled: every listed type bound one type-less omp.declare_reduction op, so a variable of any but the first type ran through an op built for the wrong type (an !fir.ref<f32> reduction on an i32 op, a mismatch the verifier does not catch). This affects all three forms: operator (.op.), named (myred), and a name that shadows an intrinsic (max/min/iand/ior/ieor, the arm added by llvm-project#<!-- -->205893).
Fixes #<!-- -->207489.
Emit one op per listed type and bind each variable to the op for its type. The directive loop threads a per-type instance index across the parallel type, combiner, and initializer lists so each op gets its own element type, combiner, and initializer.
Name every user-reduction op from one canonical source, getScopedUserReductionName: the reduction symbol's ultimate name, qualified with its owning scope, plus a type and by-ref suffix. Both the directive and clause sides call it, so their names cannot drift, and the use-associated cases converge on the source declaration's name. Because the name also carries the owning scope, a same-spelling same-type operator reduction imported from two modules yields two distinct ops rather than colliding on one.
Suffix the type unconditionally, including for a single-type reduction: a conditional suffix would let a multi-type myred's per-type op @<!-- -->_QQFmyred_i32 collide with a single-type reduction literally named myred_i32, silently binding one reduction's clause to the other's combiner.
An allocatable or pointer reduction of a trivial element type is a clean TODO, deferred to the separate boxed-type reduction work in llvm-project#<!-- -->186765; a mode-independent guard (a boxed operand of a trivial element type) keeps it a clean TODO even under -mmlir --force-byref-reduction. Allocatable character and derived-type reductions still lower.
The same helper also lowers use-associated named reductions, including a rename, and use-associated intrinsic-shadowing reductions.
Assisted-by: Claude Opus 4.8, GPT-5.5.
---
Patch is 128.90 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/207494.diff
50 Files Affected:
- (modified) flang/include/flang/Lower/OpenMP.h (+8)
- (modified) flang/include/flang/Lower/Support/ReductionProcessor.h (+11-7)
- (modified) flang/include/flang/Semantics/openmp-utils.h (+18)
- (modified) flang/lib/Lower/Bridge.cpp (+9)
- (modified) flang/lib/Lower/OpenMP/ClauseProcessor.cpp (+15-6)
- (modified) flang/lib/Lower/OpenMP/ClauseProcessor.h (+2-1)
- (modified) flang/lib/Lower/OpenMP/OpenMP.cpp (+191-38)
- (modified) flang/lib/Lower/Support/ReductionProcessor.cpp (+145-70)
- (modified) flang/lib/Semantics/check-omp-structure.cpp (+4-129)
- (modified) flang/lib/Semantics/mod-file.cpp (+21-1)
- (modified) flang/lib/Semantics/openmp-utils.cpp (+139)
- (modified) flang/lib/Semantics/resolve-names-utils.cpp (+5)
- (modified) flang/lib/Semantics/resolve-names-utils.h (+11)
- (added) flang/test/Lower/OpenMP/Todo/declare-reduction-allocatable-trivial.f90 (+33)
- (removed) flang/test/Lower/OpenMP/Todo/declare-reduction-operator-multiple-types.f90 (-38)
- (removed) flang/test/Lower/OpenMP/Todo/declare-reduction-operator-use-assoc.f90 (-36)
- (removed) flang/test/Lower/OpenMP/Todo/multiple-types-declare_reduction.f90 (-51)
- (added) flang/test/Lower/OpenMP/declare-mapper-hermetic.f90 (+38)
- (modified) flang/test/Lower/OpenMP/declare-reduction-character-allocatable.f90 (+2-2)
- (modified) flang/test/Lower/OpenMP/declare-reduction-initializer-component.f90 (+1-1)
- (modified) flang/test/Lower/OpenMP/declare-reduction-initializer-defined-assign.f90 (+1-1)
- (modified) flang/test/Lower/OpenMP/declare-reduction-initializer-rhs-call.f90 (+1-1)
- (modified) flang/test/Lower/OpenMP/declare-reduction-logical-init.f90 (+1-1)
- (added) flang/test/Lower/OpenMP/declare-reduction-name-type-token-collision.f90 (+43)
- (added) flang/test/Lower/OpenMP/declare-reduction-named-renamed.f90 (+38)
- (added) flang/test/Lower/OpenMP/declare-reduction-named-use-assoc.f90 (+37)
- (modified) flang/test/Lower/OpenMP/declare-reduction-no-initializer-intrinsic.f90 (+2-2)
- (added) flang/test/Lower/OpenMP/declare-reduction-operator-collide.f90 (+79)
- (modified) flang/test/Lower/OpenMP/declare-reduction-operator-derived.f90 (+1-1)
- (added) flang/test/Lower/OpenMP/declare-reduction-operator-merged.f90 (+76)
- (added) flang/test/Lower/OpenMP/declare-reduction-operator-multiple-types.f90 (+66)
- (added) flang/test/Lower/OpenMP/declare-reduction-operator-renamed.f90 (+45)
- (added) flang/test/Lower/OpenMP/declare-reduction-operator-separate-combiners.f90 (+106)
- (added) flang/test/Lower/OpenMP/declare-reduction-operator-separate-hermetic.f90 (+56)
- (added) flang/test/Lower/OpenMP/declare-reduction-operator-separate-reexport.f90 (+93)
- (added) flang/test/Lower/OpenMP/declare-reduction-operator-separate-unused-unsupported.f90 (+86)
- (added) flang/test/Lower/OpenMP/declare-reduction-operator-separate.f90 (+162)
- (added) flang/test/Lower/OpenMP/declare-reduction-operator-use-assoc.f90 (+47)
- (modified) flang/test/Lower/OpenMP/declare-reduction-operator.f90 (+1-1)
- (modified) flang/test/Lower/OpenMP/declare-reduction-same-name-different-scope.f90 (+2-2)
- (added) flang/test/Lower/OpenMP/declare-reduction-shadows-intrinsic-multiple-types.f90 (+45)
- (added) flang/test/Lower/OpenMP/declare-reduction-shadows-intrinsic-use-assoc.f90 (+37)
- (modified) flang/test/Lower/OpenMP/declare-reduction-shadows-intrinsic.f90 (+1-1)
- (modified) flang/test/Lower/OpenMP/declare-reduction-target-intrinsic.f90 (+9-9)
- (added) flang/test/Lower/OpenMP/multiple-types-declare_reduction.f90 (+55)
- (modified) flang/test/Lower/OpenMP/omp-declare-reduction-combsub.f90 (+1-2)
- (modified) flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90 (+1-1)
- (modified) flang/test/Lower/OpenMP/omp-declare-reduction-initsub.f90 (+1-1)
- (modified) flang/test/Lower/OpenMP/omp-declare-reduction.f90 (+1-1)
- (added) flang/test/Semantics/OpenMP/declare-reduction-operator-modfile-reexport.f90 (+86)
``````````diff
diff --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h
index 882ebad9071bc..90d0e7010c033 100644
--- a/flang/include/flang/Lower/OpenMP.h
+++ b/flang/include/flang/Lower/OpenMP.h
@@ -105,6 +105,14 @@ void materializeOpenMPDeclareMappers(
Fortran::lower::AbstractConverter &, Fortran::semantics::SemanticsContext &,
const Fortran::semantics::Scope *scope = nullptr);
+// Materialize omp.declare_reduction ops for user-defined operator reduction
+// declarations found in imported modules (separate compilation). If scope
+// is null, materialize for the whole semantics global scope; otherwise, operate
+// recursively starting at scope.
+void materializeOpenMPDeclareReductions(
+ Fortran::lower::AbstractConverter &, Fortran::semantics::SemanticsContext &,
+ const Fortran::semantics::Scope *scope = nullptr);
+
} // namespace lower
} // namespace Fortran
diff --git a/flang/include/flang/Lower/Support/ReductionProcessor.h b/flang/include/flang/Lower/Support/ReductionProcessor.h
index a949da875b3a2..e500d24f52bd0 100644
--- a/flang/include/flang/Lower/Support/ReductionProcessor.h
+++ b/flang/include/flang/Lower/Support/ReductionProcessor.h
@@ -96,15 +96,19 @@ class ReductionProcessor {
const fir::KindMapping &kindMap,
mlir::Type ty, bool isByRef);
- /// Returns the module-unique name of the omp.declare_reduction op that
- /// materializes a user-defined reduction (named or operator). The name is
- /// derived from the reduction symbol's ultimate name, qualified with its
- /// owning scope via AbstractConverter::mangleName, so that reductions with
- /// the same spelling in different modules do not collide. The directive and
- /// clause lowering must both use this to agree on the op's symbol name.
+ /// Returns the module-unique name of the omp.declare_reduction op for a
+ /// user-defined reduction (named or operator). Derived from the reduction
+ /// symbol's ultimate name, qualified with its owning scope via
+ /// AbstractConverter::mangleName so same-spelling reductions in different
+ /// modules do not collide, then suffixed with the reduction type (via
+ /// getReductionName) so a reduction listing several types produces one op per
+ /// type (single-type is N=1). The directive and clause sides must both call
+ /// this with the same unwrapped type and isByRef, since both tokens are part
+ /// of the name, or the names diverge.
static std::string
getScopedUserReductionName(AbstractConverter &converter,
- const semantics::Symbol &reductionSymbol);
+ const semantics::Symbol &reductionSymbol,
+ mlir::Type reductionType, bool isByRef);
/// This function returns the identity value of the operator \p
/// reductionOpName. For example:
diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h
index 75bab5f6cb8ec..6e91ed4019b3d 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -35,6 +35,7 @@
#include <vector>
namespace Fortran::semantics {
+class DeclTypeSpec;
class Scope;
class SemanticsContext;
class Symbol;
@@ -116,6 +117,23 @@ bool IsArrayElement(const parser::OmpObject &object, SemanticsContext *semaCtx);
const Symbol *GetHostSymbol(const Symbol &sym);
+// Resolve a user-defined reduction visible in scope under the mangled name
+// mangledName (e.g. "op.myop." for operator(.myop.), or a named reduction).
+// Follows USE associations, operator renames, private visibility, and merged
+// generics exactly as the OpenMP semantic checks do, returning the found
+// (non-ultimate) reduction symbol, or null if none is visible. When type is
+// non-null, only a reduction that supports that type is accepted (used to
+// disambiguate an operator that carries reductions for several types).
+const Symbol *FindUserReductionSymbol(const Scope &scope,
+ const parser::CharBlock &mangledName, const DeclTypeSpec *type = nullptr);
+
+// Resolve the user-defined reduction associated with the defined-operator
+// symbol operatorSym. Delegates to FindUserReductionSymbol starting from the
+// operator's owning scope with the operator's mangled ("op...") name; type
+// filters by supported type as above.
+const Symbol *FindOperatorUserReductionSymbol(
+ const Symbol &operatorSym, const DeclTypeSpec *type = nullptr);
+
bool IsMapEnteringType(parser::OmpMapType::Value type);
bool IsMapExitingType(parser::OmpMapType::Value type);
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 27fa06362a1a8..1bd92049211c7 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -580,6 +580,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
*this, bridge.getSemanticsContext());
});
+ // Ensure imported OpenMP user-defined operator declare reductions are
+ // materialized at module scope before lowering any reduction clauses that
+ // may reference them (the separate-compilation counterpart of same-file
+ // module reduction lowering).
+ createBuilderOutsideOfFuncOpAndDo([&]() {
+ Fortran::lower::materializeOpenMPDeclareReductions(
+ *this, bridge.getSemanticsContext());
+ });
+
// Create definitions of intrinsic module constants.
createBuilderOutsideOfFuncOpAndDo(
[&]() { createIntrinsicModuleDefinitions(pft); });
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index ee88a24f97263..0d203afc4a168 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -538,7 +538,8 @@ bool ClauseProcessor::processInclusive(
bool ClauseProcessor::processInitializer(
lower::SymMap &symMap, ReductionProcessor::GenInitValueCBTy &genInitValueCB,
- const parser::OmpStylizedInstance *parserInitInstance) const {
+ const parser::OmpStylizedInstance *parserInitInstance,
+ unsigned instanceIdx) const {
if (auto *clause = findUniqueClause<omp::clause::Initializer>()) {
// Extract the typed assignment from the parser-level instance, if
// the initializer is an assignment statement (as opposed to a call).
@@ -553,13 +554,21 @@ bool ClauseProcessor::processInitializer(
assign = &*wrapper->v;
}
}
- genInitValueCB = [&, clause, assign](fir::FirOpBuilder &builder,
- mlir::Location loc, mlir::Type type,
- mlir::Value moldArg,
- mlir::Value privArg) {
+ // A multi-type declare reduction carries one initializer instance per
+ // listed type (parallel to the combiner instances and typeNameList); select
+ // the one for the type being lowered (index instanceIdx). Single-type is
+ // index 0 of one. Capture instanceIdx by value: the callback runs later
+ // (during createDeclareReductionHelper), after this parameter's lifetime
+ // ends.
+ assert(instanceIdx < clause->v.size() &&
+ "initializer instance index out of range");
+ genInitValueCB = [&, clause, assign,
+ instanceIdx](fir::FirOpBuilder &builder,
+ mlir::Location loc, mlir::Type type,
+ mlir::Value moldArg, mlir::Value privArg) {
lower::SymMapScope scope(symMap);
mlir::Value ompPrivVar;
- const StylizedInstance &inst = clause->v.front();
+ const StylizedInstance &inst = clause->v[instanceIdx];
for (const Object &object :
std::get<StylizedInstance::Variables>(inst.t)) {
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
index 1435af3e844e9..61c4db49c3877 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
@@ -97,7 +97,8 @@ class ClauseProcessor {
bool processInitializer(
lower::SymMap &symMap,
ReductionProcessor::GenInitValueCBTy &genInitValueCB,
- const parser::OmpStylizedInstance *parserInitInstance = nullptr) const;
+ const parser::OmpStylizedInstance *parserInitInstance = nullptr,
+ unsigned instanceIdx = 0) const;
bool processMergeable(mlir::omp::MergeableClauseOps &result) const;
bool processNogroup(mlir::omp::NogroupClauseOps &result) const;
bool processNotinbranch(mlir::omp::NotinbranchClauseOps &result) const;
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index d630d825062b7..b18a4f5b34e63 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -42,6 +42,7 @@
#include "flang/Parser/openmp-utils.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Parser/tools.h"
+#include "flang/Semantics/expression.h"
#include "flang/Semantics/openmp-directive-sets.h"
#include "flang/Semantics/openmp-utils.h"
#include "flang/Semantics/tools.h"
@@ -4505,7 +4506,7 @@ genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
static ReductionProcessor::GenCombinerCBTy processReductionCombiner(
lower::AbstractConverter &converter, lower::SymMap &symTable,
- semantics::SemanticsContext &semaCtx, const clause::Combiner &combiner,
+ semantics::SemanticsContext &semaCtx, const StylizedInstance &combinerInst,
const parser::OmpStylizedInstance &parserInst) {
// Extract the typed assignment from the parser-level instance, if
// the combiner is an assignment statement (as opposed to a call).
@@ -4519,7 +4520,11 @@ static ReductionProcessor::GenCombinerCBTy processReductionCombiner(
assign = &*wrapper->v;
}
ReductionProcessor::GenCombinerCBTy genCombinerCB;
- const StylizedInstance &inst = combiner.v.front();
+ // Use the combiner instance for the type currently being lowered (one per
+ // listed type, in typeNameList order): a multi-type declare reduction carries
+ // a distinct stylized instance per type so omp_out/omp_in are re-typed for
+ // each. Single-type is index 0 of one.
+ const StylizedInstance &inst = combinerInst;
semantics::SomeExpr evalExpr = std::get<StylizedInstance::Instance>(inst.t);
genCombinerCB = [&, evalExpr, assign](fir::FirOpBuilder &builder,
@@ -4680,24 +4685,33 @@ static bool isSimpleReductionType(mlir::Type reductionType) {
return false;
}
-// Getting the type from a symbol compared to a DeclSpec is simpler since we do
-// not need to consider derived vs intrinsic types. Semantics is guaranteed to
-// generate these symbols.
+// Compute the reduction's element type from the given combiner instance's
+// stylized declaration symbol (omp_out), without checking whether lowering
+// supports it. A multi-type declare reduction carries one combiner instance per
+// listed type (typeNameList order), so the caller passes the instance for the
+// type being lowered. Shared by getReductionType (same-file, enforces support
+// with a TODO) and materializeOpenMPDeclareReductions (skips an unsupported
+// unused import via isSimpleReductionType instead of aborting the consumer).
+// Getting the type from that symbol compared to the declared type-list (a
+// DeclarationTypeSpec) is simpler since we do not need to consider derived vs
+// intrinsic types. Semantics is guaranteed to generate these symbols.
static mlir::Type
-getReductionType(lower::AbstractConverter &converter,
- const parser::OmpReductionSpecifier &specifier) {
- const auto &combinerExpression =
- std::get<std::optional<parser::OmpCombinerExpression>>(specifier.t)
- .value();
- const parser::OmpStylizedInstance &combinerInstance =
- combinerExpression.v.front();
+computeReductionType(lower::AbstractConverter &converter,
+ const parser::OmpStylizedInstance &combinerInstance) {
const std::list<parser::OmpStylizedDeclaration> &declList =
std::get<std::list<parser::OmpStylizedDeclaration>>(combinerInstance.t);
const parser::OmpStylizedDeclaration &decl = declList.front();
const auto &name = std::get<parser::ObjectName>(decl.var.t);
const auto &symbol = semantics::SymbolRef(*name.symbol);
- mlir::Type reductionType = converter.genType(symbol);
+ return converter.genType(symbol);
+}
+// Return the reduction's element type, emitting a TODO if lowering does not
+// support it.
+static mlir::Type
+getReductionType(lower::AbstractConverter &converter,
+ const parser::OmpStylizedInstance &combinerInstance) {
+ mlir::Type reductionType = computeReductionType(converter, combinerInstance);
if (!isSimpleReductionType(reductionType))
TODO(converter.getCurrentLocation(),
"declare reduction currently only supports trivial types, "
@@ -4733,10 +4747,16 @@ appendCombiner(const parser::OmpDeclareReductionDirective &construct,
llvm_unreachable("Expecting reduction combiner");
}
-static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
- semantics::SemanticsContext &semaCtx,
- lower::pft::Evaluation &eval,
- const parser::OmpDeclareReductionDirective &construct) {
+// Lower a single declare-reduction directive. Serves both same-file lowering
+// (symOpt null) and separate-compilation materialization of an imported
+// reduction (symOpt is the source symbol from
+// materializeOpenMPDeclareReductions, with a fresh SymMap). Mirrors
+// genOpenMPDeclareMapperImpl.
+static void genOpenMPDeclareReductionImpl(
+ lower::AbstractConverter &converter, lower::SymMap &symTable,
+ semantics::SemanticsContext &semaCtx,
+ const parser::OmpDeclareReductionDirective &construct,
+ const semantics::Symbol *symOpt = nullptr) {
if (semaCtx.langOptions().OpenMPSimd)
return;
@@ -4774,6 +4794,10 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
initExpr ? initExpr->v.begin()
: std::list<parser::OmpStylizedInstance>::const_iterator{};
+ // Index of the type currently being lowered within the parallel per-type
+ // lists: typeNameList.v, the clause-level combiner instances (combiner.v),
+ // and the clause-level initializer instances. Single-type is index 0 of one.
+ unsigned instanceIdx = 0;
for (const auto &typeSpec : typeNameList.v) {
(void)typeSpec; // Currently unused
@@ -4781,7 +4805,7 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
"Mismatched combiner instance count");
const parser::OmpStylizedInstance &parserInst = *parserInstIt++;
- mlir::Type reductionType = getReductionType(converter, specifier);
+ mlir::Type reductionType = getReductionType(converter, parserInst);
bool isByRef = ReductionProcessor::doReductionByRef(reductionType);
// Compute the canonical reduction name the same way
// processReductionArguments does.
@@ -4802,41 +4826,54 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
-> std::string {
// Directive side of the user-defined operator reduction
// naming contract (the clause side is in
- // ReductionProcessor::processReductionArguments).
- // opName.v.sym() is the reduction symbol
- // "op<spelling>". Only single-declaration, single-type
- // reductions are supported; otherwise emit a clean
- // TODO.
+ // ReductionProcessor::processReductionArguments). Name
+ // the op via getScopedUserReductionName from the
+ // symbol's ultimate (name, owner) plus the per-type
+ // suffix, byte-identical to the clause reference.
+ // symOpt supplies the source symbol for separate
+ // compilation, else opName.v.sym(). Runs once per
+ // listed type (the enclosing loop walks typeNameList in
+ // lockstep with the per-type combiner/initializer
+ // instances), emitting one op per (operator, type);
+ // single-type is N=1.
const semantics::Symbol &redSym =
- opName.v.sym()->GetUltimate();
+ symOpt ? symOpt->GetUltimate()
+ : opName.v.sym()->GetUltimate();
const auto *userDetails =
redSym.detailsIf<semantics::UserReductionDetails>();
- if (!userDetails || typeNameList.v.size() != 1 ||
- userDetails->GetDeclList().size() != 1 ||
- userDetails->GetTypeList().size() != 1)
+ if (!userDetails)
TODO(converter.getCurrentLocation(),
"OpenMP user-defined operator declare reduction "
- "with multiple declarations or multiple types");
+ "without user reduction details");
return ReductionProcessor::getScopedUserReductionName(
- converter, redSym);
+ converter, redSym, reductionType, isByRef);
},
},
defOp.u);
},
[&](const clause::ProcedureDesignator &pd) -> std::string {
- // Qualify the name with the scope in which the user-defined
- // reduction is declared so that reductions with the same name
- // in different scopes produce distinct omp.declare_reduction ops.
- const semantics::Symbol *sym = pd.v.sym();
- std::string name = sym->name().ToString();
- return converter.mangleName(name, sym->GetUltimate().owner());
+ // Directive side of the named-reduction naming contract (clause
+ // side in ReductionProcessor::processReductionArguments). Name
+ // the op via getScopedUserReductionName from the source symbol's
+ // ultimate (name, owner) plus the per-type suffix, byte-identical
+ // to the clause reference. symOpt supplies the source symbol for
+ // separate compilation, else pd.v.sym(); GetUltimate keeps the
+ // name stable across a plain `use`. reductionType is the declared
+ // element type (already canonical), so unlike the clause side it
+ // needs no namingType normalization.
+ const semantics::Symbol &redSym =
+ (symOpt ? *symOpt : *pd.v.sym()).GetUltimate();
+ return ReductionProcessor::getScopedUserReductionName(
+ converter, redSym, reductionType, isByRef);
},
},
redOp.u);
+ assert(instanceIdx < combiner.v.size() &&
+ "Mismatched combiner instance count");
ReductionProcessor::GenCombinerCBTy genCombinerCB =
- processReductionCombiner(converter, symTable, semaCtx, combiner,
- parserInst);
+ processReductionCombiner(converter, symTable, semaCtx,
+ combiner.v[instanceIdx], parserInst);
const parser::OmpStylizedInstance *parserInitInst = nullptr;
if (initExpr) {
assert(parserInitInstIt != initExpr->v.end() &&
@@ -4860,7 +4897,8 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
ReductionProcessor::GenInitValueCBTy genInitValueCB;
ClauseProcessor cp(converter, semaCtx, clauses);
- if (!cp.processInitializer(symTable, genInitValueCB, parserInitInst)) {
+ if (!cp.processInitializer(symTable, genInitValueCB, parserInitInst,
+ instanceIdx)) {
// No initializer clause provided. Per OpenMP, initialize as
// default-initialized using the shared inline init helper.
const semantics::DerivedTypeSpec *derivedTypeSpec = nullptr;
@@ -4913,9 +4951,22 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
mlir::o...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/207494
More information about the flang-commits
mailing list