Skip to content

Commit 7a5a1a1

Browse files
authored
Merge pull request #1029 from flang-compiler/jpr-update-equivalence-handling
Jpr update equivalence handling
2 parents 53d598b + de404fd commit 7a5a1a1

27 files changed

+891
-665
lines changed

flang/include/flang/Evaluate/initial-image.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class InitialImage {
3030
};
3131

3232
explicit InitialImage(std::size_t bytes) : data_(bytes) {}
33+
InitialImage(InitialImage &&that) = default;
3334

3435
std::size_t size() const { return data_.size(); }
3536

@@ -93,19 +94,17 @@ class InitialImage {
9394

9495
void AddPointer(ConstantSubscript, const Expr<SomeType> &);
9596

96-
void Incorporate(ConstantSubscript, const InitialImage &);
97+
void Incorporate(ConstantSubscript toOffset, const InitialImage &from,
98+
ConstantSubscript fromOffset, ConstantSubscript bytes);
9799

98100
// Conversions to constant initializers
99101
std::optional<Expr<SomeType>> AsConstant(FoldingContext &,
100102
const DynamicType &, const ConstantSubscripts &,
101103
ConstantSubscript offset = 0) const;
102-
std::optional<Expr<SomeType>> AsConstantDataPointer(
103-
const DynamicType &, ConstantSubscript offset = 0) const;
104-
const ProcedureDesignator &AsConstantProcPointer(
104+
std::optional<Expr<SomeType>> AsConstantPointer(
105105
ConstantSubscript offset = 0) const;
106106

107107
friend class AsConstantHelper;
108-
friend class AsConstantDataPointerHelper;
109108

110109
private:
111110
std::vector<char> data_;

flang/include/flang/Lower/PFTBuilder.h

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -392,31 +392,49 @@ struct Variable {
392392
std::size_t aliasOffset{};
393393
};
394394

395+
/// <offset, size> pair
395396
using Interval = std::tuple<std::size_t, std::size_t>;
396397

397398
/// An interval of storage is a contiguous block of memory to be allocated or
398399
/// mapped onto another variable. Aliasing variables will be pointers into
399400
/// interval stores and may overlap each other.
400401
struct AggregateStore {
401-
AggregateStore(Interval &&interval, const Fortran::semantics::Scope &scope,
402-
bool isDeclaration = false)
403-
: interval{std::move(interval)}, scope{&scope}, isDecl{isDeclaration} {}
404-
AggregateStore(
405-
Interval &&interval, const Fortran::semantics::Scope &scope,
406-
const llvm::SmallVector<const semantics::Symbol *> &unorderedVars,
407-
bool isDeclaration = false);
408-
409-
bool isGlobal() const { return vars.size() > 0; }
402+
AggregateStore(Interval &&interval,
403+
const Fortran::semantics::Symbol &namingSym,
404+
bool isDeclaration = false, bool isGlobal = false)
405+
: interval{std::move(interval)}, namingSymbol{&namingSym},
406+
isDecl{isDeclaration}, isGlobalAggregate{isGlobal} {}
407+
AggregateStore(const semantics::Symbol &initialValueSym,
408+
const semantics::Symbol &namingSym,
409+
bool isDeclaration = false, bool isGlobal = false)
410+
: interval{initialValueSym.offset(), initialValueSym.size()},
411+
namingSymbol{&namingSym}, initialValueSymbol{&initialValueSym},
412+
isDecl{isDeclaration}, isGlobalAggregate{isGlobal} {};
413+
414+
bool isGlobal() const { return isGlobalAggregate; }
410415
bool isDeclaration() const { return isDecl; }
411416
/// Get offset of the aggregate inside its scope.
412417
std::size_t getOffset() const { return std::get<0>(interval); }
413-
418+
/// Returns symbols holding the aggregate initial value if any.
419+
const semantics::Symbol *getInitialValueSymbol() const {
420+
return initialValueSymbol;
421+
}
422+
/// Returns the symbol that gives its name to the aggregate.
423+
const semantics::Symbol &getNamingSymbol() const { return *namingSymbol; }
424+
/// Scope to which the aggregates belongs to.
425+
const semantics::Scope &getOwningScope() const {
426+
return getNamingSymbol().owner();
427+
}
428+
/// <offset, size> of the aggregate in its scope.
414429
Interval interval{};
415-
/// scope in which the interval is.
416-
const Fortran::semantics::Scope *scope;
417-
llvm::SmallVector<const semantics::Symbol *> vars{};
430+
/// Symbol that gives its name to the aggregate. Always set by constructor.
431+
const semantics::Symbol *namingSymbol;
432+
/// Compiler generated symbol with the aggregate initial value if any.
433+
const semantics::Symbol *initialValueSymbol = nullptr;
418434
/// Is this a declaration of a storage defined in another scope ?
419435
bool isDecl;
436+
/// Is this a global aggregate ?
437+
bool isGlobalAggregate;
420438
};
421439

422440
explicit Variable(const Fortran::semantics::Symbol &sym, bool global = false,
@@ -464,7 +482,7 @@ struct Variable {
464482
return std::visit(
465483
common::visitors{
466484
[](const Nominal &x) { return &x.symbol->GetUltimate().owner(); },
467-
[](const AggregateStore &agg) { return agg.scope; }},
485+
[](const AggregateStore &agg) { return &agg.getOwningScope(); }},
468486
var);
469487
}
470488

flang/include/flang/Semantics/scope.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ struct EquivalenceObject {
4141
std::optional<ConstantSubscript> substringStart, parser::CharBlock source)
4242
: symbol{symbol}, subscripts{subscripts},
4343
substringStart{substringStart}, source{source} {}
44+
explicit EquivalenceObject(Symbol &symbol)
45+
: symbol{symbol}, source{symbol.name()} {}
4446

4547
bool operator==(const EquivalenceObject &) const;
4648
bool operator<(const EquivalenceObject &) const;

flang/include/flang/Semantics/symbol.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ class Symbol {
497497
LocalityShared, // named in SHARED locality-spec
498498
InDataStmt, // initialized in a DATA statement
499499
InNamelist, // flag is set if the symbol is in Namelist statement
500+
CompilerCreated,
500501
// OpenACC data-sharing attribute
501502
AccPrivate, AccFirstPrivate, AccShared,
502503
// OpenACC data-mapping attribute
@@ -782,7 +783,7 @@ struct SymbolAddressCompare {
782783
}
783784
};
784785

785-
// Symbol comparison is based on the order of cooked source
786+
// Symbol comparison is usually based on the order of cooked source
786787
// stream creation and, when both are from the same cooked source,
787788
// their positions in that cooked source stream.
788789
// Don't use this comparator or OrderedSymbolSet to hold
@@ -794,12 +795,17 @@ struct SymbolSourcePositionCompare {
794795
bool operator()(const MutableSymbolRef &, const MutableSymbolRef &) const;
795796
};
796797

798+
struct SymbolOffsetCompare {
799+
bool operator()(const SymbolRef &, const SymbolRef &) const;
800+
bool operator()(const MutableSymbolRef &, const MutableSymbolRef &) const;
801+
};
802+
797803
using UnorderedSymbolSet = std::set<SymbolRef, SymbolAddressCompare>;
798-
using OrderedSymbolSet = std::set<SymbolRef, SymbolSourcePositionCompare>;
804+
using SourceOrderedSymbolSet = std::set<SymbolRef, SymbolSourcePositionCompare>;
799805

800806
template <typename A>
801-
OrderedSymbolSet OrderBySourcePosition(const A &container) {
802-
OrderedSymbolSet result;
807+
SourceOrderedSymbolSet OrderBySourcePosition(const A &container) {
808+
SourceOrderedSymbolSet result;
803809
for (SymbolRef x : container) {
804810
result.emplace(x);
805811
}

flang/include/flang/Semantics/tools.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ const DeclTypeSpec *FindParentTypeSpec(const DeclTypeSpec &);
5656
const DeclTypeSpec *FindParentTypeSpec(const Scope &);
5757
const DeclTypeSpec *FindParentTypeSpec(const Symbol &);
5858

59+
const EquivalenceSet *FindEquivalenceSet(const Symbol &);
60+
5961
enum class Tristate { No, Yes, Maybe };
6062
inline Tristate ToTristate(bool x) { return x ? Tristate::Yes : Tristate::No; }
6163

@@ -105,14 +107,13 @@ bool IsEventTypeOrLockType(const DerivedTypeSpec *);
105107
bool IsOrContainsEventOrLockComponent(const Symbol &);
106108
bool CanBeTypeBoundProc(const Symbol *);
107109
// Does a non-PARAMETER symbol have explicit initialization with =value or
108-
// =>target in its declaration, or optionally in a DATA statement? (Being
110+
// =>target in its declaration (but not in a DATA statement)? (Being
109111
// ALLOCATABLE or having a derived type with default component initialization
110112
// doesn't count; it must be a variable initialization that implies the SAVE
111113
// attribute, or a derived type component default value.)
112-
bool IsStaticallyInitialized(const Symbol &, bool ignoreDATAstatements = false);
114+
bool HasDeclarationInitializer(const Symbol &);
113115
// Is the symbol explicitly or implicitly initialized in any way?
114-
bool IsInitialized(const Symbol &, bool ignoreDATAstatements = false,
115-
const Symbol *derivedType = nullptr);
116+
bool IsInitialized(const Symbol &, bool ignoreDATAstatements = false);
116117
// Is the symbol a component subject to deallocation or finalization?
117118
bool IsDestructible(const Symbol &, const Symbol *derivedType = nullptr);
118119
bool HasIntrinsicTypeName(const Symbol &);
@@ -330,6 +331,13 @@ enum class ProcedureDefinitionClass {
330331

331332
ProcedureDefinitionClass ClassifyProcedure(const Symbol &);
332333

334+
// Returns a list of storage associations due to EQUIVALENCE in a
335+
// scope; each storage association is a list of symbol references
336+
// in ascending order of scope offset. Note that the scope may have
337+
// more EquivalenceSets than this function's result has storage
338+
// associations; these are closures over equivalences.
339+
std::list<std::list<SymbolRef>> GetStorageAssociations(const Scope &);
340+
333341
// Derived type component iterator that provides a C++ LegacyForwardIterator
334342
// iterator over the Ordered, Direct, Ultimate or Potential components of a
335343
// DerivedTypeSpec. These iterators can be used with STL algorithms

flang/lib/Evaluate/initial-image.cpp

Lines changed: 31 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,14 @@ void InitialImage::AddPointer(
5454
pointers_.emplace(offset, pointer);
5555
}
5656

57-
void InitialImage::Incorporate(
58-
ConstantSubscript offset, const InitialImage &that) {
59-
CHECK(that.pointers_.empty()); // pointers are not allowed in EQUIVALENCE
60-
CHECK(offset + that.size() <= size());
61-
std::memcpy(&data_[offset], &that.data_[0], that.size());
57+
void InitialImage::Incorporate(ConstantSubscript toOffset,
58+
const InitialImage &from, ConstantSubscript fromOffset,
59+
ConstantSubscript bytes) {
60+
CHECK(from.pointers_.empty()); // pointers are not allowed in EQUIVALENCE
61+
CHECK(fromOffset >= 0 && bytes >= 0 &&
62+
static_cast<std::size_t>(fromOffset + bytes) <= from.size());
63+
CHECK(static_cast<std::size_t>(toOffset + bytes) <= size());
64+
std::memcpy(&data_[toOffset], &from.data_[fromOffset], bytes);
6265
}
6366

6467
// Classes used with common::SearchTypes() to (re)construct Constant<> values
@@ -97,26 +100,31 @@ class AsConstantHelper {
97100
const semantics::DerivedTypeSpec &derived{type_.GetDerivedTypeSpec()};
98101
for (auto iter : DEREF(derived.scope())) {
99102
const Symbol &component{*iter.second};
100-
bool isPointer{IsPointer(component)};
101-
if (component.has<semantics::ObjectEntityDetails>() ||
102-
component.has<semantics::ProcEntityDetails>()) {
103-
auto componentType{DynamicType::From(component)};
104-
CHECK(componentType);
103+
bool isProcPtr{IsProcedurePointer(component)};
104+
if (isProcPtr || component.has<semantics::ObjectEntityDetails>()) {
105105
auto at{offset_ + component.offset()};
106-
if (isPointer) {
106+
if (isProcPtr) {
107107
for (std::size_t j{0}; j < elements; ++j, at += stride) {
108-
Result value{image_.AsConstantDataPointer(*componentType, at)};
109-
CHECK(value);
110-
typedValue[j].emplace(component, std::move(*value));
108+
if (Result value{image_.AsConstantPointer(at)}) {
109+
typedValue[j].emplace(component, std::move(*value));
110+
}
111+
}
112+
} else if (IsPointer(component)) {
113+
for (std::size_t j{0}; j < elements; ++j, at += stride) {
114+
if (Result value{image_.AsConstantPointer(at)}) {
115+
typedValue[j].emplace(component, std::move(*value));
116+
}
111117
}
112118
} else {
119+
auto componentType{DynamicType::From(component)};
120+
CHECK(componentType.has_value());
113121
auto componentExtents{GetConstantExtents(context_, component)};
114-
CHECK(componentExtents);
122+
CHECK(componentExtents.has_value());
115123
for (std::size_t j{0}; j < elements; ++j, at += stride) {
116-
Result value{image_.AsConstant(
117-
context_, *componentType, *componentExtents, at)};
118-
CHECK(value);
119-
typedValue[j].emplace(component, std::move(*value));
124+
if (Result value{image_.AsConstant(
125+
context_, *componentType, *componentExtents, at)}) {
126+
typedValue[j].emplace(component, std::move(*value));
127+
}
120128
}
121129
}
122130
}
@@ -159,45 +167,11 @@ std::optional<Expr<SomeType>> InitialImage::AsConstant(FoldingContext &context,
159167
AsConstantHelper{context, type, extents, *this, offset});
160168
}
161169

162-
class AsConstantDataPointerHelper {
163-
public:
164-
using Result = std::optional<Expr<SomeType>>;
165-
using Types = AllTypes;
166-
AsConstantDataPointerHelper(const DynamicType &type,
167-
const InitialImage &image, ConstantSubscript offset = 0)
168-
: type_{type}, image_{image}, offset_{offset} {}
169-
template <typename T> Result Test() {
170-
if (T::category != type_.category()) {
171-
return std::nullopt;
172-
}
173-
if constexpr (T::category != TypeCategory::Derived) {
174-
if (T::kind != type_.kind()) {
175-
return std::nullopt;
176-
}
177-
}
178-
auto iter{image_.pointers_.find(offset_)};
179-
if (iter == image_.pointers_.end()) {
180-
return AsGenericExpr(NullPointer{});
181-
}
182-
return iter->second;
183-
}
184-
185-
private:
186-
const DynamicType &type_;
187-
const InitialImage &image_;
188-
ConstantSubscript offset_;
189-
};
190-
191-
std::optional<Expr<SomeType>> InitialImage::AsConstantDataPointer(
192-
const DynamicType &type, ConstantSubscript offset) const {
193-
return common::SearchTypes(AsConstantDataPointerHelper{type, *this, offset});
194-
}
195-
196-
const ProcedureDesignator &InitialImage::AsConstantProcPointer(
170+
std::optional<Expr<SomeType>> InitialImage::AsConstantPointer(
197171
ConstantSubscript offset) const {
198-
auto iter{pointers_.find(0)};
199-
CHECK(iter != pointers_.end());
200-
return DEREF(std::get_if<ProcedureDesignator>(&iter->second.u));
172+
auto iter{pointers_.find(offset)};
173+
return iter == pointers_.end() ? std::optional<Expr<SomeType>>{}
174+
: iter->second;
201175
}
202176

203177
} // namespace Fortran::evaluate

0 commit comments

Comments
 (0)