Skip to content

Commit 08e788c

Browse files
committed
[flang] Don't emit needless symbols to hermetic module files
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.)
1 parent 92e5ff9 commit 08e788c

File tree

7 files changed

+166
-75
lines changed

7 files changed

+166
-75
lines changed

flang/include/flang/Semantics/symbol-set-closure.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ enum DependenceCollectionFlags {
2525
IncludeSpecificsOfGenerics = 1 << 2,
2626
IncludeComponentsInExprs = 1 << 3,
2727
};
28-
UnorderedSymbolSet CollectAllDependences(
28+
29+
SymbolVector CollectAllDependences(
2930
const UnorderedSymbolSet &, int = NoDependenceCollectionFlags);
30-
UnorderedSymbolSet CollectAllDependences(
31+
SymbolVector CollectAllDependences(
3132
const Scope &, int = NoDependenceCollectionFlags);
3233

3334
} // namespace Fortran::semantics

flang/lib/Semantics/mod-file.cpp

Lines changed: 118 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ static std::string ModFileName(const SourceName &name,
131131
return ancestorName.empty() ? result : ancestorName + '-' + result;
132132
}
133133

134-
// Write the module file for symbol, which must be a module or submodule.
134+
// Writes the module file for symbol, which must be a module or submodule.
135135
void ModFileWriter::Write(const Symbol &symbol) {
136136
const auto &module{symbol.get<ModuleDetails>()};
137137
if (symbol.test(Symbol::Flag::ModFile) || module.moduleFileHash()) {
@@ -143,26 +143,14 @@ void ModFileWriter::Write(const Symbol &symbol) {
143143
std::string path{context_.moduleDirectory() + '/' +
144144
ModFileName(symbol.name(), ancestorName, context_.moduleFileSuffix())};
145145

146-
std::set<std::string> hermeticModuleNames;
147-
hermeticModuleNames.insert(symbol.name().ToString());
148-
UnorderedSymbolSet additionalModules;
149-
PutSymbols(DEREF(symbol.scope()),
150-
hermeticModuleFileOutput_ ? &additionalModules : nullptr);
151-
auto asStr{GetAsString(symbol)};
152-
while (!additionalModules.empty()) {
153-
UnorderedSymbolSet nextPass{std::move(additionalModules)};
154-
additionalModules.clear();
155-
for (const Symbol &modSym : nextPass) {
156-
if (!modSym.owner().IsIntrinsicModules() &&
157-
hermeticModuleNames.find(modSym.name().ToString()) ==
158-
hermeticModuleNames.end()) {
159-
hermeticModuleNames.insert(modSym.name().ToString());
160-
PutSymbols(DEREF(modSym.scope()), &additionalModules);
161-
asStr += GetAsString(modSym);
162-
}
163-
}
146+
SymbolVector dependenceClosure;
147+
if (hermeticModuleFileOutput_) {
148+
dependenceClosure = CollectAllDependences(DEREF(symbol.scope()),
149+
FollowUseAssociations | IncludeSpecificsOfGenerics);
164150
}
165-
151+
PutSymbols(DEREF(symbol.scope()), hermeticModuleFileOutput_);
152+
auto asStr{GetAsString(&symbol, symbol.name().ToString())};
153+
asStr += PutDependencyModules(symbol.name().ToString(), dependenceClosure);
166154
ModuleCheckSumType checkSum;
167155
if (std::error_code error{
168156
WriteFile(path, asStr, checkSum, context_.debugModuleWriter())}) {
@@ -178,9 +166,9 @@ void ModFileWriter::WriteClosure(llvm::raw_ostream &out, const Symbol &symbol,
178166
!nonIntrinsicModulesWritten.insert(symbol).second) {
179167
return;
180168
}
181-
PutSymbols(DEREF(symbol.scope()), /*hermeticModules=*/nullptr);
169+
PutSymbols(DEREF(symbol.scope()), /*omitModules=*/false);
182170
needsBuf_.clear(); // omit module checksums
183-
auto str{GetAsString(symbol)};
171+
auto str{GetAsString(&symbol, symbol.name().ToString())};
184172
for (auto depRef : std::move(usedNonIntrinsicModules_)) {
185173
WriteClosure(out, *depRef, nonIntrinsicModulesWritten);
186174
}
@@ -189,22 +177,23 @@ void ModFileWriter::WriteClosure(llvm::raw_ostream &out, const Symbol &symbol,
189177

190178
// Return the entire body of the module file
191179
// and clear saved uses, decls, and contains.
192-
std::string ModFileWriter::GetAsString(const Symbol &symbol) {
180+
std::string ModFileWriter::GetAsString(const Symbol *symbol, std::string name) {
193181
std::string buf;
194182
llvm::raw_string_ostream all{buf};
195183
all << needs_.str();
196184
needs_.str().clear();
197-
auto &details{symbol.get<ModuleDetails>()};
198-
if (!details.isSubmodule()) {
199-
all << "module " << symbol.name();
185+
const ModuleDetails *details{
186+
symbol ? &symbol->get<ModuleDetails>() : nullptr};
187+
if (!details || !details->isSubmodule()) {
188+
all << "module " << name;
200189
} else {
201-
auto *parent{details.parent()->symbol()};
202-
auto *ancestor{details.ancestor()->symbol()};
190+
auto *parent{details->parent()->symbol()};
191+
auto *ancestor{details->ancestor()->symbol()};
203192
all << "submodule(" << ancestor->name();
204193
if (parent != ancestor) {
205194
all << ':' << parent->name();
206195
}
207-
all << ") " << symbol.name();
196+
all << ") " << name;
208197
}
209198
all << '\n' << uses_.str();
210199
uses_.str().clear();
@@ -234,7 +223,7 @@ static void HarvestSymbolsNeededFromOtherModules(
234223
void ModFileWriter::PrepareRenamings(const Scope &scope) {
235224
// Identify use-associated symbols already in scope under some name
236225
std::map<const Symbol *, const Symbol *> useMap;
237-
for (const auto &[name, symbolRef] : scope) {
226+
for (const auto &[_, symbolRef] : scope) {
238227
const Symbol *symbol{&*symbolRef};
239228
while (const auto *hostAssoc{symbol->detailsIf<HostAssocDetails>()}) {
240229
symbol = &hostAssoc->symbol();
@@ -249,38 +238,38 @@ void ModFileWriter::PrepareRenamings(const Scope &scope) {
249238
// Establish any necessary renamings of symbols in other modules
250239
// to their names in this scope, creating those new names when needed.
251240
auto &renamings{context_.moduleFileOutputRenamings()};
252-
for (SymbolRef s : symbolsNeeded) {
253-
if (s->owner().kind() != Scope::Kind::Module) {
241+
for (const Symbol &sym : symbolsNeeded) {
242+
if (sym.owner().kind() != Scope::Kind::Module) {
254243
// Not a USE'able name from a module's top scope;
255244
// component, binding, dummy argument, &c.
256245
continue;
257246
}
258-
const Scope *sMod{FindModuleContaining(s->owner())};
247+
const Scope *sMod{FindModuleContaining(sym.owner())};
259248
if (!sMod || sMod == &scope) {
260249
continue;
261250
}
262-
if (auto iter{useMap.find(&*s)}; iter != useMap.end()) {
263-
renamings.emplace(&*s, iter->second->name());
251+
if (auto iter{useMap.find(&sym)}; iter != useMap.end()) {
252+
renamings.emplace(&sym, iter->second->name());
264253
continue;
265254
}
266-
SourceName rename{s->name()};
267-
if (const Symbol * found{scope.FindSymbol(s->name())}) {
268-
if (found == &*s) {
255+
SourceName rename{sym.name()};
256+
if (const Symbol *found{scope.FindSymbol(sym.name())}) {
257+
if (found == &sym) {
269258
continue; // available in scope
270259
}
271260
if (const auto *generic{found->detailsIf<GenericDetails>()}) {
272-
if (generic->derivedType() == &*s || generic->specific() == &*s) {
261+
if (generic->derivedType() == &sym || generic->specific() == &sym) {
273262
continue;
274263
}
275264
} else if (found->has<UseDetails>()) {
276-
if (&found->GetUltimate() == &*s) {
265+
if (&found->GetUltimate() == &sym) {
277266
continue; // already use-associated with same name
278267
}
279268
}
280-
if (&s->owner() != &found->owner()) { // Symbol needs renaming
269+
if (&sym.owner() != &found->owner()) { // Symbol needs renaming
281270
rename = scope.context().SaveTempName(
282271
DEREF(sMod->symbol()).name().ToString() + "$" +
283-
s->name().ToString());
272+
sym.name().ToString());
284273
}
285274
}
286275
// Symbol is used in this scope but not visible under its name
@@ -290,31 +279,28 @@ void ModFileWriter::PrepareRenamings(const Scope &scope) {
290279
uses_ << "use ";
291280
}
292281
uses_ << DEREF(sMod->symbol()).name() << ",only:";
293-
if (rename != s->name()) {
282+
if (rename != sym.name()) {
294283
uses_ << rename << "=>";
295-
renamings.emplace(&s->GetUltimate(), rename);
284+
renamings.emplace(&sym.GetUltimate(), rename);
296285
}
297-
uses_ << s->name() << '\n';
286+
uses_ << sym.name() << '\n';
298287
useExtraAttrs_ << "private::" << rename << '\n';
299288
}
300289
}
301290

302291
// Put out the visible symbols from scope.
303-
void ModFileWriter::PutSymbols(
304-
const Scope &scope, UnorderedSymbolSet *hermeticModules) {
292+
void ModFileWriter::PutSymbols(const Scope &scope, bool omitModules) {
305293
SymbolVector sorted;
306294
SymbolVector uses;
307295
auto &renamings{context_.moduleFileOutputRenamings()};
308296
auto previousRenamings{std::move(renamings)};
309297
PrepareRenamings(scope);
310298
SourceOrderedSymbolSet modules;
311299
CollectSymbols(scope, sorted, uses, modules);
312-
// Write module files for dependences first so that their
300+
// Write module files for compiled dependency modules first so that their
313301
// hashes are known.
314-
for (const Symbol &mod : modules) {
315-
if (hermeticModules) {
316-
hermeticModules->insert(mod);
317-
} else {
302+
if (!omitModules) {
303+
for (const Symbol &mod : modules) {
318304
Write(mod);
319305
// It's possible that the module's file already existed and
320306
// without its own hash due to being embedded in a hermetic
@@ -352,6 +338,86 @@ void ModFileWriter::PutSymbols(
352338
renamings = std::move(previousRenamings);
353339
}
354340

341+
std::string ModFileWriter::PutDependencyModules(
342+
std::string originalModuleName, const SymbolVector &revOrder) {
343+
// Partition symbols by module name.
344+
// Ignore symbols from intrinsic modules and the original module.
345+
std::map<std::string, SymbolVector> perModuleName;
346+
for (const Symbol &symbol : revOrder) {
347+
if (const Scope *module{FindModuleContaining(symbol.owner())}) {
348+
if (!module->parent().IsIntrinsicModules()) {
349+
if (auto name{module->GetName()}) {
350+
if (getenv("PMK") && name->ToString() == originalModuleName)
351+
llvm::errs() << "pmk: from original module: " << symbol << '\n';
352+
perModuleName[name->ToString()].emplace_back(symbol);
353+
}
354+
}
355+
}
356+
}
357+
std::string result;
358+
for (const auto &[moduleName, symbols] : perModuleName) {
359+
if (moduleName != originalModuleName) {
360+
result += PutDependencyModule(moduleName, symbols);
361+
}
362+
}
363+
return result;
364+
}
365+
366+
std::string ModFileWriter::PutDependencyModule(
367+
const std::string &moduleName, const SymbolVector &symbols) {
368+
SymbolVector order, namelists, generics;
369+
std::set<std::string> names, commonNames, genericNames;
370+
order.reserve(symbols.size());
371+
for (const Symbol &symbol : symbols) {
372+
std::string symbolName{symbol.name().ToString()};
373+
if (symbol.test(Symbol::Flag::ParentComp) ||
374+
symbol.test(Symbol::Flag::CompilerCreated) ||
375+
!symbol.owner().IsModule()) {
376+
} else if (symbol.has<CommonBlockDetails>()) {
377+
if (commonNames.find(symbolName) == commonNames.end()) {
378+
order.push_back(symbol);
379+
commonNames.insert(symbolName);
380+
}
381+
} else if (const auto *generic{symbol.detailsIf<GenericDetails>()}) {
382+
if (names.find(symbolName) == names.end()) {
383+
if (generic->specific() &&
384+
&generic->specific()->owner() == &symbol.owner()) {
385+
order.push_back(*generic->specific());
386+
names.insert(symbolName);
387+
} else if (generic->derivedType() &&
388+
&generic->derivedType()->owner() == &symbol.owner()) {
389+
order.push_back(*generic->derivedType());
390+
names.insert(symbolName);
391+
}
392+
}
393+
if (genericNames.find(symbolName) == genericNames.end()) {
394+
generics.push_back(symbol);
395+
genericNames.insert(symbolName);
396+
}
397+
} else if (names.find(symbolName) != names.end()) {
398+
} else if (symbol.has<NamelistDetails>()) {
399+
namelists.push_back(symbol);
400+
names.insert(symbolName);
401+
} else {
402+
order.push_back(symbol);
403+
names.insert(symbolName);
404+
}
405+
}
406+
order.insert(order.end(), generics.begin(), generics.end());
407+
order.insert(order.end(), namelists.begin(), namelists.end());
408+
// Emit the symbols
409+
std::string buf;
410+
llvm::raw_string_ostream typeBindings{buf};
411+
for (const Symbol &symbol : order) {
412+
if (getenv("PMK"))
413+
llvm::errs() << "pmk: putting " << symbol << '\n';
414+
PutSymbol(typeBindings, symbol);
415+
}
416+
// pmk TODO: equivalence sets
417+
CHECK(typeBindings.str().empty());
418+
return GetAsString(nullptr, moduleName);
419+
}
420+
355421
// Emit components in order
356422
bool ModFileWriter::PutComponents(const Symbol &typeSymbol) {
357423
const auto &scope{DEREF(typeSymbol.scope())};

flang/lib/Semantics/mod-file.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,13 @@ class ModFileWriter {
6666
void WriteAll(const Scope &);
6767
void WriteOne(const Scope &);
6868
void Write(const Symbol &);
69-
std::string GetAsString(const Symbol &);
69+
std::string GetAsString(const Symbol *, std::string);
7070
void PrepareRenamings(const Scope &);
71-
void PutSymbols(const Scope &, UnorderedSymbolSet *hermetic);
71+
void PutSymbols(const Scope &, bool omitModules);
72+
std::string PutDependencyModules(
73+
std::string originalModuleName, const SymbolVector &);
74+
std::string PutDependencyModule(
75+
const std::string &modName, const SymbolVector &);
7276
// Returns true if a derived type with bindings and "contains" was emitted
7377
bool PutComponents(const Symbol &);
7478
void PutSymbol(llvm::raw_ostream &, const Symbol &);

flang/lib/Semantics/semantics.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,8 @@ bool Semantics::Perform() {
648648
PerformStatementSemantics(context_, program_) &&
649649
CanonicalizeDirectives(context_.messages(), program_) &&
650650
ModFileWriter{context_}
651-
.set_hermeticModuleFileOutput(hermeticModuleFileOutput_)
651+
.set_hermeticModuleFileOutput(
652+
hermeticModuleFileOutput_ || getenv("PMK_HERMETIC"))
652653
.WriteAll();
653654
}
654655

0 commit comments

Comments
 (0)