Skip to content

Commit c67feed

Browse files
committed
[flang] Add general symbol dependence collection utility
Replace HarvestSymbolsNeededFromOtherModules() in mod-file.cpp with a general utility function in Semantics. This new code will find other uses in further rework of hermetic module file generation as the means by which the necessary subsets of symbols in dependency modules are collected.
1 parent fd7e46b commit c67feed

File tree

7 files changed

+234
-72
lines changed

7 files changed

+234
-72
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===-- include/flang/Semantics/symbol-set-closure.h ------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef FORTRAN_SEMANTICS_SYMBOLS_SET_CLOSURE_H_
10+
#define FORTRAN_SEMANTICS_SYMBOLS_SET_CLOSURE_H_
11+
12+
#include "flang/Semantics/symbol.h"
13+
14+
namespace Fortran::semantics {
15+
16+
// For a set or scope of symbols, computes the transitive closure of their
17+
// dependences due to their types, bounds, specific procedures, interfaces,
18+
// initialization, storage association, &c. Includes the original symbol
19+
// or members of the original set. Does not include dependences from
20+
// subprogram definitions, only their interfaces.
21+
enum DependenceCollectionFlags {
22+
NoDependenceCollectionFlags = 0,
23+
IncludeOriginalSymbols = 1 << 0,
24+
FollowUseAssociations = 1 << 1,
25+
IncludeSpecificsOfGenerics = 1 << 2,
26+
IncludeComponentsInExprs = 1 << 3,
27+
};
28+
UnorderedSymbolSet CollectAllDependences(const UnorderedSymbolSet &,
29+
enum DependenceCollectionFlags = NoDependenceCollectionFlags);
30+
UnorderedSymbolSet CollectAllDependences(const Scope &,
31+
enum DependenceCollectionFlags = NoDependenceCollectionFlags);
32+
33+
} // namespace Fortran::semantics
34+
#endif // FORTRAN_SEMANTICS_SYMBOLS_SET_CLOSURE_H_

flang/lib/Semantics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ add_flang_library(FortranSemantics
4646
scope.cpp
4747
semantics.cpp
4848
symbol.cpp
49+
symbol-set-closure.cpp
4950
tools.cpp
5051
type.cpp
5152
unparse-with-symbols.cpp

flang/lib/Semantics/mod-file.cpp

Lines changed: 4 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "flang/Parser/unparse.h"
1616
#include "flang/Semantics/scope.h"
1717
#include "flang/Semantics/semantics.h"
18+
#include "flang/Semantics/symbol-set-closure.h"
1819
#include "flang/Semantics/symbol.h"
1920
#include "flang/Semantics/tools.h"
2021
#include "llvm/Support/FileSystem.h"
@@ -223,71 +224,10 @@ std::string ModFileWriter::GetAsString(const Symbol &symbol) {
223224
// Collect symbols from constant and specification expressions that are being
224225
// referenced directly from other modules; they may require new USE
225226
// associations.
226-
static void HarvestSymbolsNeededFromOtherModules(
227-
SourceOrderedSymbolSet &, const Scope &);
228-
static void HarvestSymbolsNeededFromOtherModules(
229-
SourceOrderedSymbolSet &set, const Symbol &symbol, const Scope &scope) {
230-
auto HarvestBound{[&](const Bound &bound) {
231-
if (const auto &expr{bound.GetExplicit()}) {
232-
for (SymbolRef ref : evaluate::CollectSymbols(*expr)) {
233-
set.emplace(*ref);
234-
}
235-
}
236-
}};
237-
auto HarvestShapeSpec{[&](const ShapeSpec &shapeSpec) {
238-
HarvestBound(shapeSpec.lbound());
239-
HarvestBound(shapeSpec.ubound());
240-
}};
241-
auto HarvestArraySpec{[&](const ArraySpec &arraySpec) {
242-
for (const auto &shapeSpec : arraySpec) {
243-
HarvestShapeSpec(shapeSpec);
244-
}
245-
}};
246-
247-
if (symbol.has<DerivedTypeDetails>()) {
248-
if (symbol.scope()) {
249-
HarvestSymbolsNeededFromOtherModules(set, *symbol.scope());
250-
}
251-
} else if (const auto &generic{symbol.detailsIf<GenericDetails>()};
252-
generic && generic->derivedType()) {
253-
const Symbol &dtSym{*generic->derivedType()};
254-
if (dtSym.has<DerivedTypeDetails>()) {
255-
if (dtSym.scope()) {
256-
HarvestSymbolsNeededFromOtherModules(set, *dtSym.scope());
257-
}
258-
} else {
259-
CHECK(dtSym.has<UseDetails>() || dtSym.has<UseErrorDetails>());
260-
}
261-
} else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
262-
HarvestArraySpec(object->shape());
263-
HarvestArraySpec(object->coshape());
264-
if (IsNamedConstant(symbol) || scope.IsDerivedType()) {
265-
if (object->init()) {
266-
for (SymbolRef ref : evaluate::CollectSymbols(*object->init())) {
267-
set.emplace(*ref);
268-
}
269-
}
270-
}
271-
} else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) {
272-
if (proc->init() && *proc->init() && scope.IsDerivedType()) {
273-
set.emplace(**proc->init());
274-
}
275-
} else if (const auto *subp{symbol.detailsIf<SubprogramDetails>()}) {
276-
for (const Symbol *dummy : subp->dummyArgs()) {
277-
if (dummy) {
278-
HarvestSymbolsNeededFromOtherModules(set, *dummy, scope);
279-
}
280-
}
281-
if (subp->isFunction()) {
282-
HarvestSymbolsNeededFromOtherModules(set, subp->result(), scope);
283-
}
284-
}
285-
}
286-
287227
static void HarvestSymbolsNeededFromOtherModules(
288228
SourceOrderedSymbolSet &set, const Scope &scope) {
289-
for (const auto &[_, symbol] : scope) {
290-
HarvestSymbolsNeededFromOtherModules(set, *symbol, scope);
229+
for (const Symbol &symbol : CollectAllDependences(scope)) {
230+
set.insert(symbol);
291231
}
292232
}
293233

@@ -369,7 +309,7 @@ void ModFileWriter::PutSymbols(
369309
PrepareRenamings(scope);
370310
SourceOrderedSymbolSet modules;
371311
CollectSymbols(scope, sorted, uses, modules);
372-
// Write module files for dependencies first so that their
312+
// Write module files for dependences first so that their
373313
// hashes are known.
374314
for (const Symbol &mod : modules) {
375315
if (hermeticModules) {

flang/lib/Semantics/resolve-names.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7416,7 +7416,8 @@ void DeclarationVisitor::SetType(
74167416
std::optional<DerivedTypeSpec> DeclarationVisitor::ResolveDerivedType(
74177417
const parser::Name &name) {
74187418
Scope &outer{NonDerivedTypeScope()};
7419-
Symbol *symbol{FindSymbol(outer, name)};
7419+
Symbol *original{FindSymbol(outer, name)};
7420+
Symbol *symbol{original};
74207421
Symbol *ultimate{symbol ? &symbol->GetUltimate() : nullptr};
74217422
auto *generic{ultimate ? ultimate->detailsIf<GenericDetails>() : nullptr};
74227423
if (generic) {
@@ -7429,11 +7430,12 @@ std::optional<DerivedTypeSpec> DeclarationVisitor::ResolveDerivedType(
74297430
(generic && &ultimate->owner() == &outer)) {
74307431
if (allowForwardReferenceToDerivedType()) {
74317432
if (!symbol) {
7432-
symbol = &MakeSymbol(outer, name.source, Attrs{});
7433+
symbol = original = &MakeSymbol(outer, name.source, Attrs{});
74337434
Resolve(name, *symbol);
74347435
} else if (generic) {
74357436
// forward ref to type with later homonymous generic
7436-
symbol = &outer.MakeSymbol(name.source, Attrs{}, UnknownDetails{});
7437+
symbol = original =
7438+
&outer.MakeSymbol(name.source, Attrs{}, UnknownDetails{});
74377439
generic->set_derivedType(*symbol);
74387440
name.symbol = symbol;
74397441
}
@@ -7453,7 +7455,7 @@ std::optional<DerivedTypeSpec> DeclarationVisitor::ResolveDerivedType(
74537455
if (CheckUseError(name)) {
74547456
return std::nullopt;
74557457
} else if (symbol->GetUltimate().has<DerivedTypeDetails>()) {
7456-
return DerivedTypeSpec{name.source, *symbol};
7458+
return DerivedTypeSpec{name.source, *original};
74577459
} else {
74587460
Say(name, "'%s' is not a derived type"_err_en_US);
74597461
return std::nullopt;
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
//===-- lib/Semantics/symbol-set-closure.cpp ------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "flang/Semantics/symbol-set-closure.h"
10+
#include "flang/Common/idioms.h"
11+
#include "flang/Common/visit.h"
12+
13+
namespace Fortran::semantics {
14+
15+
class Collector {
16+
public:
17+
explicit Collector(enum DependenceCollectionFlags flags) : flags_{flags} {}
18+
19+
UnorderedSymbolSet Collected() { return std::move(set_); }
20+
21+
void operator()(const Symbol &x) { set_.insert(x); }
22+
void operator()(SymbolRef x) { (*this)(*x); }
23+
template <typename A> void operator()(const std::optional<A> &x) {
24+
if (x) {
25+
(*this)(*x);
26+
}
27+
}
28+
template <typename A> void operator()(const A *x) {
29+
if (x) {
30+
(*this)(*x);
31+
}
32+
}
33+
void operator()(const UnorderedSymbolSet &x) {
34+
for (const Symbol &symbol : x) {
35+
(*this)(symbol);
36+
}
37+
}
38+
void operator()(const SourceOrderedSymbolSet &x) {
39+
for (const Symbol &symbol : x) {
40+
(*this)(symbol);
41+
}
42+
}
43+
void operator()(const Scope &x) {
44+
for (const auto &[_, ref] : x) {
45+
(*this)(*ref);
46+
}
47+
}
48+
template <typename T> void operator()(const evaluate::Expr<T> &x) {
49+
UnorderedSymbolSet exprSyms{evaluate::CollectSymbols(x)};
50+
for (const Symbol &sym : exprSyms) {
51+
if (!sym.owner().IsDerivedType() || sym.has<DerivedTypeDetails>() ||
52+
(flags_ & IncludeComponentsInExprs)) {
53+
(*this)(sym);
54+
}
55+
}
56+
}
57+
void operator()(const DeclTypeSpec &type) {
58+
if (type.category() == DeclTypeSpec::Category::Character) {
59+
(*this)(type.characterTypeSpec().length());
60+
} else {
61+
(*this)(type.AsDerived());
62+
}
63+
}
64+
void operator()(const DerivedTypeSpec &type) {
65+
(*this)(type.originalTypeSymbol());
66+
for (const auto &[_, value] : type.parameters()) {
67+
(*this)(value);
68+
}
69+
}
70+
void operator()(const ParamValue &x) { (*this)(x.GetExplicit()); }
71+
void operator()(const Bound &x) { (*this)(x.GetExplicit()); }
72+
void operator()(const ShapeSpec &x) {
73+
(*this)(x.lbound());
74+
(*this)(x.ubound());
75+
}
76+
void operator()(const ArraySpec &x) {
77+
for (const ShapeSpec &shapeSpec : x) {
78+
(*this)(shapeSpec);
79+
}
80+
}
81+
82+
private:
83+
UnorderedSymbolSet set_;
84+
enum DependenceCollectionFlags flags_ { NoDependenceCollectionFlags };
85+
};
86+
87+
UnorderedSymbolSet CollectAllDependences(
88+
const Scope &scope, enum DependenceCollectionFlags flags) {
89+
UnorderedSymbolSet basis;
90+
for (const auto &[_, symbol] : scope) {
91+
basis.insert(*symbol);
92+
}
93+
return CollectAllDependences(basis, flags);
94+
}
95+
96+
UnorderedSymbolSet CollectAllDependences(
97+
const UnorderedSymbolSet &original, enum DependenceCollectionFlags flags) {
98+
UnorderedSymbolSet result;
99+
if (flags & IncludeOriginalSymbols) {
100+
result = original;
101+
}
102+
UnorderedSymbolSet work{original};
103+
while (!work.empty()) {
104+
Collector collect{flags};
105+
for (const Symbol &symbol : work) {
106+
collect(symbol.GetType());
107+
common::visit(
108+
common::visitors{
109+
[&collect, &symbol](const ObjectEntityDetails &x) {
110+
collect(x.shape());
111+
collect(x.coshape());
112+
if (IsNamedConstant(symbol) || symbol.owner().IsDerivedType()) {
113+
collect(x.init());
114+
}
115+
},
116+
[&collect, &symbol](const ProcEntityDetails &x) {
117+
collect(x.rawProcInterface());
118+
if (symbol.owner().IsDerivedType()) {
119+
collect(x.init());
120+
}
121+
},
122+
[&collect](const ProcBindingDetails &x) { collect(x.symbol()); },
123+
[&collect](const SubprogramDetails &x) {
124+
for (const Symbol *dummy : x.dummyArgs()) {
125+
collect(dummy);
126+
}
127+
if (x.isFunction()) {
128+
collect(x.result());
129+
}
130+
},
131+
[&collect, &symbol](
132+
const DerivedTypeDetails &) { collect(symbol.scope()); },
133+
[&collect, flags](const GenericDetails &x) {
134+
collect(x.derivedType());
135+
collect(x.specific());
136+
if (flags & IncludeSpecificsOfGenerics) {
137+
for (const Symbol &specific : x.specificProcs()) {
138+
collect(specific);
139+
}
140+
}
141+
},
142+
[&collect](const NamelistDetails &x) {
143+
for (const Symbol &symbol : x.objects()) {
144+
collect(symbol);
145+
}
146+
},
147+
[&collect](const CommonBlockDetails &x) {
148+
for (auto ref : x.objects()) {
149+
collect(*ref);
150+
}
151+
},
152+
[&collect, &symbol, flags](const UseDetails &x) {
153+
if (flags & FollowUseAssociations) {
154+
collect(x.symbol());
155+
}
156+
},
157+
[&collect](const HostAssocDetails &x) { collect(x.symbol()); },
158+
[](const auto &) {},
159+
},
160+
symbol.details());
161+
}
162+
work.clear();
163+
for (const Symbol &symbol : collect.Collected()) {
164+
if (result.find(symbol) == result.end() &&
165+
((flags & IncludeOriginalSymbols) ||
166+
original.find(symbol) == original.end())) {
167+
result.insert(symbol);
168+
work.insert(symbol);
169+
}
170+
}
171+
}
172+
return result;
173+
}
174+
175+
} // namespace Fortran::semantics

flang/lib/Semantics/tools.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "flang/Parser/tools.h"
9+
#include "flang/Semantics/tools.h"
1010
#include "flang/Common/indirection.h"
1111
#include "flang/Parser/dump-parse-tree.h"
1212
#include "flang/Parser/message.h"
1313
#include "flang/Parser/parse-tree.h"
14+
#include "flang/Parser/tools.h"
1415
#include "flang/Semantics/scope.h"
1516
#include "flang/Semantics/semantics.h"
1617
#include "flang/Semantics/symbol.h"
17-
#include "flang/Semantics/tools.h"
1818
#include "flang/Semantics/type.h"
1919
#include "flang/Support/Fortran.h"
2020
#include "llvm/ADT/StringSwitch.h"
@@ -2117,4 +2117,4 @@ bool IsSameOrConvertOf(const SomeExpr &expr, const SomeExpr &x) {
21172117
return false;
21182118
}
21192119
}
2120-
} // namespace Fortran::semantics
2120+
} // namespace Fortran::semantics

flang/lib/Semantics/type.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,19 @@
2222

2323
namespace Fortran::semantics {
2424

25+
static const Symbol &ResolveOriginalTypeSymbol(const Symbol *symbol) {
26+
symbol = &symbol->GetUltimate();
27+
if (const auto *generic{symbol->detailsIf<GenericDetails>()}) {
28+
CHECK(generic->derivedType() != nullptr);
29+
return generic->derivedType()->GetUltimate();
30+
} else {
31+
return *symbol;
32+
}
33+
}
34+
2535
DerivedTypeSpec::DerivedTypeSpec(SourceName name, const Symbol &typeSymbol)
2636
: name_{name}, originalTypeSymbol_{typeSymbol},
27-
typeSymbol_{typeSymbol.GetUltimate()} {
37+
typeSymbol_{ResolveOriginalTypeSymbol(&typeSymbol)} {
2838
CHECK(typeSymbol_.has<DerivedTypeDetails>());
2939
}
3040
DerivedTypeSpec::DerivedTypeSpec(const DerivedTypeSpec &that) = default;

0 commit comments

Comments
 (0)