Skip to content

Commit e00a3cc

Browse files
authored
[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.
1 parent 0585eed commit e00a3cc

File tree

11 files changed

+122
-3
lines changed

11 files changed

+122
-3
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6647,7 +6647,9 @@ def fdebug_unparse : Flag<["-"], "fdebug-unparse">, Group<Action_Group>,
66476647
DocBrief<[{Run the parser and the semantic checks. Then unparse the
66486648
parse-tree and output the generated Fortran source file.}]>;
66496649
def fdebug_unparse_with_symbols : Flag<["-"], "fdebug-unparse-with-symbols">, Group<Action_Group>,
6650-
HelpText<"Unparse and stop.">;
6650+
HelpText<"Unparse with symbols and stop.">;
6651+
def fdebug_unparse_with_modules : Flag<["-"], "fdebug-unparse-with-modules">, Group<Action_Group>,
6652+
HelpText<"Unparse with dependent modules and stop.">;
66516653
def fdebug_dump_symbols : Flag<["-"], "fdebug-dump-symbols">, Group<Action_Group>,
66526654
HelpText<"Dump symbols after the semantic analysis">;
66536655
def fdebug_dump_parse_tree : Flag<["-"], "fdebug-dump-parse-tree">, Group<Action_Group>,

flang/include/flang/Frontend/FrontendActions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ class DebugUnparseWithSymbolsAction : public PrescanAndSemaAction {
108108
void executeAction() override;
109109
};
110110

111+
class DebugUnparseWithModulesAction : public PrescanAndSemaAction {
112+
void executeAction() override;
113+
};
114+
111115
class DebugUnparseAction : public PrescanAndSemaAction {
112116
void executeAction() override;
113117
};

flang/include/flang/Frontend/FrontendOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ enum ActionKind {
6363
/// Fortran source file
6464
DebugUnparseWithSymbols,
6565

66+
/// Parse, run semantics, and output a Fortran source file preceded
67+
/// by all the necessary modules (transitively)
68+
DebugUnparseWithModules,
69+
6670
/// Parse, run semantics and then output symbols from semantics
6771
DebugDumpSymbols,
6872

flang/include/flang/Semantics/unparse-with-symbols.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ struct Program;
2121
}
2222

2323
namespace Fortran::semantics {
24+
class SemanticsContext;
2425
void UnparseWithSymbols(llvm::raw_ostream &, const parser::Program &,
2526
parser::Encoding encoding = parser::Encoding::UTF_8);
27+
void UnparseWithModules(llvm::raw_ostream &, SemanticsContext &,
28+
const parser::Program &,
29+
parser::Encoding encoding = parser::Encoding::UTF_8);
2630
}
2731

2832
#endif // FORTRAN_SEMANTICS_UNPARSE_WITH_SYMBOLS_H_

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,9 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
488488
case clang::driver::options::OPT_fdebug_unparse_with_symbols:
489489
opts.programAction = DebugUnparseWithSymbols;
490490
break;
491+
case clang::driver::options::OPT_fdebug_unparse_with_modules:
492+
opts.programAction = DebugUnparseWithModules;
493+
break;
491494
case clang::driver::options::OPT_fdebug_dump_symbols:
492495
opts.programAction = DebugDumpSymbols;
493496
break;

flang/lib/Frontend/FrontendActions.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,15 @@ void DebugUnparseWithSymbolsAction::executeAction() {
477477
reportFatalSemanticErrors();
478478
}
479479

480+
void DebugUnparseWithModulesAction::executeAction() {
481+
auto &parseTree{*getInstance().getParsing().parseTree()};
482+
CompilerInstance &ci{getInstance()};
483+
Fortran::semantics::UnparseWithModules(
484+
llvm::outs(), ci.getSemantics().context(), parseTree,
485+
/*encoding=*/Fortran::parser::Encoding::UTF_8);
486+
reportFatalSemanticErrors();
487+
}
488+
480489
void DebugDumpSymbolsAction::executeAction() {
481490
CompilerInstance &ci = this->getInstance();
482491

flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ createFrontendAction(CompilerInstance &ci) {
5959
return std::make_unique<DebugUnparseNoSemaAction>();
6060
case DebugUnparseWithSymbols:
6161
return std::make_unique<DebugUnparseWithSymbolsAction>();
62+
case DebugUnparseWithModules:
63+
return std::make_unique<DebugUnparseWithModulesAction>();
6264
case DebugDumpSymbols:
6365
return std::make_unique<DebugDumpSymbolsAction>();
6466
case DebugDumpParseTree:

flang/lib/Semantics/mod-file.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,11 @@ static std::string ModFileName(const SourceName &name,
132132

133133
// Write the module file for symbol, which must be a module or submodule.
134134
void ModFileWriter::Write(const Symbol &symbol) {
135-
auto &module{symbol.get<ModuleDetails>()};
135+
const auto &module{symbol.get<ModuleDetails>()};
136136
if (module.moduleFileHash()) {
137137
return; // already written
138138
}
139-
auto *ancestor{module.ancestor()};
139+
const auto *ancestor{module.ancestor()};
140140
isSubmodule_ = ancestor != nullptr;
141141
auto ancestorName{ancestor ? ancestor->GetName().value().ToString() : ""s};
142142
auto path{context_.moduleDirectory() + '/' +
@@ -151,6 +151,21 @@ void ModFileWriter::Write(const Symbol &symbol) {
151151
const_cast<ModuleDetails &>(module).set_moduleFileHash(checkSum);
152152
}
153153

154+
void ModFileWriter::WriteClosure(llvm::raw_ostream &out, const Symbol &symbol,
155+
UnorderedSymbolSet &nonIntrinsicModulesWritten) {
156+
if (!symbol.has<ModuleDetails>() || symbol.owner().IsIntrinsicModules() ||
157+
!nonIntrinsicModulesWritten.insert(symbol).second) {
158+
return;
159+
}
160+
PutSymbols(DEREF(symbol.scope()));
161+
needsBuf_.clear(); // omit module checksums
162+
auto str{GetAsString(symbol)};
163+
for (auto depRef : std::move(usedNonIntrinsicModules_)) {
164+
WriteClosure(out, *depRef, nonIntrinsicModulesWritten);
165+
}
166+
out << std::move(str);
167+
}
168+
154169
// Return the entire body of the module file
155170
// and clear saved uses, decls, and contains.
156171
std::string ModFileWriter::GetAsString(const Symbol &symbol) {
@@ -710,6 +725,7 @@ void ModFileWriter::PutUse(const Symbol &symbol) {
710725
uses_ << "use,intrinsic::";
711726
} else {
712727
uses_ << "use ";
728+
usedNonIntrinsicModules_.insert(module);
713729
}
714730
uses_ << module.name() << ",only:";
715731
PutGenericName(uses_, symbol);

flang/lib/Semantics/mod-file.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class ModFileWriter {
3535
public:
3636
explicit ModFileWriter(SemanticsContext &context) : context_{context} {}
3737
bool WriteAll();
38+
void WriteClosure(llvm::raw_ostream &, const Symbol &,
39+
UnorderedSymbolSet &nonIntrinsicModulesWritten);
3840

3941
private:
4042
SemanticsContext &context_;
@@ -46,6 +48,7 @@ class ModFileWriter {
4648
std::string containsBuf_;
4749
// Tracks nested DEC structures and fields of that type
4850
UnorderedSymbolSet emittedDECStructures_, emittedDECFields_;
51+
UnorderedSymbolSet usedNonIntrinsicModules_;
4952

5053
llvm::raw_string_ostream needs_{needsBuf_};
5154
llvm::raw_string_ostream uses_{usesBuf_};

flang/lib/Semantics/unparse-with-symbols.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "flang/Semantics/unparse-with-symbols.h"
10+
#include "mod-file.h"
1011
#include "flang/Parser/parse-tree-visitor.h"
1112
#include "flang/Parser/parse-tree.h"
1213
#include "flang/Parser/unparse.h"
@@ -98,4 +99,41 @@ void UnparseWithSymbols(llvm::raw_ostream &out, const parser::Program &program,
9899
int indent) { visitor.PrintSymbols(location, out, indent); }};
99100
parser::Unparse(out, program, encoding, false, true, &preStatement);
100101
}
102+
103+
// UnparseWithModules()
104+
105+
class UsedModuleVisitor {
106+
public:
107+
UnorderedSymbolSet &modulesUsed() { return modulesUsed_; }
108+
UnorderedSymbolSet &modulesDefined() { return modulesDefined_; }
109+
template <typename T> bool Pre(const T &) { return true; }
110+
template <typename T> void Post(const T &) {}
111+
void Post(const parser::ModuleStmt &module) {
112+
if (module.v.symbol) {
113+
modulesDefined_.insert(*module.v.symbol);
114+
}
115+
}
116+
void Post(const parser::UseStmt &use) {
117+
if (use.moduleName.symbol) {
118+
modulesUsed_.insert(*use.moduleName.symbol);
119+
}
120+
}
121+
122+
private:
123+
UnorderedSymbolSet modulesUsed_;
124+
UnorderedSymbolSet modulesDefined_;
125+
};
126+
127+
void UnparseWithModules(llvm::raw_ostream &out, SemanticsContext &context,
128+
const parser::Program &program, parser::Encoding encoding) {
129+
UsedModuleVisitor visitor;
130+
parser::Walk(program, visitor);
131+
UnorderedSymbolSet nonIntrinsicModulesWritten{
132+
std::move(visitor.modulesDefined())};
133+
ModFileWriter writer{context};
134+
for (SymbolRef moduleRef : visitor.modulesUsed()) {
135+
writer.WriteClosure(out, *moduleRef, nonIntrinsicModulesWritten);
136+
}
137+
parser::Unparse(out, program, encoding, false, true);
138+
}
101139
} // namespace Fortran::semantics
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
! RUN: %flang_fc1 -I %S/Inputs/module-dir -fdebug-unparse-with-modules %s | FileCheck %s
2+
module m1
3+
use iso_fortran_env
4+
use BasicTestModuleTwo
5+
implicit none
6+
type(t2) y
7+
real(real32) x
8+
end
9+
10+
program test
11+
use m1
12+
use BasicTestModuleTwo
13+
implicit none
14+
x = 123.
15+
y = t2()
16+
end
17+
18+
!CHECK-NOT: module iso_fortran_env
19+
!CHECK: module basictestmoduletwo
20+
!CHECK: type::t2
21+
!CHECK: end type
22+
!CHECK: end
23+
!CHECK: module m1
24+
!CHECK: use :: iso_fortran_env
25+
!CHECK: implicit none
26+
!CHECK: real(kind=real32) x
27+
!CHECK: end module
28+
!CHECK: program test
29+
!CHECK: use :: m1
30+
!CHECK: use :: basictestmoduletwo
31+
!CHECK: implicit none
32+
!CHECK: x = 123.
33+
!CHECK: y = t2()
34+
!CHECK: end program

0 commit comments

Comments
 (0)