24
24
#include " flang/Lower/Todo.h"
25
25
#include " flang/Optimizer/Builder/Character.h"
26
26
#include " flang/Optimizer/Builder/FIRBuilder.h"
27
+ #include " flang/Optimizer/Builder/Runtime/Derived.h"
27
28
#include " flang/Optimizer/Dialect/FIRAttr.h"
28
29
#include " flang/Optimizer/Dialect/FIRDialect.h"
29
30
#include " flang/Optimizer/Dialect/FIROps.h"
30
- #include " flang/Optimizer/Builder/Runtime/Derived.h"
31
31
#include " flang/Optimizer/Support/FIRContext.h"
32
32
#include " flang/Optimizer/Support/FatalError.h"
33
33
#include " flang/Semantics/tools.h"
@@ -588,147 +588,19 @@ getAggregateStore(Fortran::lower::AggregateStoreMap &storeMap,
588
588
// / Build the name for the storage of a global equivalence.
589
589
static std::string mangleGlobalAggregateStore (
590
590
const Fortran::lower::pft::Variable::AggregateStore &st) {
591
- assert (st.isGlobal () && " cannot name local aggregate" );
592
- return Fortran::lower::mangle::mangleName (*st.vars [0 ]);
593
- }
594
-
595
- // In equivalences, 19.5.3.4 point 10 gives rules regarding explicit and default
596
- // initialization interaction. The interpretation of this point is not
597
- // ubiquitous among compilers, but the majority (nag, ifort, nvfortran) accept
598
- // full or partial overlap of explicit init over default init. In case of
599
- // partial overlap, these compiler still apply the default init for the
600
- // components for which the storage is not explicitly initialized.
601
- //
602
- // In the example below, the equivalence storage must be initialized to [3 , 2].
603
- // 3 comes from the explicit init of k, and 2 from part of the deafult init of
604
- // a.
605
- //
606
- // type t
607
- // i = 1
608
- // j = 2
609
- // end type
610
- // type(t), save :: a
611
- // integer, save :: k = 3
612
- // equivalence (a, k)
613
- //
614
-
615
- // / Helper to analyze overlaps between default and explicit initialization in
616
- // / equivalences. \p offset is the current equivalence offset, memIter is the
617
- // / current symbol iterator over the equivalence members. It must point to a
618
- // / member that has default initialization. \p endIter must be the end of the
619
- // / equivalence members iterators. This will tell if the equivalence member \p
620
- // / memIter is fully, partially, or not overlapped by members with explicit
621
- // / initialization.
622
- enum class OverlapWithExplicitInit { None, Partial, Full };
623
- template <typename SymIter>
624
- static OverlapWithExplicitInit analyzeDefaultInitOverlap (std::size_t offset,
625
- SymIter memIter,
626
- SymIter endIter) {
627
- const auto *mem = *memIter;
628
- auto isFullyEquivalencedByExplicitInit = false ;
629
- auto overlapsWithExplicitInit = false ;
630
- if (mem->offset () < offset)
631
- // Explicit initialization was already performed for part of the storage
632
- // that also have default initialization.
633
- overlapsWithExplicitInit = true ;
634
- auto memEnd = mem->offset () + mem->size ();
635
- if (memEnd > offset) {
636
- // The default initialization overlaps storage that has no initialization
637
- // yet. It may have to be taken into account if no further explicit
638
- // initialization overrides it.
639
- auto fullExplicitInitUntil = offset;
640
- for (auto peek = memIter; peek < endIter; ++peek) {
641
- const auto *nextSym = *peek;
642
- if (nextSym->offset () > memEnd)
643
- // Reached the end of the storage that may be default initialized.
644
- break ;
645
- if (const auto *nextDet = nextSym->template detailsIf <
646
- Fortran::semantics::ObjectEntityDetails>())
647
- if (nextDet->init ()) {
648
- // Test there is no gap between the previous explicit init and this
649
- // one.
650
- overlapsWithExplicitInit = true ;
651
- if (nextSym->offset () == fullExplicitInitUntil)
652
- fullExplicitInitUntil = nextSym->offset () + nextSym->size ();
653
- }
654
- }
655
- isFullyEquivalencedByExplicitInit = fullExplicitInitUntil >= memEnd;
656
- } else {
657
- isFullyEquivalencedByExplicitInit = overlapsWithExplicitInit;
658
- }
659
- if (!overlapsWithExplicitInit)
660
- return OverlapWithExplicitInit::None;
661
- if (isFullyEquivalencedByExplicitInit)
662
- return OverlapWithExplicitInit::Full;
663
- return OverlapWithExplicitInit::Partial;
591
+ return Fortran::lower::mangle::mangleName (st.getNamingSymbol ());
664
592
}
665
593
666
594
// / Build the type for the storage of an equivalence.
667
- static mlir::TupleType
595
+ static mlir::Type
668
596
getAggregateType (Fortran::lower::AbstractConverter &converter,
669
597
const Fortran::lower::pft::Variable::AggregateStore &st) {
670
- auto &builder = converter.getFirOpBuilder ();
671
- auto i8Ty = builder.getIntegerType (8 );
672
- llvm::SmallVector<mlir::Type> members;
673
- std::size_t counter = std::get<0 >(st.interval );
674
-
675
- for (auto iter = st.vars .begin (); iter != st.vars .end (); ++iter) {
676
- const auto *mem = *iter;
677
- if (const auto *memDet =
678
- mem->detailsIf <Fortran::semantics::ObjectEntityDetails>()) {
679
- if (mem->offset () > counter) {
680
- fir::SequenceType::Shape len = {
681
- static_cast <fir::SequenceType::Extent>(mem->offset () - counter)};
682
- auto byteTy = builder.getIntegerType (8 );
683
- auto memTy = fir::SequenceType::get (len, byteTy);
684
- members.push_back (memTy);
685
- counter = mem->offset ();
686
- }
687
- if (memDet->init ()) {
688
- auto memTy = converter.genType (*mem);
689
- members.push_back (memTy);
690
- counter = mem->offset () + mem->size ();
691
- } else if (hasDefaultInitialization (*mem)) {
692
- auto overlap = analyzeDefaultInitOverlap (counter, iter, st.vars .end ());
693
- if (overlap == OverlapWithExplicitInit::None) {
694
- if (mem->offset () == counter) {
695
- // No overlap with explicit init on the storage and default init
696
- // not yet performed for this storage. Apply default initialization.
697
- auto memTy = converter.genType (*mem);
698
- members.push_back (memTy);
699
- counter = mem->offset () + mem->size ();
700
- } else {
701
- // It is possible the storage was already default initialized by an
702
- // entity of the same type. The standard mandates in 19.5.3.4 point
703
- // 10 that only one type must provide default initialization for a
704
- // storage. Simply ensure the already default initialized storage
705
- // has the same size.
706
- assert (counter == mem->offset () + mem->size () &&
707
- " bad default init overlap" );
708
- }
709
- } else if (overlap == OverlapWithExplicitInit::Partial) {
710
- // Must interleave pieces of default initialization with explicit init
711
- // to achieve ifort, nvfortran and nag semantics.
712
- TODO (converter.genLocation (mem->name ()),
713
- " overlapping default and explicit initialization in equivalence "
714
- " storage" );
715
- } else {
716
- // The storage if fully covered with explicit initialization, simply
717
- // ignore the default initialization and let explicit initialization
718
- // happen.
719
- assert (overlap == OverlapWithExplicitInit::Full);
720
- }
721
- }
722
- }
723
- }
724
- if (counter < std::get<0 >(st.interval ) + std::get<1 >(st.interval )) {
725
- fir::SequenceType::Shape len = {static_cast <fir::SequenceType::Extent>(
726
- std::get<0 >(st.interval ) + std::get<1 >(st.interval ) - counter)};
727
- auto memTy = fir::SequenceType::get (len, i8Ty);
728
- members.push_back (memTy);
729
- }
730
- return mlir::TupleType::get (builder.getContext (), members);
598
+ if (const auto *initSym = st.getInitialValueSymbol ())
599
+ return converter.genType (*initSym);
600
+ auto byteTy = converter.getFirOpBuilder ().getIntegerType (8 );
601
+ return fir::SequenceType::get (std::get<1 >(st.interval ), byteTy);
731
602
}
603
+
732
604
// / Define a GlobalOp for the storage of a global equivalence described
733
605
// / by \p aggregate. The global is named \p aggName and is created with
734
606
// / the provided \p linkage.
@@ -745,70 +617,21 @@ static fir::GlobalOp defineGlobalAggregateStore(
745
617
assert (aggregate.isGlobal () && " not a global interval" );
746
618
auto &builder = converter.getFirOpBuilder ();
747
619
auto loc = converter.getCurrentLocation ();
748
- auto idxTy = builder.getIndexType ();
749
- mlir::TupleType aggTy = getAggregateType (converter, aggregate);
750
- auto initFunc = [&](fir::FirOpBuilder &builder) {
751
- mlir::Value cb = builder.create <fir::UndefOp>(loc, aggTy);
752
- unsigned tupIdx = 0 ;
753
- std::size_t offset = std::get<0 >(aggregate.interval );
754
- LLVM_DEBUG (llvm::dbgs () << " equivalence {\n " );
755
- for (auto iter = aggregate.vars .begin (); iter != aggregate.vars .end ();
756
- ++iter) {
757
- const auto *mem = *iter;
758
- if (const auto *memDet =
759
- mem->detailsIf <Fortran::semantics::ObjectEntityDetails>()) {
760
- if (mem->offset () > offset) {
761
- ++tupIdx;
762
- offset = mem->offset ();
763
- }
764
- bool applyDefaultInit = false ;
765
- if (hasDefaultInitialization (*mem)) {
766
- auto overlap =
767
- analyzeDefaultInitOverlap (offset, iter, aggregate.vars .end ());
768
- if (overlap == OverlapWithExplicitInit::None) {
769
- if (mem->offset () == offset)
770
- // No explicit init. Not yet default initialized.
771
- applyDefaultInit = true ;
772
- else
773
- // Already default initialized.
774
- assert (offset == mem->offset () + mem->size () &&
775
- " bad default init overlap" );
776
- } else if (overlap == OverlapWithExplicitInit::Partial) {
777
- TODO (converter.genLocation (mem->name ()),
778
- " overlapping default and explicit initialization in "
779
- " equivalence storage" );
780
- } else {
781
- // Explicit inits completely override default init.
782
- assert (overlap == OverlapWithExplicitInit::Full);
783
- }
784
- }
785
- if (memDet->init () || applyDefaultInit) {
786
- LLVM_DEBUG (llvm::dbgs ()
787
- << " offset: " << mem->offset () << " is " << *mem << ' \n ' );
620
+ auto aggTy = getAggregateType (converter, aggregate);
621
+ if (const auto *initSym = aggregate.getInitialValueSymbol ())
622
+ if (const auto *objectDetails =
623
+ initSym->detailsIf <Fortran::semantics::ObjectEntityDetails>())
624
+ if (objectDetails->init ()) {
625
+ auto initFunc = [&](fir::FirOpBuilder &builder) {
788
626
Fortran::lower::StatementContext stmtCtx;
789
- mlir::Value initVal;
790
- if (memDet->init ())
791
- // Explicit initialization.
792
- initVal = fir::getBase (genInitializerExprValue (
793
- converter, loc, memDet->init ().value (), stmtCtx));
794
- else
795
- initVal = genDefaultInitializerValue (
796
- converter, loc, *mem, converter.genType (*mem), stmtCtx);
797
- auto offVal = builder.createIntegerConstant (loc, idxTy, tupIdx);
798
- auto castVal =
799
- builder.createConvert (loc, aggTy.getType (tupIdx), initVal);
800
- cb = builder.create <fir::InsertValueOp>(loc, aggTy, cb, castVal,
801
- offVal);
802
- ++tupIdx;
803
- offset = mem->offset () + mem->size ();
804
- }
627
+ auto initVal = fir::getBase (genInitializerExprValue (
628
+ converter, loc, objectDetails->init ().value (), stmtCtx));
629
+ builder.create <fir::HasValueOp>(loc, initVal);
630
+ };
631
+ return builder.createGlobal (loc, aggTy, aggName,
632
+ /* isConstant=*/ false , initFunc, linkage);
805
633
}
806
- }
807
- LLVM_DEBUG (llvm::dbgs () << " }\n " );
808
- builder.create <fir::HasValueOp>(loc, cb);
809
- };
810
- return builder.createGlobal (loc, aggTy, aggName,
811
- /* isConstant=*/ false , initFunc, linkage);
634
+ return builder.createGlobal (loc, aggTy, aggName, linkage);
812
635
}
813
636
814
637
// / Declare a GlobalOp for the storage of a global equivalence described
@@ -893,8 +716,8 @@ static void instantiateAlias(Fortran::lower::AbstractConverter &converter,
893
716
auto store = getAggregateStore (storeMap, var);
894
717
auto i8Ty = builder.getIntegerType (8 );
895
718
auto i8Ptr = builder.getRefType (i8Ty);
896
- auto offset =
897
- builder. createIntegerConstant ( loc, idxTy, sym.offset () - aliasOffset);
719
+ auto offset = builder. createIntegerConstant (
720
+ loc, idxTy, sym. GetUltimate () .offset () - aliasOffset);
898
721
auto ptr = builder.create <fir::CoordinateOp>(loc, i8Ptr, store,
899
722
mlir::ValueRange{offset});
900
723
auto preAlloc = builder.createConvert (
@@ -983,15 +806,18 @@ getCommonMembersWithInitAliases(const Fortran::semantics::Symbol &common) {
983
806
// common members * common members
984
807
for (const auto &set : common.owner ().equivalenceSets ())
985
808
for (const auto &obj : set) {
986
- if (const auto &details =
987
- obj.symbol .detailsIf <Fortran::semantics::ObjectEntityDetails>()) {
988
- const auto *com = FindCommonBlockContaining (obj.symbol );
989
- if (!details->init () || com != &common)
990
- continue ;
991
- // This is an alias with an init that belongs to the list
992
- if (std::find (members.begin (), members.end (), obj.symbol ) ==
993
- members.end ())
994
- members.emplace_back (obj.symbol );
809
+ if (!obj.symbol .test (Fortran::semantics::Symbol::Flag::CompilerCreated)) {
810
+ if (const auto &details =
811
+ obj.symbol
812
+ .detailsIf <Fortran::semantics::ObjectEntityDetails>()) {
813
+ const auto *com = FindCommonBlockContaining (obj.symbol );
814
+ if (!details->init () || com != &common)
815
+ continue ;
816
+ // This is an alias with an init that belongs to the list
817
+ if (std::find (members.begin (), members.end (), obj.symbol ) ==
818
+ members.end ())
819
+ members.emplace_back (obj.symbol );
820
+ }
995
821
}
996
822
}
997
823
return members;
0 commit comments