@@ -568,6 +568,232 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
568
568
mapSymbolAttributes (converter, var, symMap, stmtCtx);
569
569
}
570
570
571
+ // / Cast an alias address (variable part of an equivalence) to fir.ptr so that
572
+ // / the optimizer is conservative and avoids doing copy elision in assignment
573
+ // / involving equivalenced variables.
574
+ // / TODO: Represent the equivalence aliasing constraint in another way to avoid
575
+ // / pessimizing array assignments involving equivalenced variables.
576
+ static mlir::Value castAliasToPointer (fir::FirOpBuilder &builder,
577
+ mlir::Location loc, mlir::Type aliasType,
578
+ mlir::Value aliasAddr) {
579
+ return builder.createConvert (loc, fir::PointerType::get (aliasType),
580
+ aliasAddr);
581
+ }
582
+
583
+ // ===--------------------------------------------------------------===//
584
+ // COMMON blocks instantiation
585
+ // ===--------------------------------------------------------------===//
586
+
587
+ // / Does any member of the common block has an initializer ?
588
+ static bool
589
+ commonBlockHasInit (const Fortran::semantics::MutableSymbolVector &cmnBlkMems) {
590
+ for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
591
+ if (const auto *memDet =
592
+ mem->detailsIf <Fortran::semantics::ObjectEntityDetails>())
593
+ if (memDet->init ())
594
+ return true ;
595
+ }
596
+ return false ;
597
+ }
598
+
599
+ // / Build a tuple type for a common block based on the common block
600
+ // / members and the common block size.
601
+ // / This type is only needed to build common block initializers where
602
+ // / the initial value is the collection of the member initial values.
603
+ static mlir::TupleType getTypeOfCommonWithInit (
604
+ Fortran::lower::AbstractConverter &converter,
605
+ const Fortran::semantics::MutableSymbolVector &cmnBlkMems,
606
+ std::size_t commonSize) {
607
+ fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
608
+ llvm::SmallVector<mlir::Type> members;
609
+ std::size_t counter = 0 ;
610
+ for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
611
+ if (const auto *memDet =
612
+ mem->detailsIf <Fortran::semantics::ObjectEntityDetails>()) {
613
+ if (mem->offset () > counter) {
614
+ fir::SequenceType::Shape len = {
615
+ static_cast <fir::SequenceType::Extent>(mem->offset () - counter)};
616
+ mlir::IntegerType byteTy = builder.getIntegerType (8 );
617
+ auto memTy = fir::SequenceType::get (len, byteTy);
618
+ members.push_back (memTy);
619
+ counter = mem->offset ();
620
+ }
621
+ if (memDet->init ()) {
622
+ mlir::Type memTy = converter.genType (*mem);
623
+ members.push_back (memTy);
624
+ counter = mem->offset () + mem->size ();
625
+ }
626
+ }
627
+ }
628
+ if (counter < commonSize) {
629
+ fir::SequenceType::Shape len = {
630
+ static_cast <fir::SequenceType::Extent>(commonSize - counter)};
631
+ mlir::IntegerType byteTy = builder.getIntegerType (8 );
632
+ auto memTy = fir::SequenceType::get (len, byteTy);
633
+ members.push_back (memTy);
634
+ }
635
+ return mlir::TupleType::get (builder.getContext (), members);
636
+ }
637
+
638
+ // / Common block members may have aliases. They are not in the common block
639
+ // / member list from the symbol. We need to know about these aliases if they
640
+ // / have initializer to generate the common initializer.
641
+ // / This function takes care of adding aliases with initializer to the member
642
+ // / list.
643
+ static Fortran::semantics::MutableSymbolVector
644
+ getCommonMembersWithInitAliases (const Fortran::semantics::Symbol &common) {
645
+ const auto &commonDetails =
646
+ common.get <Fortran::semantics::CommonBlockDetails>();
647
+ auto members = commonDetails.objects ();
648
+
649
+ // The number and size of equivalence and common is expected to be small, so
650
+ // no effort is given to optimize this loop of complexity equivalenced
651
+ // common members * common members
652
+ for (const Fortran::semantics::EquivalenceSet &set :
653
+ common.owner ().equivalenceSets ())
654
+ for (const Fortran::semantics::EquivalenceObject &obj : set) {
655
+ if (!obj.symbol .test (Fortran::semantics::Symbol::Flag::CompilerCreated)) {
656
+ if (const auto &details =
657
+ obj.symbol
658
+ .detailsIf <Fortran::semantics::ObjectEntityDetails>()) {
659
+ const Fortran::semantics::Symbol *com =
660
+ FindCommonBlockContaining (obj.symbol );
661
+ if (!details->init () || com != &common)
662
+ continue ;
663
+ // This is an alias with an init that belongs to the list
664
+ if (std::find (members.begin (), members.end (), obj.symbol ) ==
665
+ members.end ())
666
+ members.emplace_back (obj.symbol );
667
+ }
668
+ }
669
+ }
670
+ return members;
671
+ }
672
+
673
+ // / Define a global for a common block if it does not already exist in the
674
+ // / mlir module.
675
+ // / There is no "declare" version since there is not a
676
+ // / scope that owns common blocks more that the others. All scopes using
677
+ // / a common block attempts to define it with common linkage.
678
+ static fir::GlobalOp
679
+ defineCommonBlock (Fortran::lower::AbstractConverter &converter,
680
+ const Fortran::semantics::Symbol &common) {
681
+ fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
682
+ std::string commonName = Fortran::lower::mangle::mangleName (common);
683
+ fir::GlobalOp global = builder.getNamedGlobal (commonName);
684
+ if (global)
685
+ return global;
686
+ Fortran::semantics::MutableSymbolVector cmnBlkMems =
687
+ getCommonMembersWithInitAliases (common);
688
+ mlir::Location loc = converter.genLocation (common.name ());
689
+ mlir::IndexType idxTy = builder.getIndexType ();
690
+ mlir::StringAttr linkage = builder.createCommonLinkage ();
691
+ if (!common.name ().size () || !commonBlockHasInit (cmnBlkMems)) {
692
+ // A blank (anonymous) COMMON block must always be initialized to zero.
693
+ // A named COMMON block sans initializers is also initialized to zero.
694
+ // mlir::Vector types must have a strictly positive size, so at least
695
+ // temporarily, force a zero size COMMON block to have one byte.
696
+ const auto sz = static_cast <fir::SequenceType::Extent>(
697
+ common.size () > 0 ? common.size () : 1 );
698
+ fir::SequenceType::Shape shape = {sz};
699
+ mlir::IntegerType i8Ty = builder.getIntegerType (8 );
700
+ auto commonTy = fir::SequenceType::get (shape, i8Ty);
701
+ auto vecTy = mlir::VectorType::get (sz, i8Ty);
702
+ mlir::Attribute zero = builder.getIntegerAttr (i8Ty, 0 );
703
+ auto init = mlir::DenseElementsAttr::get (vecTy, llvm::makeArrayRef (zero));
704
+ return builder.createGlobal (loc, commonTy, commonName, linkage, init);
705
+ }
706
+
707
+ // Named common with initializer, sort members by offset before generating
708
+ // the type and initializer.
709
+ std::sort (cmnBlkMems.begin (), cmnBlkMems.end (),
710
+ [](auto &s1, auto &s2) { return s1->offset () < s2->offset (); });
711
+ mlir::TupleType commonTy =
712
+ getTypeOfCommonWithInit (converter, cmnBlkMems, common.size ());
713
+ auto initFunc = [&](fir::FirOpBuilder &builder) {
714
+ mlir::Value cb = builder.create <fir::UndefOp>(loc, commonTy);
715
+ unsigned tupIdx = 0 ;
716
+ std::size_t offset = 0 ;
717
+ LLVM_DEBUG (llvm::dbgs () << " block {\n " );
718
+ for (const Fortran::semantics::MutableSymbolRef &mem : cmnBlkMems) {
719
+ if (const auto *memDet =
720
+ mem->detailsIf <Fortran::semantics::ObjectEntityDetails>()) {
721
+ if (mem->offset () > offset) {
722
+ ++tupIdx;
723
+ offset = mem->offset ();
724
+ }
725
+ if (memDet->init ()) {
726
+ LLVM_DEBUG (llvm::dbgs ()
727
+ << " offset: " << mem->offset () << " is " << *mem << ' \n ' );
728
+ Fortran::lower::StatementContext stmtCtx;
729
+ auto initExpr = memDet->init ().value ();
730
+ fir::ExtendedValue initVal =
731
+ Fortran::semantics::IsPointer (*mem)
732
+ ? Fortran::lower::genInitialDataTarget (
733
+ converter, loc, converter.genType (*mem), initExpr)
734
+ : genInitializerExprValue (converter, loc, initExpr, stmtCtx);
735
+ mlir::IntegerAttr offVal = builder.getIntegerAttr (idxTy, tupIdx);
736
+ mlir::Value castVal = builder.createConvert (
737
+ loc, commonTy.getType (tupIdx), fir::getBase (initVal));
738
+ cb = builder.create <fir::InsertValueOp>(loc, commonTy, cb, castVal,
739
+ builder.getArrayAttr (offVal));
740
+ ++tupIdx;
741
+ offset = mem->offset () + mem->size ();
742
+ }
743
+ }
744
+ }
745
+ LLVM_DEBUG (llvm::dbgs () << " }\n " );
746
+ builder.create <fir::HasValueOp>(loc, cb);
747
+ };
748
+ // create the global object
749
+ return builder.createGlobal (loc, commonTy, commonName,
750
+ /* isConstant=*/ false , initFunc);
751
+ }
752
+ // / The COMMON block is a global structure. `var` will be at some offset
753
+ // / within the COMMON block. Adds the address of `var` (COMMON + offset) to
754
+ // / the symbol map.
755
+ static void instantiateCommon (Fortran::lower::AbstractConverter &converter,
756
+ const Fortran::semantics::Symbol &common,
757
+ const Fortran::lower::pft::Variable &var,
758
+ Fortran::lower::SymMap &symMap) {
759
+ fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
760
+ const Fortran::semantics::Symbol &varSym = var.getSymbol ();
761
+ mlir::Location loc = converter.genLocation (varSym.name ());
762
+
763
+ mlir::Value commonAddr;
764
+ if (Fortran::lower::SymbolBox symBox = symMap.lookupSymbol (common))
765
+ commonAddr = symBox.getAddr ();
766
+ if (!commonAddr) {
767
+ // introduce a local AddrOf and add it to the map
768
+ fir::GlobalOp global = defineCommonBlock (converter, common);
769
+ commonAddr = builder.create <fir::AddrOfOp>(loc, global.resultType (),
770
+ global.getSymbol ());
771
+
772
+ symMap.addSymbol (common, commonAddr);
773
+ }
774
+ std::size_t byteOffset = varSym.GetUltimate ().offset ();
775
+ mlir::IntegerType i8Ty = builder.getIntegerType (8 );
776
+ mlir::Type i8Ptr = builder.getRefType (i8Ty);
777
+ mlir::Type seqTy = builder.getRefType (builder.getVarLenSeqTy (i8Ty));
778
+ mlir::Value base = builder.createConvert (loc, seqTy, commonAddr);
779
+ mlir::Value offs =
780
+ builder.createIntegerConstant (loc, builder.getIndexType (), byteOffset);
781
+ auto varAddr = builder.create <fir::CoordinateOp>(loc, i8Ptr, base,
782
+ mlir::ValueRange{offs});
783
+ mlir::Type symType = converter.genType (var.getSymbol ());
784
+ mlir::Value local;
785
+ if (Fortran::semantics::FindEquivalenceSet (var.getSymbol ()) != nullptr )
786
+ local = castAliasToPointer (builder, loc, symType, varAddr);
787
+ else
788
+ local = builder.createConvert (loc, builder.getRefType (symType), varAddr);
789
+ Fortran::lower::StatementContext stmtCtx;
790
+ mapSymbolAttributes (converter, var, symMap, stmtCtx, local);
791
+ }
792
+
793
+ // ===--------------------------------------------------------------===//
794
+ // Lower Variables specification expressions and attributes
795
+ // ===--------------------------------------------------------------===//
796
+
571
797
// / Helper to decide if a dummy argument must be tracked in an BoxValue.
572
798
static bool lowerToBoxValue (const Fortran::semantics::Symbol &sym,
573
799
mlir::Value dummyArg) {
@@ -1197,9 +1423,10 @@ void Fortran::lower::defineModuleVariable(
1197
1423
TODO (loc, " defineModuleVariable aggregateStore" );
1198
1424
}
1199
1425
const Fortran::semantics::Symbol &sym = var.getSymbol ();
1200
- if (Fortran::semantics::FindCommonBlockContaining (var.getSymbol ())) {
1201
- const mlir::Location loc = converter.genLocation (sym.name ());
1202
- TODO (loc, " defineModuleVariable common block" );
1426
+ if (const Fortran::semantics::Symbol *common =
1427
+ Fortran::semantics::FindCommonBlockContaining (var.getSymbol ())) {
1428
+ // Define common block containing the variable.
1429
+ defineCommonBlock (converter, *common);
1203
1430
} else if (var.isAlias ()) {
1204
1431
// Do nothing. Mapping will be done on user side.
1205
1432
} else {
@@ -1216,9 +1443,10 @@ void Fortran::lower::instantiateVariable(AbstractConverter &converter,
1216
1443
const mlir::Location loc = converter.genLocation (sym.name ());
1217
1444
if (var.isAggregateStore ()) {
1218
1445
TODO (loc, " instantiateVariable AggregateStore" );
1219
- } else if (Fortran::semantics::FindCommonBlockContaining (
1220
- var.getSymbol ().GetUltimate ())) {
1221
- TODO (loc, " instantiateVariable Common" );
1446
+ } else if (const Fortran::semantics::Symbol *common =
1447
+ Fortran::semantics::FindCommonBlockContaining (
1448
+ var.getSymbol ().GetUltimate ())) {
1449
+ instantiateCommon (converter, *common, var, symMap);
1222
1450
} else if (var.isAlias ()) {
1223
1451
TODO (loc, " instantiateVariable Alias" );
1224
1452
} else if (var.isGlobal ()) {
0 commit comments