[flang-commits] [flang] [flang][OpenMP] Lower multi-type user-defined declare reduction (PR #207494)

Tom Eccles via flang-commits flang-commits at lists.llvm.org
Mon Jul 13 03:55:16 PDT 2026


================
@@ -908,17 +949,47 @@ bool ReductionProcessor::processReductionArguments(
                          &redOperator.u)) {
         if (!ReductionProcessor::supportedIntrinsicProcReduction(
                 *reductionIntrinsic)) {
-          // Custom reductions we can just add to the symbols without
-          // generating the declare reduction op.
+          // A user-defined named reduction (declare reduction(myred: ...)). The
+          // clause references the (possibly USE-associated) reduction symbol;
+          // bind its pre-materialized omp.declare_reduction op instead of
+          // generating a new one.
           semantics::Symbol *sym = reductionIntrinsic->v.sym();
-          // Qualify the name with the scope in which the user-defined
-          // reduction was declared so that reductions with the same name in
-          // different scopes refer to distinct omp.declare_reduction ops.
-          std::string reductionName = getRealName(sym).ToString();
-          reductionName =
-              converter.mangleName(reductionName, sym->GetUltimate().owner());
-          reductionDeclSymbols.push_back(
-              mlir::SymbolRefAttr::get(builder.getContext(), reductionName));
+          if (!sym->GetUltimate()
+                   .detailsIf<semantics::UserReductionDetails>()) {
+            // Not a supported intrinsic proc (checked just above) and not a
+            // user-defined reduction: a clean TODO, never a wrong binding. (A
+            // named reduction reusing an intrinsic spelling such as `max` is
+            // handled by the supportedIntrinsicProcReduction branch, not here.)
+            TODO(currentLocation, "Lowering unrecognised reduction type");
+          }
+          // Name the op from the resolved symbol's scoped ultimate (name,
+          // owner) plus the per-type suffix, byte-identical to the
+          // directive/materializer side, via getScopedUserReductionName.
+          // Reductions of the same spelling in different scopes refer to
+          // distinct ops, and a named reduction listing several types binds the
+          // op for the variable's type instead of colliding on the first type's
+          // op. namingType is the canonical element type (storage wrappers
+          // stripped) so the by-ref suffix matches the directive.
+          std::string reductionName =
+              ReductionProcessor::getScopedUserReductionName(
+                  converter, *sym, namingType, isByRef);
+          mlir::ModuleOp module = builder.getModule();
+          auto existingDecl = module.lookupSymbol<OpType>(reductionName);
+          // The MLIR verifier does not type-check these ops, so this is the
+          // only guard against binding a missing or mismatched declaration
+          // (e.g. a named declare reduction that does not list the variable's
+          // type). Compare unwrapped element types against namingType, the type
+          // the op was named and created from.
+          if (!existingDecl ||
+              fir::unwrapRefType(existingDecl.getType()) !=
+                  fir::unwrapRefType(namingType) ||
+              isBoxedTrivialReduction) {
+            TODO(currentLocation,
+                 "OpenMP user-defined named reduction declaration was not "
+                 "materialized for the variable's type");
----------------
tblah wrote:

Is this really something left unimplemented or is it just a bug?

https://github.com/llvm/llvm-project/pull/207494


More information about the flang-commits mailing list