diff options
author | Peter Klausler <35819229+klausler@users.noreply.github.com> | 2024-05-15 15:44:37 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-15 15:44:37 -0700 |
commit | e00a3ccf43563209b71c5b68f56d83f4052dca63 (patch) | |
tree | 5729f1012e0a0fcd56901ab7afe63b7595012ccb /flang/lib/Semantics | |
parent | 0585eed9409c1362f7deaabc42c1d3c3f55c4b6c (diff) | |
download | llvm-e00a3ccf43563209b71c5b68f56d83f4052dca63.zip llvm-e00a3ccf43563209b71c5b68f56d83f4052dca63.tar.gz llvm-e00a3ccf43563209b71c5b68f56d83f4052dca63.tar.bz2 |
[flang] New -fdebug-unparse-with-modules option (#91660)
This option is a compilation action that parses a source file and
performs semantic analysis on it, like the existing -fdebug-unparse
option does. Its output, however, is preceded by the effective contents
of all of the non-intrinsic modules on which it depends but does not
define, transitively preceded by the closure of all of those modules'
dependencies.
The output from this option is therefore the analyzed parse tree for a
source file encapsulated with all of its non-intrinsic module
dependencies. This output may be useful for extracting code from large
applications for use as an attachment to a bug report, or as input to a
test case reduction tool for problem isolation.
Diffstat (limited to 'flang/lib/Semantics')
-rw-r--r-- | flang/lib/Semantics/mod-file.cpp | 20 | ||||
-rw-r--r-- | flang/lib/Semantics/mod-file.h | 3 | ||||
-rw-r--r-- | flang/lib/Semantics/unparse-with-symbols.cpp | 38 |
3 files changed, 59 insertions, 2 deletions
diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp index e9aebe5..bb8c6c7 100644 --- a/flang/lib/Semantics/mod-file.cpp +++ b/flang/lib/Semantics/mod-file.cpp @@ -132,11 +132,11 @@ static std::string ModFileName(const SourceName &name, // Write the module file for symbol, which must be a module or submodule. void ModFileWriter::Write(const Symbol &symbol) { - auto &module{symbol.get<ModuleDetails>()}; + const auto &module{symbol.get<ModuleDetails>()}; if (module.moduleFileHash()) { return; // already written } - auto *ancestor{module.ancestor()}; + const auto *ancestor{module.ancestor()}; isSubmodule_ = ancestor != nullptr; auto ancestorName{ancestor ? ancestor->GetName().value().ToString() : ""s}; auto path{context_.moduleDirectory() + '/' + @@ -151,6 +151,21 @@ void ModFileWriter::Write(const Symbol &symbol) { const_cast<ModuleDetails &>(module).set_moduleFileHash(checkSum); } +void ModFileWriter::WriteClosure(llvm::raw_ostream &out, const Symbol &symbol, + UnorderedSymbolSet &nonIntrinsicModulesWritten) { + if (!symbol.has<ModuleDetails>() || symbol.owner().IsIntrinsicModules() || + !nonIntrinsicModulesWritten.insert(symbol).second) { + return; + } + PutSymbols(DEREF(symbol.scope())); + needsBuf_.clear(); // omit module checksums + auto str{GetAsString(symbol)}; + for (auto depRef : std::move(usedNonIntrinsicModules_)) { + WriteClosure(out, *depRef, nonIntrinsicModulesWritten); + } + out << std::move(str); +} + // Return the entire body of the module file // and clear saved uses, decls, and contains. std::string ModFileWriter::GetAsString(const Symbol &symbol) { @@ -710,6 +725,7 @@ void ModFileWriter::PutUse(const Symbol &symbol) { uses_ << "use,intrinsic::"; } else { uses_ << "use "; + usedNonIntrinsicModules_.insert(module); } uses_ << module.name() << ",only:"; PutGenericName(uses_, symbol); diff --git a/flang/lib/Semantics/mod-file.h b/flang/lib/Semantics/mod-file.h index b4ece40..739add3 100644 --- a/flang/lib/Semantics/mod-file.h +++ b/flang/lib/Semantics/mod-file.h @@ -35,6 +35,8 @@ class ModFileWriter { public: explicit ModFileWriter(SemanticsContext &context) : context_{context} {} bool WriteAll(); + void WriteClosure(llvm::raw_ostream &, const Symbol &, + UnorderedSymbolSet &nonIntrinsicModulesWritten); private: SemanticsContext &context_; @@ -46,6 +48,7 @@ private: std::string containsBuf_; // Tracks nested DEC structures and fields of that type UnorderedSymbolSet emittedDECStructures_, emittedDECFields_; + UnorderedSymbolSet usedNonIntrinsicModules_; llvm::raw_string_ostream needs_{needsBuf_}; llvm::raw_string_ostream uses_{usesBuf_}; diff --git a/flang/lib/Semantics/unparse-with-symbols.cpp b/flang/lib/Semantics/unparse-with-symbols.cpp index 67016e8..c451f885 100644 --- a/flang/lib/Semantics/unparse-with-symbols.cpp +++ b/flang/lib/Semantics/unparse-with-symbols.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "flang/Semantics/unparse-with-symbols.h" +#include "mod-file.h" #include "flang/Parser/parse-tree-visitor.h" #include "flang/Parser/parse-tree.h" #include "flang/Parser/unparse.h" @@ -98,4 +99,41 @@ void UnparseWithSymbols(llvm::raw_ostream &out, const parser::Program &program, int indent) { visitor.PrintSymbols(location, out, indent); }}; parser::Unparse(out, program, encoding, false, true, &preStatement); } + +// UnparseWithModules() + +class UsedModuleVisitor { +public: + UnorderedSymbolSet &modulesUsed() { return modulesUsed_; } + UnorderedSymbolSet &modulesDefined() { return modulesDefined_; } + template <typename T> bool Pre(const T &) { return true; } + template <typename T> void Post(const T &) {} + void Post(const parser::ModuleStmt &module) { + if (module.v.symbol) { + modulesDefined_.insert(*module.v.symbol); + } + } + void Post(const parser::UseStmt &use) { + if (use.moduleName.symbol) { + modulesUsed_.insert(*use.moduleName.symbol); + } + } + +private: + UnorderedSymbolSet modulesUsed_; + UnorderedSymbolSet modulesDefined_; +}; + +void UnparseWithModules(llvm::raw_ostream &out, SemanticsContext &context, + const parser::Program &program, parser::Encoding encoding) { + UsedModuleVisitor visitor; + parser::Walk(program, visitor); + UnorderedSymbolSet nonIntrinsicModulesWritten{ + std::move(visitor.modulesDefined())}; + ModFileWriter writer{context}; + for (SymbolRef moduleRef : visitor.modulesUsed()) { + writer.WriteClosure(out, *moduleRef, nonIntrinsicModulesWritten); + } + parser::Unparse(out, program, encoding, false, true); +} } // namespace Fortran::semantics |