Skip to content

Commit

Permalink
[flang] New -fdebug-unparse-with-modules option (#91660)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
klausler authored May 15, 2024
1 parent 0585eed commit e00a3cc
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 3 deletions.
4 changes: 3 additions & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -6647,7 +6647,9 @@ def fdebug_unparse : Flag<["-"], "fdebug-unparse">, Group<Action_Group>,
DocBrief<[{Run the parser and the semantic checks. Then unparse the
parse-tree and output the generated Fortran source file.}]>;
def fdebug_unparse_with_symbols : Flag<["-"], "fdebug-unparse-with-symbols">, Group<Action_Group>,
HelpText<"Unparse and stop.">;
HelpText<"Unparse with symbols and stop.">;
def fdebug_unparse_with_modules : Flag<["-"], "fdebug-unparse-with-modules">, Group<Action_Group>,
HelpText<"Unparse with dependent modules and stop.">;
def fdebug_dump_symbols : Flag<["-"], "fdebug-dump-symbols">, Group<Action_Group>,
HelpText<"Dump symbols after the semantic analysis">;
def fdebug_dump_parse_tree : Flag<["-"], "fdebug-dump-parse-tree">, Group<Action_Group>,
Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ class DebugUnparseWithSymbolsAction : public PrescanAndSemaAction {
void executeAction() override;
};

class DebugUnparseWithModulesAction : public PrescanAndSemaAction {
void executeAction() override;
};

class DebugUnparseAction : public PrescanAndSemaAction {
void executeAction() override;
};
Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ enum ActionKind {
/// Fortran source file
DebugUnparseWithSymbols,

/// Parse, run semantics, and output a Fortran source file preceded
/// by all the necessary modules (transitively)
DebugUnparseWithModules,

/// Parse, run semantics and then output symbols from semantics
DebugDumpSymbols,

Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Semantics/unparse-with-symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ struct Program;
}

namespace Fortran::semantics {
class SemanticsContext;
void UnparseWithSymbols(llvm::raw_ostream &, const parser::Program &,
parser::Encoding encoding = parser::Encoding::UTF_8);
void UnparseWithModules(llvm::raw_ostream &, SemanticsContext &,
const parser::Program &,
parser::Encoding encoding = parser::Encoding::UTF_8);
}

#endif // FORTRAN_SEMANTICS_UNPARSE_WITH_SYMBOLS_H_
3 changes: 3 additions & 0 deletions flang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,9 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
case clang::driver::options::OPT_fdebug_unparse_with_symbols:
opts.programAction = DebugUnparseWithSymbols;
break;
case clang::driver::options::OPT_fdebug_unparse_with_modules:
opts.programAction = DebugUnparseWithModules;
break;
case clang::driver::options::OPT_fdebug_dump_symbols:
opts.programAction = DebugDumpSymbols;
break;
Expand Down
9 changes: 9 additions & 0 deletions flang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,15 @@ void DebugUnparseWithSymbolsAction::executeAction() {
reportFatalSemanticErrors();
}

void DebugUnparseWithModulesAction::executeAction() {
auto &parseTree{*getInstance().getParsing().parseTree()};
CompilerInstance &ci{getInstance()};
Fortran::semantics::UnparseWithModules(
llvm::outs(), ci.getSemantics().context(), parseTree,
/*encoding=*/Fortran::parser::Encoding::UTF_8);
reportFatalSemanticErrors();
}

void DebugDumpSymbolsAction::executeAction() {
CompilerInstance &ci = this->getInstance();

Expand Down
2 changes: 2 additions & 0 deletions flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ createFrontendAction(CompilerInstance &ci) {
return std::make_unique<DebugUnparseNoSemaAction>();
case DebugUnparseWithSymbols:
return std::make_unique<DebugUnparseWithSymbolsAction>();
case DebugUnparseWithModules:
return std::make_unique<DebugUnparseWithModulesAction>();
case DebugDumpSymbols:
return std::make_unique<DebugDumpSymbolsAction>();
case DebugDumpParseTree:
Expand Down
20 changes: 18 additions & 2 deletions flang/lib/Semantics/mod-file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() + '/' +
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions flang/lib/Semantics/mod-file.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand All @@ -46,6 +48,7 @@ class ModFileWriter {
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_};
Expand Down
38 changes: 38 additions & 0 deletions flang/lib/Semantics/unparse-with-symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
34 changes: 34 additions & 0 deletions flang/test/Driver/unparse-with-modules.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
! RUN: %flang_fc1 -I %S/Inputs/module-dir -fdebug-unparse-with-modules %s | FileCheck %s
module m1
use iso_fortran_env
use BasicTestModuleTwo
implicit none
type(t2) y
real(real32) x
end

program test
use m1
use BasicTestModuleTwo
implicit none
x = 123.
y = t2()
end

!CHECK-NOT: module iso_fortran_env
!CHECK: module basictestmoduletwo
!CHECK: type::t2
!CHECK: end type
!CHECK: end
!CHECK: module m1
!CHECK: use :: iso_fortran_env
!CHECK: implicit none
!CHECK: real(kind=real32) x
!CHECK: end module
!CHECK: program test
!CHECK: use :: m1
!CHECK: use :: basictestmoduletwo
!CHECK: implicit none
!CHECK: x = 123.
!CHECK: y = t2()
!CHECK: end program

0 comments on commit e00a3cc

Please sign in to comment.