[flang-commits] [flang] [Flang][OpenMP] Fix crash and IR errors for user-defined reduction on allocatable variables (PR #186765)

via flang-commits flang-commits at lists.llvm.org
Thu Jul 2 00:53:22 PDT 2026


================
@@ -803,6 +804,185 @@ bool ReductionProcessor::processReductionArguments(
                          &redOperator.u)) {
         if (!ReductionProcessor::supportedIntrinsicProcReduction(
                 *reductionIntrinsic)) {
+          if (isByRef) {
+            // create a new declare_reduction for the boxed type, reusing
+            // the existing init and combiner
+            semantics::Symbol *sym = reductionIntrinsic->v.sym();
+            llvm::StringRef baseName = {sym->name().begin(),
+                                        sym->name().size()};
+            mlir::ModuleOp module = builder.getModule();
+            auto existingDecl = module.lookupSymbol<OpType>(baseName);
+            if (!existingDecl) {
+              TODO(currentLocation,
+                   "User-defined reductions on allocatable or pointer "
+                   "variables: cannot find base reduction declaration");
+            }
+
+            std::string byrefName = getReductionName(
+                baseName, builder.getKindMap(), redType, isByRef);
+
+            mlir::Region &existingInitRegion =
+                existingDecl.getInitializerRegion();
+            auto genInitValueCB =
+                [&existingInitRegion](fir::FirOpBuilder &builder,
+                                      mlir::Location loc, mlir::Type elemTy,
+                                      mlir::Value) -> mlir::Value {
+              // unwrap box type to get the scalar element type
+              mlir::Type scalarTy = unwrapSeqOrBoxedType(elemTy);
+              // find a constant-producing op in the existing init region
+              mlir::Operation *constOp = nullptr;
+              existingInitRegion.walk([&](mlir::Operation *op) {
+                if (constOp)
+                  return;
+                if (auto arithConst =
+                        mlir::dyn_cast<mlir::arith::ConstantOp>(op)) {
+                  if (arithConst.getType() == scalarTy)
+                    constOp = op;
+                  return;
+                }
+                if (mlir::isa<fir::StringLitOp>(op)) {
+                  constOp = op;
+                  return;
+                }
+                if (mlir::isa<fir::AddrOfOp>(op)) {
+                  constOp = op;
+                  return;
+                }
+              });
+
+              if (constOp) {
+                mlir::IRMapping mapper;
+                mlir::Value cloned =
+                    builder.clone(*constOp, mapper)->getResult(0);
+                // load if the cloned op produces a reference
+                if (fir::isa_ref_type(cloned.getType()))
+                  cloned = fir::LoadOp::create(builder, loc, cloned);
+                if (cloned.getType() != scalarTy)
+                  cloned = builder.createConvert(loc, scalarTy, cloned);
+                return cloned;
+              }
+              // Fallback: zero-initialize for trivial types.
+              if (fir::isa_integer(scalarTy))
+                return builder.createIntegerConstant(loc, scalarTy, 0);
+              if (mlir::isa<mlir::FloatType>(scalarTy))
+                return builder.createRealConstant(loc, scalarTy,
+                                                  llvm::APFloat(0.0));
----------------
MattPD wrote:

This fallback crashes the compiler for a `real` allocatable reduction whose initializer is not a literal constant. `llvm::APFloat(0.0)` is IEEEdouble, but `scalarTy` is `f32` for default `real`, so `createRealConstant` fails `FloatAttr` verification and aborts.

You can reproduce it by saving this to `t.f90`:

```fortran
program p
  real, allocatable :: a
  integer :: i
  !$omp declare reduction (rmax : real : omp_out = max(omp_out, omp_in)) &
  !$omp&   initializer (omp_priv = omp_orig)
  allocate(a); a = 0.0
  !$omp parallel do reduction(rmax : a)
  do i = 1, 4
    a = max(a, real(i))
  end do
end program
```

and running `flang -fc1 -emit-hlfir -fopenmp -fopenmp-version=45 t.f90`. It aborts with `error: FloatAttr type doesn't match the type implied by its value` inside `createRealConstant`. A constant initializer such as `omp_priv = 0.0` compiles, because the walk finds the `f32` constant and this fallback never runs.

Would building the zero with the target type's own semantics avoid it, for example the double overload `builder.createRealConstant(loc, scalarTy, 0.0)`, or `APFloat(cast<FloatType>(scalarTy).getFloatSemantics(), 0)`?

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


More information about the flang-commits mailing list