[flang-commits] [flang] [flang][lowering] Implement component-wise initialization for derived types (PR #187465)

via flang-commits flang-commits at lists.llvm.org
Mon Mar 23 04:16:05 PDT 2026


================
@@ -812,6 +818,244 @@ mustBeDefaultInitializedAtRuntime(const Fortran::lower::pft::Variable &var) {
   return Fortran::lower::hasDefaultInitialization(sym);
 }
 
+namespace {
+/// Determines if \p sym represents a complex derived type.
+/// A derived type is considered complex if it contains allocatable, pointer,
+/// or procedure pointer components, or nested complex derived types.
+static bool isComplexDerivedType(const Fortran::semantics::Symbol &sym) {
+  const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType();
+  if (!declTy || !declTy->AsDerived())
+    return false;
+  const Fortran::semantics::DerivedTypeSpec &derivedSpec = *declTy->AsDerived();
+  const Fortran::semantics::Scope *scope = derivedSpec.GetScope();
+  if (!scope)
+    return false;
+  const auto &typeDetails =
+      derivedSpec.typeSymbol().get<Fortran::semantics::DerivedTypeDetails>();
+  for (const auto &compName : typeDetails.componentNames()) {
+    auto iter = scope->find(compName);
+    if (iter == scope->cend())
+      continue;
+    const Fortran::semantics::Symbol &compSym = iter->second.get();
+    const auto *objDetails =
+        compSym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
+    const auto *procDetails =
+        compSym.detailsIf<Fortran::semantics::ProcEntityDetails>();
+    if (Fortran::semantics::IsAllocatableOrPointer(compSym)) {
+      return true;
+    } else if (procDetails && procDetails->init().has_value()) {
+      return true;
+    } else if (objDetails && objDetails->init() && compSym.Rank() > 0) {
+      return true;
+    } else if (isComplexDerivedType(compSym)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/// Performs precise, component-wise initialization for \p derivedSpec,
+/// selectively generating IR only for components that require it.
+static void genDerivedTypeComponentInit(
+    Fortran::lower::AbstractConverter &converter, mlir::Location loc,
+    const Fortran::semantics::DerivedTypeSpec &derivedSpec,
+    mlir::Value baseAddr, fir::RecordType recTy) {
+  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+  const Fortran::semantics::Scope *scope = derivedSpec.GetScope();
+  if (!scope)
+    return;
+  const auto &typeDetails =
+      derivedSpec.typeSymbol().get<Fortran::semantics::DerivedTypeDetails>();
+  for (const auto &compName : typeDetails.componentNames()) {
+    auto scopeIter = scope->find(compName);
+    if (scopeIter == scope->cend())
+      continue;
+    const Fortran::semantics::Symbol &compSym = scopeIter->second.get();
+    const auto *objDetails =
+        compSym.detailsIf<Fortran::semantics::ObjectEntityDetails>();
+    const auto *procDetails =
+        compSym.detailsIf<Fortran::semantics::ProcEntityDetails>();
+    // Determine if the component requires initialization.
+    // Dynamic descriptors (pointers/allocatables) and explicitly initialized
+    // entities must be processed.
+    bool needsInit = Fortran::semantics::IsAllocatableOrPointer(compSym) ||
+                     (objDetails && objDetails->init()) ||
+                     (procDetails && procDetails->init().has_value());
+    if (!needsInit && !Fortran::lower::hasDefaultInitialization(compSym))
+      continue;
+    std::string name = converter.getRecordTypeFieldName(compSym);
+    mlir::Type compFirTy = recTy.getType(name);
+    if (!compFirTy)
+      continue;
+    // Compute the memory coordinate of the current component.
+    auto fieldIdx = fir::FieldIndexOp::create(
+        builder, loc, fir::FieldType::get(recTy.getContext()), name, recTy,
+        mlir::ValueRange{});
+    auto compAddr =
+        fir::CoordinateOp::create(builder, loc, builder.getRefType(compFirTy),
+                                  baseAddr, mlir::ValueRange{fieldIdx});
+
+    // Case A: Standard data components (ObjectEntityDetails).
+    if (objDetails) {
+      if (objDetails->init()) {
+        // Subcase A.1: Component has explicit initialization.
+        if (Fortran::semantics::IsPointer(compSym)) {
+          // Subcase A.1.1: Pointer with explicit target.
+          std::string globalName = fir::NameUniquer::doGenerated(
+              (converter.mangleName(derivedSpec) + fir::kNameSeparator + name +
+               fir::kNameSeparator + "init")
+                  .str());
+          fir::GlobalOp global = builder.getNamedGlobal(globalName);
+          if (!global) {
+            global = builder.createGlobal(loc, compFirTy, globalName,
+                                          builder.createInternalLinkage(),
+                                          mlir::Attribute{}, true);
+            createGlobalInitialization(
+                builder, global, [&](fir::FirOpBuilder &b) {
+                  mlir::Value initBox = Fortran::lower::genInitialDataTarget(
+                      converter, loc, compFirTy, *objDetails->init());
+                  fir::HasValueOp::create(b, loc, initBox);
+                });
+          }
+          auto srcAddr = fir::AddrOfOp::create(
+              builder, loc, global.resultType(), global.getSymbol());
+          mlir::Value loadedBox = fir::LoadOp::create(builder, loc, srcAddr);
+          fir::StoreOp::create(builder, loc, loadedBox, compAddr);
+        } else {
+          // Subcase A.1.2: Non-pointer components with explicit initialization.
+          Fortran::lower::StatementContext stmtCtx(/*cleanupProhibited=*/true);
+          if (mlir::isa<fir::SequenceType>(compFirTy)) {
+            std::string globalName = fir::NameUniquer::doGenerated(
+                (converter.mangleName(derivedSpec) + fir::kNameSeparator +
+                 name + fir::kNameSeparator + "arr_init")
+                    .str());
+            fir::GlobalOp global = builder.getNamedGlobal(globalName);
+            if (!global) {
+              const auto &initExpr = objDetails->init().value();
+              cuf::DataAttributeAttr dataAttr = {};
+              global = Fortran::lower::tryCreatingDenseGlobal(
+                  builder, loc, compFirTy, globalName,
+                  builder.createInternalLinkage(), /*isConst=*/true, initExpr,
+                  dataAttr);
+            }
+            if (global) {
+              auto srcAddr = fir::AddrOfOp::create(
+                  builder, loc, global.resultType(), global.getSymbol());
+              fir::CopyOp::create(builder, loc, srcAddr, compAddr,
+                                  /*noOverlap=*/true);
+            } else {
+              Fortran::lower::StatementContext inlineCtx;
+              Fortran::lower::SymMap emptyMap;
+              hlfir::Entity lhs{compAddr};
+              hlfir::Entity rhs = Fortran::lower::convertExprToHLFIR(
+                  loc, converter, objDetails->init().value(), emptyMap,
+                  inlineCtx);
+              hlfir::AssignOp::create(builder, loc, rhs, lhs);
+            }
+          } else {
+            // Scalar component: Evaluate the expression and store directly.
+            fir::ExtendedValue exInitVal = genInitializerExprValue(
+                converter, loc, objDetails->init().value(), stmtCtx);
+            mlir::Value initVal = fir::getBase(exInitVal);
+            if (fir::isa_ref_type(initVal.getType()) &&
+                !fir::isa_ref_type(compFirTy))
+              initVal = fir::LoadOp::create(builder, loc, initVal);
+            mlir::Value castVal =
+                builder.createConvert(loc, compFirTy, initVal);
+            fir::StoreOp::create(builder, loc, castVal, compAddr);
+          }
+        }
+      } else if (Fortran::semantics::IsAllocatableOrPointer(compSym)) {
+        // Subcase A.2: Pointer or allocatable without initialization.
+        // Create deallocated/disassociated value.
+        std::string globalName = fir::NameUniquer::doGenerated(
+            (converter.mangleName(derivedSpec) + fir::kNameSeparator + name +
+             fir::kNameSeparator + "null_box")
+                .str());
+        fir::GlobalOp global = builder.getNamedGlobal(globalName);
+        if (!global) {
+          global = builder.createGlobal(loc, compFirTy, globalName,
+                                        builder.createInternalLinkage(),
+                                        mlir::Attribute{}, true);
+          createGlobalInitialization(
+              builder, global, [&](fir::FirOpBuilder &b) {
+                mlir::Value nullBox = fir::factory::createUnallocatedBox(
+                    b, loc, compFirTy, mlir::ValueRange{});
+                fir::HasValueOp::create(b, loc, nullBox);
+              });
----------------
jeanPerier wrote:

No need to create a global for this IMHO. Descriptor are small enough to keep their creation inlined.

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


More information about the flang-commits mailing list