Skip to content

Commit

Permalink
[flang][nfc] Move Semantics from FrontendAction to `CompilerInsta…
Browse files Browse the repository at this point in the history
…nce`

`CompilerInstance` is a more appropriate place for a key component of
the frontend like `Semantics`.

This change opens a path for us to introduce new frontend actions that
will also run semantics, but for which inheriting from
`PrescanAndSemaAction` wouldn't make much sense. For example, for
code-gen actions we plan to introduce a dedicate hierarchy of action
classes.

I've also added a doxyment for `CompilerInstance` to add a bit of
context for this change (and also make future refactoring more informed).
As `CompilerInstance` in Flang has been inspired by its counterpart in
Clang, this comment is roughly a verbatim copy of the comment in Clang
(with some adjustments from me). Credits to Daniel Dunbar for the great
design and the original comment.

Differential Revision: https://reviews.llvm.org/D108035
  • Loading branch information
banach-space committed Aug 15, 2021
1 parent c35e4dc commit 265a996
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 27 deletions.
24 changes: 24 additions & 0 deletions flang/include/flang/Frontend/CompilerInstance.h
Expand Up @@ -18,6 +18,21 @@

namespace Fortran::frontend {

/// Helper class for managing a single instance of the Flang compiler.
///
/// This class serves two purposes:
/// (1) It manages the various objects which are necessary to run the compiler
/// (2) It provides utility routines for constructing and manipulating the
/// common Flang objects.
///
/// The compiler instance generally owns the instance of all the objects that it
/// manages. However, clients can still share objects by manually setting the
/// object and retaking ownership prior to destroying the CompilerInstance.
///
/// The compiler instance is intended to simplify clients, but not to lock them
/// in to the compiler instance for everything. When possible, utility functions
/// come in two forms; a short form that reuses the CompilerInstance objects,
/// and a long form that takes explicit instances of any required objects.
class CompilerInstance {

/// The options used in this compiler instance.
Expand All @@ -30,6 +45,8 @@ class CompilerInstance {

std::shared_ptr<Fortran::parser::Parsing> parsing_;

std::unique_ptr<Fortran::semantics::Semantics> semantics_;

/// The stream for diagnostics from Semantics
llvm::raw_ostream *semaOutputStream_ = &llvm::errs();

Expand Down Expand Up @@ -110,6 +127,13 @@ class CompilerInstance {
/// Get the current stream for verbose output.
llvm::raw_ostream &semaOutputStream() { return *semaOutputStream_; }

Fortran::semantics::Semantics &semantics() { return *semantics_; }
const Fortran::semantics::Semantics &semantics() const { return *semantics_; }

void setSemantics(std::unique_ptr<Fortran::semantics::Semantics> semantics) {
semantics_ = std::move(semantics);
}

/// }
/// @name High-Level Operations
/// {
Expand Down
9 changes: 0 additions & 9 deletions flang/include/flang/Frontend/FrontendActions.h
Expand Up @@ -90,18 +90,9 @@ class DebugDumpParseTreeNoSemaAction : public PrescanAndParseAction {
// PrescanAndSema Actions
//===----------------------------------------------------------------------===//
class PrescanAndSemaAction : public FrontendAction {
std::unique_ptr<Fortran::semantics::Semantics> semantics_;

void ExecuteAction() override = 0;
bool BeginSourceFileAction(CompilerInstance &ci) override;

public:
Fortran::semantics::Semantics &semantics() { return *semantics_; }
const Fortran::semantics::Semantics &semantics() const { return *semantics_; }

void setSemantics(std::unique_ptr<Fortran::semantics::Semantics> semantics) {
semantics_ = std::move(semantics);
}
};

class DebugUnparseWithSymbolsAction : public PrescanAndSemaAction {
Expand Down
43 changes: 25 additions & 18 deletions flang/lib/Frontend/FrontendActions.cpp
Expand Up @@ -139,10 +139,10 @@ bool PrescanAndSemaAction::BeginSourceFileAction(CompilerInstance &c1) {
auto &parseTree{*ci.parsing().parseTree()};

// Prepare semantics
setSemantics(std::make_unique<Fortran::semantics::Semantics>(
ci.setSemantics(std::make_unique<Fortran::semantics::Semantics>(
ci.invocation().semanticsContext(), parseTree,
ci.invocation().debugModuleDir()));
auto &semantics = this->semantics();
auto &semantics = ci.semantics();

// Run semantic checks
semantics.Perform();
Expand Down Expand Up @@ -224,8 +224,10 @@ void DebugDumpProvenanceAction::ExecuteAction() {
}

void ParseSyntaxOnlyAction::ExecuteAction() {
reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
GetCurrentFileOrBufferName());
CompilerInstance &ci = this->instance();

reportFatalSemanticErrors(
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName());
}

void DebugUnparseNoSemaAction::ExecuteAction() {
Expand Down Expand Up @@ -256,24 +258,25 @@ void DebugUnparseAction::ExecuteAction() {
invoc.useAnalyzedObjectsForUnparse() ? &invoc.asFortran() : nullptr);

// Report fatal semantic errors
reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
reportFatalSemanticErrors(ci.semantics(), this->instance().diagnostics(),
GetCurrentFileOrBufferName());
}

void DebugUnparseWithSymbolsAction::ExecuteAction() {
CompilerInstance &ci = this->instance();
auto &parseTree{*instance().parsing().parseTree()};

Fortran::semantics::UnparseWithSymbols(
llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8);

// Report fatal semantic errors
reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
GetCurrentFileOrBufferName());
reportFatalSemanticErrors(
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName());
}

void DebugDumpSymbolsAction::ExecuteAction() {
CompilerInstance &ci = this->instance();
auto &semantics = this->semantics();
auto &semantics = ci.semantics();

auto tables{Fortran::semantics::BuildRuntimeDerivedTypeTables(
instance().invocation().semanticsContext())};
Expand Down Expand Up @@ -306,7 +309,7 @@ void DebugDumpAllAction::ExecuteAction() {
Fortran::parser::DumpTree(
llvm::outs(), parseTree, &ci.invocation().asFortran());

auto &semantics = this->semantics();
auto &semantics = ci.semantics();
auto tables{Fortran::semantics::BuildRuntimeDerivedTypeTables(
instance().invocation().semanticsContext())};
// The runtime derived type information table builder may find and report
Expand Down Expand Up @@ -339,15 +342,16 @@ void DebugDumpParseTreeNoSemaAction::ExecuteAction() {
}

void DebugDumpParseTreeAction::ExecuteAction() {
CompilerInstance &ci = this->instance();
auto &parseTree{instance().parsing().parseTree()};

// Dump parse tree
Fortran::parser::DumpTree(
llvm::outs(), parseTree, &this->instance().invocation().asFortran());

// Report fatal semantic errors
reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
GetCurrentFileOrBufferName());
reportFatalSemanticErrors(
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName());
}

void DebugMeasureParseTreeAction::ExecuteAction() {
Expand Down Expand Up @@ -385,7 +389,7 @@ void DebugPreFIRTreeAction::ExecuteAction() {
CompilerInstance &ci = this->instance();
// Report and exit if fatal semantic errors are present
if (reportFatalSemanticErrors(
semantics(), ci.diagnostics(), GetCurrentFileOrBufferName())) {
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName())) {
return;
}

Expand All @@ -410,12 +414,13 @@ void DebugDumpParsingLogAction::ExecuteAction() {
}

void GetDefinitionAction::ExecuteAction() {
CompilerInstance &ci = this->instance();

// Report and exit if fatal semantic errors are present
if (reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
GetCurrentFileOrBufferName()))
if (reportFatalSemanticErrors(
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName()))
return;

CompilerInstance &ci = this->instance();
parser::AllCookedSources &cs = ci.allCookedSources();
unsigned diagID = ci.diagnostics().getCustomDiagID(
clang::DiagnosticsEngine::Error, "Symbol not found");
Expand Down Expand Up @@ -457,12 +462,14 @@ void GetDefinitionAction::ExecuteAction() {
}

void GetSymbolsSourcesAction::ExecuteAction() {
CompilerInstance &ci = this->instance();

// Report and exit if fatal semantic errors are present
if (reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
GetCurrentFileOrBufferName()))
if (reportFatalSemanticErrors(
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName()))
return;

semantics().DumpSymbolsSources(llvm::outs());
ci.semantics().DumpSymbolsSources(llvm::outs());
}

void EmitObjAction::ExecuteAction() {
Expand Down

0 comments on commit 265a996

Please sign in to comment.