@@ -347,91 +347,160 @@ genConstantValue(Fortran::lower::AbstractConverter &converter,
347347 mlir::Location loc,
348348 const Fortran::lower::SomeExpr &constantExpr);
349349
350+ static mlir::Value genStructureComponentInit (
351+ Fortran::lower::AbstractConverter &converter, mlir::Location loc,
352+ const Fortran::semantics::Symbol &sym, const Fortran::lower::SomeExpr &expr,
353+ mlir::Value res) {
354+ fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
355+ fir::RecordType recTy = mlir::cast<fir::RecordType>(res.getType ());
356+ std::string name = converter.getRecordTypeFieldName (sym);
357+ mlir::Type componentTy = recTy.getType (name);
358+ auto fieldTy = fir::FieldType::get (recTy.getContext ());
359+ assert (componentTy && " failed to retrieve component" );
360+ // FIXME: type parameters must come from the derived-type-spec
361+ auto field = builder.create <fir::FieldIndexOp>(
362+ loc, fieldTy, name, recTy,
363+ /* typeParams=*/ mlir::ValueRange{} /* TODO*/ );
364+
365+ if (Fortran::semantics::IsAllocatable (sym))
366+ TODO (loc, " allocatable component in structure constructor" );
367+
368+ if (Fortran::semantics::IsPointer (sym)) {
369+ mlir::Value initialTarget =
370+ Fortran::lower::genInitialDataTarget (converter, loc, componentTy, expr);
371+ res = builder.create <fir::InsertValueOp>(
372+ loc, recTy, res, initialTarget,
373+ builder.getArrayAttr (field.getAttributes ()));
374+ return res;
375+ }
376+
377+ if (Fortran::lower::isDerivedTypeWithLenParameters (sym))
378+ TODO (loc, " component with length parameters in structure constructor" );
379+
380+ // Special handling for scalar c_ptr/c_funptr constants. The array constant
381+ // must fall through to genConstantValue() below.
382+ if (Fortran::semantics::IsBuiltinCPtr (sym) && sym.Rank () == 0 &&
383+ (Fortran::evaluate::GetLastSymbol (expr) ||
384+ Fortran::evaluate::IsNullPointer (expr))) {
385+ // Builtin c_ptr and c_funptr have special handling because designators
386+ // and NULL() are handled as initial values for them as an extension
387+ // (otherwise only c_ptr_null/c_funptr_null are allowed and these are
388+ // replaced by structure constructors by semantics, so GetLastSymbol
389+ // returns nothing).
390+
391+ // The Ev::Expr is an initializer that is a pointer target (e.g., 'x' or
392+ // NULL()) that must be inserted into an intermediate cptr record value's
393+ // address field, which ought to be an intptr_t on the target.
394+ mlir::Value addr = fir::getBase (
395+ Fortran::lower::genExtAddrInInitializer (converter, loc, expr));
396+ if (addr.getType ().isa <fir::BoxProcType>())
397+ addr = builder.create <fir::BoxAddrOp>(loc, addr);
398+ assert ((fir::isa_ref_type (addr.getType ()) ||
399+ addr.getType ().isa <mlir::FunctionType>()) &&
400+ " expect reference type for address field" );
401+ assert (fir::isa_derived (componentTy) &&
402+ " expect C_PTR, C_FUNPTR to be a record" );
403+ auto cPtrRecTy = componentTy.cast <fir::RecordType>();
404+ llvm::StringRef addrFieldName = Fortran::lower::builtin::cptrFieldName;
405+ mlir::Type addrFieldTy = cPtrRecTy.getType (addrFieldName);
406+ auto addrField = builder.create <fir::FieldIndexOp>(
407+ loc, fieldTy, addrFieldName, componentTy,
408+ /* typeParams=*/ mlir::ValueRange{});
409+ mlir::Value castAddr = builder.createConvert (loc, addrFieldTy, addr);
410+ auto undef = builder.create <fir::UndefOp>(loc, componentTy);
411+ addr = builder.create <fir::InsertValueOp>(
412+ loc, componentTy, undef, castAddr,
413+ builder.getArrayAttr (addrField.getAttributes ()));
414+ res = builder.create <fir::InsertValueOp>(
415+ loc, recTy, res, addr, builder.getArrayAttr (field.getAttributes ()));
416+ return res;
417+ }
418+
419+ mlir::Value val = fir::getBase (genConstantValue (converter, loc, expr));
420+ assert (!fir::isa_ref_type (val.getType ()) && " expecting a constant value" );
421+ mlir::Value castVal = builder.createConvert (loc, componentTy, val);
422+ res = builder.create <fir::InsertValueOp>(
423+ loc, recTy, res, castVal, builder.getArrayAttr (field.getAttributes ()));
424+ return res;
425+ }
426+
350427// Generate a StructureConstructor inlined (returns raw fir.type<T> value,
351428// not the address of a global constant).
352429static mlir::Value genInlinedStructureCtorLitImpl (
353430 Fortran::lower::AbstractConverter &converter, mlir::Location loc,
354431 const Fortran::evaluate::StructureConstructor &ctor, mlir::Type type) {
355432 fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
356433 auto recTy = type.cast <fir::RecordType>();
357- auto fieldTy = fir::FieldType::get (type.getContext ());
358- mlir::Value res = builder.create <fir::UndefOp>(loc, recTy);
359-
360- for (const auto &[sym, expr] : ctor.values ()) {
361- // Parent components need more work because they do not appear in the
362- // fir.rec type.
363- if (sym->test (Fortran::semantics::Symbol::Flag::ParentComp))
364- TODO (loc, " parent component in structure constructor" );
365-
366- std::string name = converter.getRecordTypeFieldName (sym);
367- mlir::Type componentTy = recTy.getType (name);
368- assert (componentTy && " failed to retrieve component" );
369- // FIXME: type parameters must come from the derived-type-spec
370- auto field = builder.create <fir::FieldIndexOp>(
371- loc, fieldTy, name, type,
372- /* typeParams=*/ mlir::ValueRange{} /* TODO*/ );
373434
374- if (Fortran::semantics::IsAllocatable (sym))
375- TODO (loc, " allocatable component in structure constructor" );
435+ if (!converter.getLoweringOptions ().getLowerToHighLevelFIR ()) {
436+ mlir::Value res = builder.create <fir::UndefOp>(loc, recTy);
437+ for (const auto &[sym, expr] : ctor.values ()) {
438+ // Parent components need more work because they do not appear in the
439+ // fir.rec type.
440+ if (sym->test (Fortran::semantics::Symbol::Flag::ParentComp))
441+ TODO (loc, " parent component in structure constructor" );
442+ res = genStructureComponentInit (converter, loc, sym, expr.value (), res);
443+ }
444+ return res;
445+ }
376446
377- if (Fortran::semantics::IsPointer (sym)) {
378- mlir::Value initialTarget = Fortran::lower::genInitialDataTarget (
379- converter, loc, componentTy, expr.value ());
447+ auto fieldTy = fir::FieldType::get (recTy.getContext ());
448+ mlir::Value res{};
449+ // When the first structure component values belong to some parent type PT
450+ // and the next values belong to a type extension ET, a new undef for ET must
451+ // be created and the previous PT value inserted into it. There may
452+ // be empty parent types in between ET and PT, hence the list and while loop.
453+ auto insertParentValueIntoExtension = [&](mlir::Type typeExtension) {
454+ assert (res && " res must be set" );
455+ llvm::SmallVector<mlir::Type> parentTypes = {typeExtension};
456+ while (true ) {
457+ fir::RecordType last = mlir::cast<fir::RecordType>(parentTypes.back ());
458+ mlir::Type next =
459+ last.getType (0 ); // parent components are first in HLFIR.
460+ if (next != res.getType ())
461+ parentTypes.push_back (next);
462+ else
463+ break ;
464+ }
465+ for (mlir::Type parentType : llvm::reverse (parentTypes)) {
466+ auto undef = builder.create <fir::UndefOp>(loc, parentType);
467+ fir::RecordType parentRecTy = mlir::cast<fir::RecordType>(parentType);
468+ auto field = builder.create <fir::FieldIndexOp>(
469+ loc, fieldTy, parentRecTy.getTypeList ()[0 ].first , parentType,
470+ /* typeParams=*/ mlir::ValueRange{} /* TODO*/ );
380471 res = builder.create <fir::InsertValueOp>(
381- loc, recTy, res, initialTarget ,
472+ loc, parentRecTy, undef, res ,
382473 builder.getArrayAttr (field.getAttributes ()));
383- continue ;
384474 }
475+ };
385476
386- if (Fortran::lower::isDerivedTypeWithLenParameters (sym))
387- TODO (loc, " component with length parameters in structure constructor" );
388-
389- // Special handling for scalar c_ptr/c_funptr constants. The array constant
390- // must fall through to genConstantValue() below.
391- if (Fortran::semantics::IsBuiltinCPtr (sym) && sym->Rank () == 0 &&
392- (Fortran::evaluate::GetLastSymbol (expr.value ()) ||
393- Fortran::evaluate::IsNullPointer (expr.value ()))) {
394- // Builtin c_ptr and c_funptr have special handling because designators
395- // and NULL() are handled as initial values for them as an extension
396- // (otherwise only c_ptr_null/c_funptr_null are allowed and these are
397- // replaced by structure constructors by semantics, so GetLastSymbol
398- // returns nothing).
399-
400- // The Ev::Expr is an initializer that is a pointer target (e.g., 'x' or
401- // NULL()) that must be inserted into an intermediate cptr record value's
402- // address field, which ought to be an intptr_t on the target.
403- mlir::Value addr = fir::getBase (Fortran::lower::genExtAddrInInitializer (
404- converter, loc, expr.value ()));
405- if (addr.getType ().isa <fir::BoxProcType>())
406- addr = builder.create <fir::BoxAddrOp>(loc, addr);
407- assert ((fir::isa_ref_type (addr.getType ()) ||
408- addr.getType ().isa <mlir::FunctionType>()) &&
409- " expect reference type for address field" );
410- assert (fir::isa_derived (componentTy) &&
411- " expect C_PTR, C_FUNPTR to be a record" );
412- auto cPtrRecTy = componentTy.cast <fir::RecordType>();
413- llvm::StringRef addrFieldName = Fortran::lower::builtin::cptrFieldName;
414- mlir::Type addrFieldTy = cPtrRecTy.getType (addrFieldName);
415- auto addrField = builder.create <fir::FieldIndexOp>(
416- loc, fieldTy, addrFieldName, componentTy,
417- /* typeParams=*/ mlir::ValueRange{});
418- mlir::Value castAddr = builder.createConvert (loc, addrFieldTy, addr);
419- auto undef = builder.create <fir::UndefOp>(loc, componentTy);
420- addr = builder.create <fir::InsertValueOp>(
421- loc, componentTy, undef, castAddr,
422- builder.getArrayAttr (addrField.getAttributes ()));
423- res = builder.create <fir::InsertValueOp>(
424- loc, recTy, res, addr, builder.getArrayAttr (field.getAttributes ()));
425- continue ;
477+ const Fortran::semantics::DerivedTypeSpec *curentType = nullptr ;
478+ for (const auto &[sym, expr] : ctor.values ()) {
479+ // This TODO is not needed here anymore, but should be removed in a separate
480+ // patch.
481+ if (sym->test (Fortran::semantics::Symbol::Flag::ParentComp))
482+ TODO (loc, " parent component in structure constructor" );
483+ const Fortran::semantics::DerivedTypeSpec *componentParentType =
484+ sym->owner ().derivedTypeSpec ();
485+ assert (componentParentType && " failed to retrieve component parent type" );
486+ if (!res) {
487+ mlir::Type parentType = converter.genType (*componentParentType);
488+ curentType = componentParentType;
489+ res = builder.create <fir::UndefOp>(loc, parentType);
490+ } else if (*componentParentType != *curentType) {
491+ mlir::Type parentType = converter.genType (*componentParentType);
492+ insertParentValueIntoExtension (parentType);
493+ curentType = componentParentType;
426494 }
427-
428- mlir::Value val =
429- fir::getBase (genConstantValue (converter, loc, expr.value ()));
430- assert (!fir::isa_ref_type (val.getType ()) && " expecting a constant value" );
431- mlir::Value castVal = builder.createConvert (loc, componentTy, val);
432- res = builder.create <fir::InsertValueOp>(
433- loc, recTy, res, castVal, builder.getArrayAttr (field.getAttributes ()));
495+ res = genStructureComponentInit (converter, loc, sym, expr.value (), res);
434496 }
497+
498+ if (!res) // structure constructor for empty type.
499+ return builder.create <fir::UndefOp>(loc, recTy);
500+
501+ // The last component may belong to a parent type.
502+ if (res.getType () != recTy)
503+ insertParentValueIntoExtension (recTy);
435504 return res;
436505}
437506
0 commit comments