@@ -347,91 +347,160 @@ genConstantValue(Fortran::lower::AbstractConverter &converter,
347
347
mlir::Location loc,
348
348
const Fortran::lower::SomeExpr &constantExpr);
349
349
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
+
350
427
// Generate a StructureConstructor inlined (returns raw fir.type<T> value,
351
428
// not the address of a global constant).
352
429
static mlir::Value genInlinedStructureCtorLitImpl (
353
430
Fortran::lower::AbstractConverter &converter, mlir::Location loc,
354
431
const Fortran::evaluate::StructureConstructor &ctor, mlir::Type type) {
355
432
fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
356
433
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*/ );
373
434
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
+ }
376
446
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*/ );
380
471
res = builder.create <fir::InsertValueOp>(
381
- loc, recTy, res, initialTarget ,
472
+ loc, parentRecTy, undef, res ,
382
473
builder.getArrayAttr (field.getAttributes ()));
383
- continue ;
384
474
}
475
+ };
385
476
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;
426
494
}
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);
434
496
}
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);
435
504
return res;
436
505
}
437
506
0 commit comments