@@ -125,6 +125,8 @@ static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter,
125
125
llvm::StringRef globalName,
126
126
mlir::StringAttr linkage) {
127
127
fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
128
+ if (fir::GlobalOp global = builder.getNamedGlobal (globalName))
129
+ return global;
128
130
const Fortran::semantics::Symbol &sym = var.getSymbol ();
129
131
mlir::Location loc = converter.genLocation (sym.name ());
130
132
// Resolve potential host and module association before checking that this
@@ -356,6 +358,24 @@ static mlir::Value genDefaultInitializerValue(
356
358
return initialValue;
357
359
}
358
360
361
+ // / Does this global already have an initializer ?
362
+ static bool globalIsInitialized (fir::GlobalOp global) {
363
+ return !global.getRegion ().empty () || global.initVal ();
364
+ }
365
+
366
+ // / Call \p genInit to generate code inside \p global initializer region.
367
+ static void
368
+ createGlobalInitialization (fir::FirOpBuilder &builder, fir::GlobalOp global,
369
+ std::function<void (fir::FirOpBuilder &)> genInit) {
370
+ mlir::Region ®ion = global.getRegion ();
371
+ region.push_back (new mlir::Block);
372
+ mlir::Block &block = region.back ();
373
+ auto insertPt = builder.saveInsertionPoint ();
374
+ builder.setInsertionPointToStart (&block);
375
+ genInit (builder);
376
+ builder.restoreInsertionPoint (insertPt);
377
+ }
378
+
359
379
// / Create the global op and its init if it has one
360
380
static fir::GlobalOp defineGlobal (Fortran::lower::AbstractConverter &converter,
361
381
const Fortran::lower::pft::Variable &var,
@@ -365,96 +385,96 @@ static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
365
385
const Fortran::semantics::Symbol &sym = var.getSymbol ();
366
386
mlir::Location loc = converter.genLocation (sym.name ());
367
387
bool isConst = sym.attrs ().test (Fortran::semantics::Attr::PARAMETER);
368
- fir::GlobalOp global;
388
+ fir::GlobalOp global = builder.getNamedGlobal (globalName);
389
+ if (global && globalIsInitialized (global))
390
+ return global;
391
+ mlir::Type symTy = converter.genType (var);
392
+ if (!global)
393
+ global = builder.createGlobal (loc, symTy, globalName, linkage,
394
+ mlir::Attribute{}, isConst);
369
395
if (Fortran::semantics::IsAllocatableOrPointer (sym)) {
370
- mlir::Type symTy = converter.genType (var);
371
396
const auto *details =
372
397
sym.detailsIf <Fortran::semantics::ObjectEntityDetails>();
373
398
if (details && details->init ()) {
374
399
auto expr = *details->init ();
375
- auto init = [&](fir::FirOpBuilder &b) {
400
+ createGlobalInitialization (builder, global, [&](fir::FirOpBuilder &b) {
376
401
mlir::Value box =
377
402
Fortran::lower::genInitialDataTarget (converter, loc, symTy, expr);
378
403
b.create <fir::HasValueOp>(loc, box);
379
- };
380
- global =
381
- builder.createGlobal (loc, symTy, globalName, isConst, init, linkage);
404
+ });
382
405
} else {
383
406
// Create unallocated/disassociated descriptor if no explicit init
384
- auto init = [&](fir::FirOpBuilder &b) {
407
+ createGlobalInitialization (builder, global, [&](fir::FirOpBuilder &b) {
385
408
mlir::Value box =
386
409
fir::factory::createUnallocatedBox (b, loc, symTy, llvm::None);
387
410
b.create <fir::HasValueOp>(loc, box);
388
- };
389
- global =
390
- builder.createGlobal (loc, symTy, globalName, isConst, init, linkage);
411
+ });
391
412
}
392
413
393
414
} else if (const auto *details =
394
415
sym.detailsIf <Fortran::semantics::ObjectEntityDetails>()) {
395
416
if (details->init ()) {
396
- mlir::Type symTy = converter.genType (var);
397
417
if (fir::isa_char (symTy)) {
398
418
// CHARACTER literal
399
419
if (auto chLit = getCharacterLiteralCopy (details->init ().value ())) {
400
420
mlir::StringAttr init =
401
421
builder.getStringAttr (std::get<std::string>(*chLit));
402
- global = builder.createGlobal (loc, symTy, globalName, linkage, init,
403
- isConst);
422
+ global->setAttr (global.getInitValAttrName (), init);
404
423
} else {
405
424
fir::emitFatalError (loc, " CHARACTER has unexpected initial value" );
406
425
}
407
426
} else {
408
- global = builder.createGlobal (
409
- loc, symTy, globalName, isConst,
410
- [&](fir::FirOpBuilder &builder) {
427
+ createGlobalInitialization (
428
+ builder, global, [&](fir::FirOpBuilder &builder) {
411
429
Fortran::lower::StatementContext stmtCtx (/* prohibited=*/ true );
412
430
fir::ExtendedValue initVal = genInitializerExprValue (
413
431
converter, loc, details->init ().value (), stmtCtx);
414
432
mlir::Value castTo =
415
433
builder.createConvert (loc, symTy, fir::getBase (initVal));
416
434
stmtCtx.finalize ();
417
435
builder.create <fir::HasValueOp>(loc, castTo);
418
- },
419
- linkage);
436
+ });
420
437
}
421
438
} else if (hasDefaultInitialization (sym)) {
422
- mlir::Type symTy = converter.genType (var);
423
- global = builder.createGlobal (
424
- loc, symTy, globalName, isConst,
425
- [&](fir::FirOpBuilder &builder) {
439
+ createGlobalInitialization (
440
+ builder, global, [&](fir::FirOpBuilder &builder) {
426
441
Fortran::lower::StatementContext stmtCtx (/* prohibited=*/ true );
427
442
mlir::Value initVal =
428
443
genDefaultInitializerValue (converter, loc, sym, symTy, stmtCtx);
429
- mlir::Value castTo =
430
- builder.createConvert (loc, symTy, fir::getBase (initVal));
444
+ mlir::Value castTo = builder.createConvert (loc, symTy, initVal);
431
445
stmtCtx.finalize ();
432
446
builder.create <fir::HasValueOp>(loc, castTo);
433
- },
434
- linkage);
447
+ });
435
448
}
436
449
} else if (sym.has <Fortran::semantics::CommonBlockDetails>()) {
437
450
mlir::emitError (loc, " COMMON symbol processed elsewhere" );
438
451
} else {
439
452
TODO (loc, " global" ); // Procedure pointer or something else
440
453
}
441
- // Creates undefined initializer for globals without initialziers
442
- if (!global) {
443
- mlir::Type symTy = converter.genType (var);
444
- global = builder.createGlobal (
445
- loc, symTy, globalName, isConst,
446
- [&](fir::FirOpBuilder &builder) {
454
+ // Creates undefined initializer for globals without initializers
455
+ if (!globalIsInitialized (global))
456
+ createGlobalInitialization (
457
+ builder, global, [&](fir::FirOpBuilder &builder) {
447
458
builder.create <fir::HasValueOp>(
448
459
loc, builder.create <fir::UndefOp>(loc, symTy));
449
- },
450
- linkage);
451
- }
460
+ });
452
461
// Set public visibility to prevent global definition to be optimized out
453
462
// even if they have no initializer and are unused in this compilation unit.
454
463
global.setVisibility (mlir::SymbolTable::Visibility::Public);
455
464
return global;
456
465
}
457
466
467
+ // / Return linkage attribute for \p var.
468
+ static mlir::StringAttr
469
+ getLinkageAttribute (fir::FirOpBuilder &builder,
470
+ const Fortran::lower::pft::Variable &var) {
471
+ if (var.isModuleVariable ())
472
+ return {}; // external linkage
473
+ // Otherwise, the variable is owned by a procedure and must not be visible in
474
+ // other compilation units.
475
+ return builder.createInternalLinkage ();
476
+ }
477
+
458
478
// / Instantiate a global variable. If it hasn't already been processed, add
459
479
// / the global to the ModuleOp as a new uniqued symbol and initialize it with
460
480
// / the correct value. It will be referenced on demand using `fir.addr_of`.
@@ -467,18 +487,13 @@ static void instantiateGlobal(Fortran::lower::AbstractConverter &converter,
467
487
std::string globalName = Fortran::lower::mangle::mangleName (sym);
468
488
mlir::Location loc = converter.genLocation (sym.name ());
469
489
fir::GlobalOp global = builder.getNamedGlobal (globalName);
470
- if (!global) {
471
- if (var.isDeclaration ()) {
472
- // Using a global from a module not defined in this compilation unit.
473
- mlir::StringAttr externalLinkage;
474
- global = declareGlobal (converter, var, globalName, externalLinkage);
475
- } else {
476
- mlir::StringAttr linkage; // external if remains empty.
477
- if (!sym.owner ().IsModule () &&
478
- !Fortran::semantics::FindCommonBlockContaining (sym))
479
- linkage = builder.createInternalLinkage ();
480
- global = defineGlobal (converter, var, globalName, linkage);
481
- }
490
+ mlir::StringAttr linkage = getLinkageAttribute (builder, var);
491
+ if (var.isModuleVariable ()) {
492
+ // A module global was or will be defined when lowering the module. Emit
493
+ // only a declaration if the global does not exist at that point.
494
+ global = declareGlobal (converter, var, globalName, linkage);
495
+ } else {
496
+ global = defineGlobal (converter, var, globalName, linkage);
482
497
}
483
498
auto addrOf = builder.create <fir::AddrOfOp>(loc, global.resultType (),
484
499
global.getSymbol ());
@@ -624,23 +639,27 @@ static fir::GlobalOp defineGlobalAggregateStore(
624
639
StringRef aggName, mlir::StringAttr linkage) {
625
640
assert (aggregate.isGlobal () && " not a global interval" );
626
641
fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
642
+ fir::GlobalOp global = builder.getNamedGlobal (aggName);
643
+ if (global && globalIsInitialized (global))
644
+ return global;
627
645
mlir::Location loc = converter.getCurrentLocation ();
628
646
mlir::Type aggTy = getAggregateType (converter, aggregate);
647
+ if (!global)
648
+ global = builder.createGlobal (loc, aggTy, aggName, linkage);
649
+
629
650
if (const Fortran::semantics::Symbol *initSym =
630
651
aggregate.getInitialValueSymbol ())
631
652
if (const auto *objectDetails =
632
653
initSym->detailsIf <Fortran::semantics::ObjectEntityDetails>())
633
- if (objectDetails->init ()) {
634
- auto initFunc = [&](fir::FirOpBuilder &builder) {
635
- Fortran::lower::StatementContext stmtCtx;
636
- mlir::Value initVal = fir::getBase (genInitializerExprValue (
637
- converter, loc, objectDetails->init ().value (), stmtCtx));
638
- builder.create <fir::HasValueOp>(loc, initVal);
639
- };
640
- return builder.createGlobal (loc, aggTy, aggName,
641
- /* isConstant=*/ false , initFunc, linkage);
642
- }
643
- return builder.createGlobal (loc, aggTy, aggName, linkage);
654
+ if (objectDetails->init ())
655
+ createGlobalInitialization (
656
+ builder, global, [&](fir::FirOpBuilder &builder) {
657
+ Fortran::lower::StatementContext stmtCtx;
658
+ mlir::Value initVal = fir::getBase (genInitializerExprValue (
659
+ converter, loc, objectDetails->init ().value (), stmtCtx));
660
+ builder.create <fir::HasValueOp>(loc, initVal);
661
+ });
662
+ return global;
644
663
}
645
664
646
665
// / Declare a GlobalOp for the storage of a global equivalence described
@@ -656,8 +675,11 @@ static fir::GlobalOp declareGlobalAggregateStore(
656
675
const Fortran::lower::pft::Variable::AggregateStore &aggregate,
657
676
StringRef aggName, mlir::StringAttr linkage) {
658
677
assert (aggregate.isGlobal () && " not a global interval" );
678
+ fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
679
+ if (fir::GlobalOp global = builder.getNamedGlobal (aggName))
680
+ return global;
659
681
mlir::Type aggTy = getAggregateType (converter, aggregate);
660
- return converter. getFirOpBuilder () .createGlobal (loc, aggTy, aggName, linkage);
682
+ return builder .createGlobal (loc, aggTy, aggName, linkage);
661
683
}
662
684
663
685
// / This is an aggregate store for a set of EQUIVALENCED variables. Create the
@@ -672,23 +694,17 @@ instantiateAggregateStore(Fortran::lower::AbstractConverter &converter,
672
694
mlir::Location loc = converter.getCurrentLocation ();
673
695
std::string aggName = mangleGlobalAggregateStore (var.getAggregateStore ());
674
696
if (var.isGlobal ()) {
675
- // The scope of this aggregate is this procedure.
676
- fir::GlobalOp global = builder.getNamedGlobal (aggName);
677
- if (!global) {
678
- auto &aggregate = var.getAggregateStore ();
679
- if (var.isDeclaration ()) {
680
- // Using aggregate from a module not defined in the current
681
- // compilation unit.
682
- mlir::StringAttr externalLinkage;
683
- global = declareGlobalAggregateStore (converter, loc, aggregate, aggName,
684
- externalLinkage);
685
- } else {
686
- // The aggregate is owned by a procedure and must not be
687
- // visible in other compilation units.
688
- mlir::StringAttr internalLinkage = builder.createInternalLinkage ();
689
- global = defineGlobalAggregateStore (converter, aggregate, aggName,
690
- internalLinkage);
691
- }
697
+ fir::GlobalOp global;
698
+ auto &aggregate = var.getAggregateStore ();
699
+ mlir::StringAttr linkage = getLinkageAttribute (builder, var);
700
+ if (var.isModuleVariable ()) {
701
+ // A module global was or will be defined when lowering the module. Emit
702
+ // only a declaration if the global does not exist at that point.
703
+ global = declareGlobalAggregateStore (converter, loc, aggregate, aggName,
704
+ linkage);
705
+ } else {
706
+ global =
707
+ defineGlobalAggregateStore (converter, aggregate, aggName, linkage);
692
708
}
693
709
auto addr = builder.create <fir::AddrOfOp>(loc, global.resultType (),
694
710
global.getSymbol ());
@@ -1709,9 +1725,6 @@ void Fortran::lower::defineModuleVariable(
1709
1725
// Use empty linkage for module variables, which makes them available
1710
1726
// for use in another unit.
1711
1727
mlir::StringAttr externalLinkage;
1712
- // Only define variable owned by this module
1713
- if (var.isDeclaration ())
1714
- return ;
1715
1728
if (!var.isGlobal ())
1716
1729
fir::emitFatalError (converter.genLocation (),
1717
1730
" attempting to lower module variable as local" );
0 commit comments