-
Notifications
You must be signed in to change notification settings - Fork 14.2k
[flang] Don't emit needless symbols to hermetic module files #144765
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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.
When emitting the dependent modules for a hermetic module file, omit symbols that are not necessary (directly or otherwise) for the declarations and definitions in the main module. (Includes llvm#144618 as the first commit.)
@llvm/pr-subscribers-flang-semantics Author: Peter Klausler (klausler) ChangesWhen emitting the dependent modules for a hermetic module file, omit symbols that are not necessary (directly or otherwise) for the declarations and definitions in the main module. (Includes #144618 as the first commit.) Patch is 24.80 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144765.diff 9 Files Affected:
diff --git a/flang/include/flang/Semantics/symbol-set-closure.h b/flang/include/flang/Semantics/symbol-set-closure.h
new file mode 100644
index 0000000000000..d7f2f74c47e9a
--- /dev/null
+++ b/flang/include/flang/Semantics/symbol-set-closure.h
@@ -0,0 +1,34 @@
+//===-- include/flang/Semantics/symbol-set-closure.h ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_SEMANTICS_SYMBOLS_SET_CLOSURE_H_
+#define FORTRAN_SEMANTICS_SYMBOLS_SET_CLOSURE_H_
+
+#include "flang/Semantics/symbol.h"
+
+namespace Fortran::semantics {
+
+// For a set or scope of symbols, computes the transitive closure of their
+// dependences due to their types, bounds, specific procedures, interfaces,
+// initialization, storage association, &c. Includes the original symbol
+// or members of the original set. Does not include dependences from
+// subprogram definitions, only their interfaces.
+enum DependenceCollectionFlags {
+ NoDependenceCollectionFlags = 0,
+ IncludeOriginalSymbols = 1 << 0,
+ FollowUseAssociations = 1 << 1,
+ IncludeSpecificsOfGenerics = 1 << 2,
+ IncludeComponentsInExprs = 1 << 3,
+};
+UnorderedSymbolSet CollectAllDependences(
+ const UnorderedSymbolSet &, int = NoDependenceCollectionFlags);
+UnorderedSymbolSet CollectAllDependences(
+ const Scope &, int = NoDependenceCollectionFlags);
+
+} // namespace Fortran::semantics
+#endif // FORTRAN_SEMANTICS_SYMBOLS_SET_CLOSURE_H_
diff --git a/flang/lib/Semantics/CMakeLists.txt b/flang/lib/Semantics/CMakeLists.txt
index 18c89587843a9..c1be83b0c744c 100644
--- a/flang/lib/Semantics/CMakeLists.txt
+++ b/flang/lib/Semantics/CMakeLists.txt
@@ -46,6 +46,7 @@ add_flang_library(FortranSemantics
scope.cpp
semantics.cpp
symbol.cpp
+ symbol-set-closure.cpp
tools.cpp
type.cpp
unparse-with-symbols.cpp
diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index 82c8536902eb2..9985c4a3cecdb 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -15,6 +15,7 @@
#include "flang/Parser/unparse.h"
#include "flang/Semantics/scope.h"
#include "flang/Semantics/semantics.h"
+#include "flang/Semantics/symbol-set-closure.h"
#include "flang/Semantics/symbol.h"
#include "flang/Semantics/tools.h"
#include "llvm/Support/FileSystem.h"
@@ -47,8 +48,8 @@ struct ModHeader {
};
static std::optional<SourceName> GetSubmoduleParent(const parser::Program &);
-static void CollectSymbols(
- const Scope &, SymbolVector &, SymbolVector &, SourceOrderedSymbolSet &);
+static void CollectSymbols(const Scope &, SymbolVector &, SymbolVector &,
+ SourceOrderedSymbolSet &, UnorderedSymbolSet *);
static void PutPassName(llvm::raw_ostream &, const std::optional<SourceName> &);
static void PutInit(llvm::raw_ostream &, const Symbol &, const MaybeExpr &,
const parser::Expr *, SemanticsContext &);
@@ -130,7 +131,7 @@ static std::string ModFileName(const SourceName &name,
return ancestorName.empty() ? result : ancestorName + '-' + result;
}
-// Write the module file for symbol, which must be a module or submodule.
+// Writes the module file for symbol, which must be a module or submodule.
void ModFileWriter::Write(const Symbol &symbol) {
const auto &module{symbol.get<ModuleDetails>()};
if (symbol.test(Symbol::Flag::ModFile) || module.moduleFileHash()) {
@@ -142,21 +143,30 @@ void ModFileWriter::Write(const Symbol &symbol) {
std::string path{context_.moduleDirectory() + '/' +
ModFileName(symbol.name(), ancestorName, context_.moduleFileSuffix())};
- std::set<std::string> hermeticModuleNames;
- hermeticModuleNames.insert(symbol.name().ToString());
UnorderedSymbolSet additionalModules;
+ UnorderedSymbolSet dependenceClosure;
+ if (hermeticModuleFileOutput_) {
+ dependenceClosure = CollectAllDependences(
+ DEREF(symbol.scope()), IncludeOriginalSymbols | FollowUseAssociations);
+ }
PutSymbols(DEREF(symbol.scope()),
- hermeticModuleFileOutput_ ? &additionalModules : nullptr);
+ hermeticModuleFileOutput_ ? &additionalModules : nullptr,
+ hermeticModuleFileOutput_ ? &dependenceClosure : nullptr);
+ std::set<std::string> emittedModuleNames;
+ emittedModuleNames.insert(symbol.name().ToString());
auto asStr{GetAsString(symbol)};
+
+ // Emit additional modules for a hermetic module file
while (!additionalModules.empty()) {
UnorderedSymbolSet nextPass{std::move(additionalModules)};
additionalModules.clear();
for (const Symbol &modSym : nextPass) {
if (!modSym.owner().IsIntrinsicModules() &&
- hermeticModuleNames.find(modSym.name().ToString()) ==
- hermeticModuleNames.end()) {
- hermeticModuleNames.insert(modSym.name().ToString());
- PutSymbols(DEREF(modSym.scope()), &additionalModules);
+ emittedModuleNames.find(modSym.name().ToString()) ==
+ emittedModuleNames.end()) {
+ emittedModuleNames.insert(modSym.name().ToString());
+ PutSymbols(
+ DEREF(modSym.scope()), &additionalModules, &dependenceClosure);
asStr += GetAsString(modSym);
}
}
@@ -177,7 +187,8 @@ void ModFileWriter::WriteClosure(llvm::raw_ostream &out, const Symbol &symbol,
!nonIntrinsicModulesWritten.insert(symbol).second) {
return;
}
- PutSymbols(DEREF(symbol.scope()), /*hermeticModules=*/nullptr);
+ PutSymbols(DEREF(symbol.scope()), /*hermeticModules=*/nullptr,
+ /*dependenceClosure=*/nullptr);
needsBuf_.clear(); // omit module checksums
auto str{GetAsString(symbol)};
for (auto depRef : std::move(usedNonIntrinsicModules_)) {
@@ -223,78 +234,18 @@ std::string ModFileWriter::GetAsString(const Symbol &symbol) {
// Collect symbols from constant and specification expressions that are being
// referenced directly from other modules; they may require new USE
// associations.
-static void HarvestSymbolsNeededFromOtherModules(
- SourceOrderedSymbolSet &, const Scope &);
-static void HarvestSymbolsNeededFromOtherModules(
- SourceOrderedSymbolSet &set, const Symbol &symbol, const Scope &scope) {
- auto HarvestBound{[&](const Bound &bound) {
- if (const auto &expr{bound.GetExplicit()}) {
- for (SymbolRef ref : evaluate::CollectSymbols(*expr)) {
- set.emplace(*ref);
- }
- }
- }};
- auto HarvestShapeSpec{[&](const ShapeSpec &shapeSpec) {
- HarvestBound(shapeSpec.lbound());
- HarvestBound(shapeSpec.ubound());
- }};
- auto HarvestArraySpec{[&](const ArraySpec &arraySpec) {
- for (const auto &shapeSpec : arraySpec) {
- HarvestShapeSpec(shapeSpec);
- }
- }};
-
- if (symbol.has<DerivedTypeDetails>()) {
- if (symbol.scope()) {
- HarvestSymbolsNeededFromOtherModules(set, *symbol.scope());
- }
- } else if (const auto &generic{symbol.detailsIf<GenericDetails>()};
- generic && generic->derivedType()) {
- const Symbol &dtSym{*generic->derivedType()};
- if (dtSym.has<DerivedTypeDetails>()) {
- if (dtSym.scope()) {
- HarvestSymbolsNeededFromOtherModules(set, *dtSym.scope());
- }
- } else {
- CHECK(dtSym.has<UseDetails>() || dtSym.has<UseErrorDetails>());
- }
- } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
- HarvestArraySpec(object->shape());
- HarvestArraySpec(object->coshape());
- if (IsNamedConstant(symbol) || scope.IsDerivedType()) {
- if (object->init()) {
- for (SymbolRef ref : evaluate::CollectSymbols(*object->init())) {
- set.emplace(*ref);
- }
- }
- }
- } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) {
- if (proc->init() && *proc->init() && scope.IsDerivedType()) {
- set.emplace(**proc->init());
- }
- } else if (const auto *subp{symbol.detailsIf<SubprogramDetails>()}) {
- for (const Symbol *dummy : subp->dummyArgs()) {
- if (dummy) {
- HarvestSymbolsNeededFromOtherModules(set, *dummy, scope);
- }
- }
- if (subp->isFunction()) {
- HarvestSymbolsNeededFromOtherModules(set, subp->result(), scope);
- }
- }
-}
-
static void HarvestSymbolsNeededFromOtherModules(
SourceOrderedSymbolSet &set, const Scope &scope) {
- for (const auto &[_, symbol] : scope) {
- HarvestSymbolsNeededFromOtherModules(set, *symbol, scope);
+ for (const Symbol &symbol : CollectAllDependences(scope)) {
+ set.insert(symbol);
}
}
-void ModFileWriter::PrepareRenamings(const Scope &scope) {
+void ModFileWriter::PrepareRenamings(
+ const Scope &scope, const UnorderedSymbolSet *dependenceClosure) {
// Identify use-associated symbols already in scope under some name
std::map<const Symbol *, const Symbol *> useMap;
- for (const auto &[name, symbolRef] : scope) {
+ for (const auto &[_, symbolRef] : scope) {
const Symbol *symbol{&*symbolRef};
while (const auto *hostAssoc{symbol->detailsIf<HostAssocDetails>()}) {
symbol = &hostAssoc->symbol();
@@ -309,38 +260,42 @@ void ModFileWriter::PrepareRenamings(const Scope &scope) {
// Establish any necessary renamings of symbols in other modules
// to their names in this scope, creating those new names when needed.
auto &renamings{context_.moduleFileOutputRenamings()};
- for (SymbolRef s : symbolsNeeded) {
- if (s->owner().kind() != Scope::Kind::Module) {
+ for (const Symbol &sym : symbolsNeeded) {
+ if (sym.owner().kind() != Scope::Kind::Module) {
// Not a USE'able name from a module's top scope;
// component, binding, dummy argument, &c.
continue;
}
- const Scope *sMod{FindModuleContaining(s->owner())};
+ const Scope *sMod{FindModuleContaining(sym.owner())};
if (!sMod || sMod == &scope) {
continue;
}
- if (auto iter{useMap.find(&*s)}; iter != useMap.end()) {
- renamings.emplace(&*s, iter->second->name());
+ if (dependenceClosure &&
+ dependenceClosure->find(sym) == dependenceClosure->end()) {
continue;
}
- SourceName rename{s->name()};
- if (const Symbol * found{scope.FindSymbol(s->name())}) {
- if (found == &*s) {
+ if (auto iter{useMap.find(&sym)}; iter != useMap.end()) {
+ renamings.emplace(&sym, iter->second->name());
+ continue;
+ }
+ SourceName rename{sym.name()};
+ if (const Symbol *found{scope.FindSymbol(sym.name())}) {
+ if (found == &sym) {
continue; // available in scope
}
if (const auto *generic{found->detailsIf<GenericDetails>()}) {
- if (generic->derivedType() == &*s || generic->specific() == &*s) {
+ if (generic->derivedType() == &sym || generic->specific() == &sym) {
continue;
}
} else if (found->has<UseDetails>()) {
- if (&found->GetUltimate() == &*s) {
+ if (&found->GetUltimate() == &sym) {
continue; // already use-associated with same name
}
}
- if (&s->owner() != &found->owner()) { // Symbol needs renaming
+ if (&sym.owner() != &found->owner()) { // Symbol needs renaming
rename = scope.context().SaveTempName(
DEREF(sMod->symbol()).name().ToString() + "$" +
- s->name().ToString());
+ sym.name().ToString());
}
}
// Symbol is used in this scope but not visible under its name
@@ -350,26 +305,27 @@ void ModFileWriter::PrepareRenamings(const Scope &scope) {
uses_ << "use ";
}
uses_ << DEREF(sMod->symbol()).name() << ",only:";
- if (rename != s->name()) {
+ if (rename != sym.name()) {
uses_ << rename << "=>";
- renamings.emplace(&s->GetUltimate(), rename);
+ renamings.emplace(&sym.GetUltimate(), rename);
}
- uses_ << s->name() << '\n';
+ uses_ << sym.name() << '\n';
useExtraAttrs_ << "private::" << rename << '\n';
}
}
// Put out the visible symbols from scope.
-void ModFileWriter::PutSymbols(
- const Scope &scope, UnorderedSymbolSet *hermeticModules) {
+void ModFileWriter::PutSymbols(const Scope &scope,
+ UnorderedSymbolSet *hermeticModules,
+ UnorderedSymbolSet *dependenceClosure) {
SymbolVector sorted;
SymbolVector uses;
auto &renamings{context_.moduleFileOutputRenamings()};
auto previousRenamings{std::move(renamings)};
- PrepareRenamings(scope);
+ PrepareRenamings(scope, dependenceClosure);
SourceOrderedSymbolSet modules;
- CollectSymbols(scope, sorted, uses, modules);
- // Write module files for dependencies first so that their
+ CollectSymbols(scope, sorted, uses, modules, dependenceClosure);
+ // Write module files for dependences first so that their
// hashes are known.
for (const Symbol &mod : modules) {
if (hermeticModules) {
@@ -852,12 +808,17 @@ void ModFileWriter::PutUseExtraAttr(
// Collect the symbols of this scope sorted by their original order, not name.
// Generics and namelists are exceptions: they are sorted after other symbols.
void CollectSymbols(const Scope &scope, SymbolVector &sorted,
- SymbolVector &uses, SourceOrderedSymbolSet &modules) {
+ SymbolVector &uses, SourceOrderedSymbolSet &modules,
+ UnorderedSymbolSet *dependenceClosure) {
SymbolVector namelist, generics;
auto symbols{scope.GetSymbols()};
std::size_t commonSize{scope.commonBlocks().size()};
sorted.reserve(symbols.size() + commonSize);
for (const Symbol &symbol : symbols) {
+ if (dependenceClosure &&
+ dependenceClosure->find(symbol) == dependenceClosure->end()) {
+ continue; // needless for the main module
+ }
const auto *generic{symbol.detailsIf<GenericDetails>()};
if (generic) {
uses.insert(uses.end(), generic->uses().begin(), generic->uses().end());
diff --git a/flang/lib/Semantics/mod-file.h b/flang/lib/Semantics/mod-file.h
index 9e5724089b3c5..443596af19df3 100644
--- a/flang/lib/Semantics/mod-file.h
+++ b/flang/lib/Semantics/mod-file.h
@@ -67,8 +67,9 @@ class ModFileWriter {
void WriteOne(const Scope &);
void Write(const Symbol &);
std::string GetAsString(const Symbol &);
- void PrepareRenamings(const Scope &);
- void PutSymbols(const Scope &, UnorderedSymbolSet *hermetic);
+ void PrepareRenamings(const Scope &, const UnorderedSymbolSet *);
+ void PutSymbols(const Scope &, UnorderedSymbolSet *hermetic,
+ UnorderedSymbolSet *dependenceClosure);
// Returns true if a derived type with bindings and "contains" was emitted
bool PutComponents(const Symbol &);
void PutSymbol(llvm::raw_ostream &, const Symbol &);
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index f66918e5c140e..f6cbe49f56543 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -7416,7 +7416,8 @@ void DeclarationVisitor::SetType(
std::optional<DerivedTypeSpec> DeclarationVisitor::ResolveDerivedType(
const parser::Name &name) {
Scope &outer{NonDerivedTypeScope()};
- Symbol *symbol{FindSymbol(outer, name)};
+ Symbol *original{FindSymbol(outer, name)};
+ Symbol *symbol{original};
Symbol *ultimate{symbol ? &symbol->GetUltimate() : nullptr};
auto *generic{ultimate ? ultimate->detailsIf<GenericDetails>() : nullptr};
if (generic) {
@@ -7429,11 +7430,12 @@ std::optional<DerivedTypeSpec> DeclarationVisitor::ResolveDerivedType(
(generic && &ultimate->owner() == &outer)) {
if (allowForwardReferenceToDerivedType()) {
if (!symbol) {
- symbol = &MakeSymbol(outer, name.source, Attrs{});
+ symbol = original = &MakeSymbol(outer, name.source, Attrs{});
Resolve(name, *symbol);
} else if (generic) {
// forward ref to type with later homonymous generic
- symbol = &outer.MakeSymbol(name.source, Attrs{}, UnknownDetails{});
+ symbol = original =
+ &outer.MakeSymbol(name.source, Attrs{}, UnknownDetails{});
generic->set_derivedType(*symbol);
name.symbol = symbol;
}
@@ -7453,7 +7455,7 @@ std::optional<DerivedTypeSpec> DeclarationVisitor::ResolveDerivedType(
if (CheckUseError(name)) {
return std::nullopt;
} else if (symbol->GetUltimate().has<DerivedTypeDetails>()) {
- return DerivedTypeSpec{name.source, *symbol};
+ return DerivedTypeSpec{name.source, *original};
} else {
Say(name, "'%s' is not a derived type"_err_en_US);
return std::nullopt;
diff --git a/flang/lib/Semantics/symbol-set-closure.cpp b/flang/lib/Semantics/symbol-set-closure.cpp
new file mode 100644
index 0000000000000..fb928460b86b5
--- /dev/null
+++ b/flang/lib/Semantics/symbol-set-closure.cpp
@@ -0,0 +1,187 @@
+//===-- lib/Semantics/symbol-set-closure.cpp ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Semantics/symbol-set-closure.h"
+#include "flang/Common/idioms.h"
+#include "flang/Common/visit.h"
+
+namespace Fortran::semantics {
+
+class Collector {
+public:
+ explicit Collector(int flags) : flags_{flags} {}
+
+ UnorderedSymbolSet Collected() { return std::move(set_); }
+
+ void operator()(const Symbol &x) { set_.insert(x); }
+ void operator()(SymbolRef x) { (*this)(*x); }
+ template <typename A> void operator()(const std::optional<A> &x) {
+ if (x) {
+ (*this)(*x);
+ }
+ }
+ template <typename A> void operator()(const A *x) {
+ if (x) {
+ (*this)(*x);
+ }
+ }
+ void operator()(const UnorderedSymbolSet &x) {
+ for (const Symbol &symbol : x) {
+ (*this)(symbol);
+ }
+ }
+ void operator()(const SourceOrderedSymbolSet &x) {
+ for (const Symbol &symbol : x) {
+ (*this)(symbol);
+ }
+ }
+ void operator()(const Scope &x) {
+ for (const auto &[_, ref] : x) {
+ (*this)(*ref);
+ }
+ }
+ template <typename T> void operator()(const evaluate::Expr<T> &x) {
+ UnorderedSymbolSet exprSyms{evaluate::CollectSymbols(x)};
+ for (const Symbol &sym : exprSyms) {
+ if (!sym.owner().IsDerivedType() || sym.has<DerivedTypeDetails>() ||
+ (flags_ & IncludeComponentsInExprs)) {
+ (*this)(sym);
+ }
+ }
+ }
+ void operator()(const DeclTypeSpec &type) {
+ if (type.category() == DeclTypeSpec::Category::Character) {
+ (*this)(type.characterTypeSpec().length());
+ } else {
+ (*this)(type.AsDerived());
+ }
+ }
+ void operator()(const DerivedTypeSpec &type) {
+ (*this)(type.originalTypeSymbol());
+ for (const auto &[_, value] : type.parameters()) {
+ (*this)(value);
+ }
+ }
+ void operator()(const ParamValue &x) { (*this)(x.GetExplicit()); }
+ void operator()(const Bound &x) { (*this)(x.GetExplicit()); }
+ void operator()(const ShapeSpec &x) {
+ (*this)(x.lbound());
+ (*this)(x.ubound());
+ }
+ void operator()(const ArraySpec &x) {
+ for (const ShapeSpec &shapeSpec : x) {
+ (*this)(shapeSpec);
+ }
+ }
+
+private:
+ UnorderedSymbolSet set_;
+ int flags_{NoDependenceCollectionFlags};
+};
+
+UnorderedSymbolSet CollectAllDependences(const Scope &scope, int flags) {
+ UnorderedSymbolSet basis;
+ for (const auto &[_, symbol] : scope) {
+ basis.insert(*symbol);
+ }
+ return CollectAllDependences(basis, flags);
+}
+
+UnorderedSymbolSet CollectAllDependences(
+ const UnorderedSymbolSet &original, int flags) {
+ UnorderedSymbolSet result;
+ if (flags & IncludeOriginalSymbols) {
+ result = original;
+ }
+ UnorderedSymbolSet work{original};
+ while (!work.empty()) {
+ Collector collect{flags};
+ for (const Symbol &symbol : work) {
+ if (symbol.test(Symbol::Flag::CompilerCreated)) {
+ continue;
+ }
+ collect(symbol.GetType());
+ common::visit(
+ common::visitors{
+ [&collect, &symbol](const ObjectEntityDetails &x) {
+ collect(x.shape());
+ collect(x.coshape());
+ if (IsNamedConstant(symbol) || symbol.owner().IsDerivedType()) {
+ collect(x.init());
+ }
+ collect(x.commonBlock());
+ if (const auto *set{FindEquivalenceSet(symbol)}) {
+...
[truncated]
|
When emitting the dependent modules for a hermetic module file, omit symbols that are not necessary (directly or otherwise) for the declarations and definitions in the main module.
(Includes #144618 as the first commit.)