[flang-commits] [flang] [Flang][OpenMP] Support declare reduction without initializer (PR #196211)
Tom Eccles via flang-commits
flang-commits at lists.llvm.org
Sun May 17 06:35:40 PDT 2026
================
@@ -4119,18 +4119,95 @@ static ReductionProcessor::GenCombinerCBTy processReductionCombiner(
return genCombinerCB;
}
-// Checks that the reduction type is either a trivial type or a derived type of
-// trivial types.
+/// Recursively initialize components of a derived type variable inline.
+/// For each component:
+/// - If it has an explicit default initializer, use that value.
+/// - If it is itself a derived type with default component initialization,
+/// recurse into its sub-components.
+/// - Otherwise, zero-initialize.
+/// This avoids calling _FortranAInitialize (which is not fully supported on
+/// GPU)
+static void initializeRecordTypeComponents(
+ lower::AbstractConverter &converter, fir::FirOpBuilder &builder,
+ mlir::Location loc, const semantics::DerivedTypeSpec *derivedTypeSpec,
+ mlir::Type type, mlir::Value baseRef, lower::StatementContext &stmtCtx) {
+ mlir::Type derivedTy = fir::unwrapRefType(type);
+ if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(derivedTy))
+ derivedTy = seqTy.getEleTy();
+ auto recTy = mlir::dyn_cast<fir::RecordType>(derivedTy);
+ assert(recTy && "expected RecordType after unwrapping derived type");
+
+ const semantics::Scope *scope = derivedTypeSpec->GetScope();
+ const auto &typeDetails =
+ derivedTypeSpec->typeSymbol().get<semantics::DerivedTypeDetails>();
+
+ for (const auto &compName : typeDetails.componentNames()) {
+ auto it = scope->find(compName);
+ if (it == scope->end())
+ continue;
+ const semantics::Symbol &comp = it->second.get();
+ std::string name = converter.getRecordTypeFieldName(comp);
+ mlir::Type compType = recTy.getType(name);
+ if (!compType)
+ continue;
+
+ auto fieldTy = fir::FieldType::get(builder.getContext());
+ auto field = fir::FieldIndexOp::create(builder, loc, fieldTy, name, recTy,
+ /*typeParams=*/mlir::ValueRange{});
+ auto compRef = fir::CoordinateOp::create(
+ builder, loc, builder.getRefType(compType), baseRef, field.getResult());
+
+ mlir::Value initVal;
+ if (const auto *obj = comp.detailsIf<semantics::ObjectEntityDetails>()) {
+ if (const auto &init = obj->init()) {
+ initVal = fir::getBase(converter.genExprValue(loc, *init, stmtCtx));
+ if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(initVal.getType()))
+ if (refTy.getEleTy() == compType)
+ initVal = fir::LoadOp::create(builder, loc, initVal);
+ } else if (const auto *compDeclType = comp.GetType()) {
+ // Component has no explicit initializer, but its type may have
+ // default component initialization (e.g., type(Point):: center
+ // where Point has x=0.0, y=5.0). Recurse.
+ if (const auto *compDerivedSpec = compDeclType->AsDerived()) {
+ if (compDerivedSpec->HasDefaultInitialization(
+ /*ignoreAllocatable=*/false, /*ignorePointer=*/true)) {
+ initializeRecordTypeComponents(converter, builder, loc,
+ compDerivedSpec, compType, compRef,
+ stmtCtx);
+ continue;
+ }
+ }
+ }
+ }
+ // Components without explicit default initialization are technically
+ // undefined in Fortran. We zero-initialize them rather than leaving
+ // them uninitialized, which is safer for GPU reduction private copies
+ // and consistent with common Fortran implementation practice.
+ if (!initVal)
+ initVal = fir::ZeroOp::create(builder, loc, compType);
+
+ initVal = builder.createConvert(loc, compType, initVal);
+ fir::StoreOp::create(builder, loc, initVal, compRef);
+ }
+}
+
+// Checks that the reduction type is either a trivial type, a fixed-length
+// character type, or a derived type composed of such types.
static bool isSimpleReductionType(mlir::Type reductionType) {
if (fir::isa_trivial(reductionType))
return true;
+ // Fixed-length CHARACTER is not trivial but can be zero-initialized.
+ if (mlir::isa<fir::CharacterType>(reductionType))
+ return true;
----------------
tblah wrote:
Dynamic CHARACTER is not handled correctly. This reproducer leads to an assertion failure:
```
subroutine dyn_char(s, n)
integer, intent(in) :: n
character(len=n) :: s
integer :: i
!$omp declare reduction(char_max: character(len=n): omp_out = max(omp_out, omp_in))
!$omp parallel do reduction(char_max: s)
do i = 1, 4
s = s
end do
end subroutine
```
If it is not going to be supported for now then it should be a TODO message
https://github.com/llvm/llvm-project/pull/196211
More information about the flang-commits
mailing list