2020-10-24 12:33:19 +01:00
|
|
|
//===--- FrontendActions.cpp ----------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2020-10-27 12:26:47 +00:00
|
|
|
|
2020-10-24 12:33:19 +01:00
|
|
|
#include "flang/Frontend/FrontendActions.h"
|
2020-12-08 16:27:46 +00:00
|
|
|
#include "flang/Common/default-kinds.h"
|
2020-10-24 12:33:19 +01:00
|
|
|
#include "flang/Frontend/CompilerInstance.h"
|
2021-02-04 11:14:57 +00:00
|
|
|
#include "flang/Frontend/FrontendOptions.h"
|
2021-04-07 11:42:37 +00:00
|
|
|
#include "flang/Frontend/PreprocessorOptions.h"
|
2022-02-03 17:00:27 +00:00
|
|
|
#include "flang/Lower/Bridge.h"
|
2021-02-17 18:53:05 +00:00
|
|
|
#include "flang/Lower/PFTBuilder.h"
|
2022-02-03 17:00:27 +00:00
|
|
|
#include "flang/Lower/Support/Verifier.h"
|
2022-02-04 17:15:12 +00:00
|
|
|
#include "flang/Optimizer/Support/FIRContext.h"
|
2022-02-03 17:00:27 +00:00
|
|
|
#include "flang/Optimizer/Support/InitFIR.h"
|
|
|
|
#include "flang/Optimizer/Support/KindMapping.h"
|
|
|
|
#include "flang/Optimizer/Support/Utils.h"
|
2021-02-17 15:55:56 +00:00
|
|
|
#include "flang/Parser/dump-parse-tree.h"
|
2020-10-27 12:26:47 +00:00
|
|
|
#include "flang/Parser/parsing.h"
|
|
|
|
#include "flang/Parser/provenance.h"
|
2020-10-24 12:33:19 +01:00
|
|
|
#include "flang/Parser/source.h"
|
2021-02-04 11:14:57 +00:00
|
|
|
#include "flang/Parser/unparse.h"
|
2021-03-08 16:54:11 +00:00
|
|
|
#include "flang/Semantics/runtime-type-info.h"
|
2020-12-08 16:27:46 +00:00
|
|
|
#include "flang/Semantics/semantics.h"
|
2021-02-04 11:14:57 +00:00
|
|
|
#include "flang/Semantics/unparse-with-symbols.h"
|
2022-02-03 17:00:27 +00:00
|
|
|
|
|
|
|
#include "mlir/IR/Dialect.h"
|
|
|
|
#include "mlir/Pass/PassManager.h"
|
2022-02-04 17:15:12 +00:00
|
|
|
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
|
2021-02-17 15:55:56 +00:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2022-02-24 17:34:27 +00:00
|
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
|
|
#include "llvm/Analysis/TargetTransformInfo.h"
|
2022-04-06 11:59:28 +00:00
|
|
|
#include "llvm/Bitcode/BitcodeWriterPass.h"
|
2022-02-24 17:34:27 +00:00
|
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
|
|
#include "llvm/MC/TargetRegistry.h"
|
|
|
|
#include "llvm/Passes/PassBuilder.h"
|
2021-04-14 10:43:14 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2022-02-24 17:34:27 +00:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
2021-02-17 15:55:56 +00:00
|
|
|
#include <clang/Basic/Diagnostic.h>
|
|
|
|
#include <memory>
|
2020-10-24 12:33:19 +01:00
|
|
|
|
|
|
|
using namespace Fortran::frontend;
|
|
|
|
|
2021-08-13 16:27:46 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Custom BeginSourceFileAction
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
bool PrescanAction::BeginSourceFileAction() { return RunPrescan(); }
|
2021-03-30 10:35:42 +00:00
|
|
|
|
2021-08-13 16:27:46 +00:00
|
|
|
bool PrescanAndParseAction::BeginSourceFileAction() {
|
|
|
|
return RunPrescan() && RunParse();
|
2021-03-30 10:35:42 +00:00
|
|
|
}
|
|
|
|
|
2021-08-13 16:27:46 +00:00
|
|
|
bool PrescanAndSemaAction::BeginSourceFileAction() {
|
2022-02-17 13:32:32 +00:00
|
|
|
return RunPrescan() && RunParse() && RunSemanticChecks() &&
|
|
|
|
GenerateRtTypeTables();
|
2021-02-04 11:14:57 +00:00
|
|
|
}
|
|
|
|
|
2021-10-07 11:33:07 +00:00
|
|
|
bool PrescanAndSemaDebugAction::BeginSourceFileAction() {
|
2022-02-17 13:32:32 +00:00
|
|
|
// This is a "debug" action for development purposes. To facilitate this, the
|
|
|
|
// semantic checks are made to succeed unconditionally to prevent this action
|
|
|
|
// from exiting early (i.e. in the presence of semantic errors). We should
|
|
|
|
// never do this in actions intended for end-users or otherwise regular
|
|
|
|
// compiler workflows!
|
|
|
|
return RunPrescan() && RunParse() && (RunSemanticChecks() || true) &&
|
|
|
|
(GenerateRtTypeTables() || true);
|
2021-10-07 11:33:07 +00:00
|
|
|
}
|
|
|
|
|
2022-02-03 17:00:27 +00:00
|
|
|
bool CodeGenAction::BeginSourceFileAction() {
|
|
|
|
bool res = RunPrescan() && RunParse() && RunSemanticChecks();
|
|
|
|
if (!res)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
|
|
|
|
// Load the MLIR dialects required by Flang
|
|
|
|
mlir::DialectRegistry registry;
|
|
|
|
mlirCtx = std::make_unique<mlir::MLIRContext>(registry);
|
|
|
|
fir::support::registerNonCodegenDialects(registry);
|
|
|
|
fir::support::loadNonCodegenDialects(*mlirCtx);
|
|
|
|
|
|
|
|
// Create a LoweringBridge
|
|
|
|
const common::IntrinsicTypeDefaultKinds &defKinds =
|
|
|
|
ci.invocation().semanticsContext().defaultKinds();
|
|
|
|
fir::KindMapping kindMap(mlirCtx.get(),
|
|
|
|
llvm::ArrayRef<fir::KindTy>{fir::fromDefaultKinds(defKinds)});
|
|
|
|
lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create(*mlirCtx,
|
|
|
|
defKinds, ci.invocation().semanticsContext().intrinsics(),
|
[flang][driver] Add support for `--target`/`--triple`
This patch adds support for:
* `--target` in the compiler driver (`flang-new`)
* `--triple` in the frontend driver (`flang-new -fc1`)
The semantics of these flags are inherited from `clangDriver`, i.e.
consistent with `clang --target` and `clang -cc1 --triple`,
respectively.
A new structure is defined, `TargetOptions`, that will hold various
Frontend options related to the target. Currently, this is mostly a
placeholder that contains the target triple. In the future, it will be
used for storing e.g. the CPU to tune for or the target features to
enable.
Additionally, the following target/triple related options are enabled
[*]: `-print-effective-triple`, `-print-target-triple`. Definitions in
Options.td are updated accordingly and, to facilated testing,
`-emit-llvm` is added to the list of options available in `flang-new`
(previously it was only enabled in `flang-new -fc1`).
[*] These options were actually available before (like all other options
defined in `clangDriver`), but not included in `flang-new --help`.
Before this change, `flang-new` would just use `native` for defining the
target, so these options were of little value.
Differential Revision: https://reviews.llvm.org/D120246
2022-02-21 11:51:32 +00:00
|
|
|
ci.parsing().allCooked(), ci.invocation().targetOpts().triple, kindMap);
|
2022-02-03 17:00:27 +00:00
|
|
|
|
|
|
|
// Create a parse tree and lower it to FIR
|
|
|
|
Fortran::parser::Program &parseTree{*ci.parsing().parseTree()};
|
|
|
|
lb.lower(parseTree, ci.invocation().semanticsContext());
|
|
|
|
mlirModule = std::make_unique<mlir::ModuleOp>(lb.getModule());
|
|
|
|
|
|
|
|
// Run the default passes.
|
|
|
|
mlir::PassManager pm(mlirCtx.get(), mlir::OpPassManager::Nesting::Implicit);
|
|
|
|
pm.enableVerifier(/*verifyPasses=*/true);
|
|
|
|
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
|
|
|
|
|
|
|
|
if (mlir::failed(pm.run(*mlirModule))) {
|
|
|
|
unsigned diagID =
|
|
|
|
ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
|
|
|
|
"verification of lowering to FIR failed");
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-13 16:27:46 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Custom ExecuteAction
|
|
|
|
//===----------------------------------------------------------------------===//
|
2021-02-04 13:06:43 +00:00
|
|
|
void InputOutputTestAction::ExecuteAction() {
|
2021-02-04 16:23:42 +00:00
|
|
|
CompilerInstance &ci = instance();
|
|
|
|
|
|
|
|
// Create a stream for errors
|
2020-10-24 12:33:19 +01:00
|
|
|
std::string buf;
|
|
|
|
llvm::raw_string_ostream error_stream{buf};
|
|
|
|
|
2021-02-04 16:23:42 +00:00
|
|
|
// Read the input file
|
2020-10-28 10:47:48 +00:00
|
|
|
Fortran::parser::AllSources &allSources{ci.allSources()};
|
2021-02-04 16:23:42 +00:00
|
|
|
std::string path{GetCurrentFileOrBufferName()};
|
2020-10-24 12:33:19 +01:00
|
|
|
const Fortran::parser::SourceFile *sf;
|
2021-02-04 16:23:42 +00:00
|
|
|
if (path == "-")
|
|
|
|
sf = allSources.ReadStandardInput(error_stream);
|
|
|
|
else
|
|
|
|
sf = allSources.Open(path, error_stream, std::optional<std::string>{"."s});
|
2020-10-24 12:33:19 +01:00
|
|
|
llvm::ArrayRef<char> fileContent = sf->content();
|
|
|
|
|
2021-02-04 16:23:42 +00:00
|
|
|
// Output file descriptor to receive the contents of the input file.
|
2020-10-24 12:33:19 +01:00
|
|
|
std::unique_ptr<llvm::raw_ostream> os;
|
|
|
|
|
2021-02-04 16:23:42 +00:00
|
|
|
// Copy the contents from the input file to the output file
|
|
|
|
if (!ci.IsOutputStreamNull()) {
|
|
|
|
// An output stream (outputStream_) was set earlier
|
|
|
|
ci.WriteOutputStream(fileContent.data());
|
|
|
|
} else {
|
|
|
|
// No pre-set output stream - create an output file
|
2020-10-24 12:33:19 +01:00
|
|
|
os = ci.CreateDefaultOutputFile(
|
2021-02-04 16:23:42 +00:00
|
|
|
/*binary=*/true, GetCurrentFileOrBufferName(), "txt");
|
2020-10-24 12:33:19 +01:00
|
|
|
if (!os)
|
|
|
|
return;
|
|
|
|
(*os) << fileContent.data();
|
|
|
|
}
|
|
|
|
}
|
2020-10-27 12:26:47 +00:00
|
|
|
|
|
|
|
void PrintPreprocessedAction::ExecuteAction() {
|
|
|
|
std::string buf;
|
|
|
|
llvm::raw_string_ostream outForPP{buf};
|
|
|
|
|
2021-07-23 16:41:04 -07:00
|
|
|
// Format or dump the prescanner's output
|
2020-10-27 12:26:47 +00:00
|
|
|
CompilerInstance &ci = this->instance();
|
2021-07-23 16:41:04 -07:00
|
|
|
if (ci.invocation().preprocessorOpts().noReformat) {
|
|
|
|
ci.parsing().DumpCookedChars(outForPP);
|
|
|
|
} else {
|
|
|
|
ci.parsing().EmitPreprocessedSource(
|
|
|
|
outForPP, !ci.invocation().preprocessorOpts().noLineDirectives);
|
|
|
|
}
|
2020-10-27 12:26:47 +00:00
|
|
|
|
2021-08-20 10:25:11 +00:00
|
|
|
// Print diagnostics from the prescanner
|
|
|
|
ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
|
|
|
|
|
2020-10-27 12:26:47 +00:00
|
|
|
// If a pre-defined output stream exists, dump the preprocessed content there
|
|
|
|
if (!ci.IsOutputStreamNull()) {
|
|
|
|
// Send the output to the pre-defined output buffer.
|
|
|
|
ci.WriteOutputStream(outForPP.str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a file and save the preprocessed output there
|
2021-08-20 10:25:11 +00:00
|
|
|
std::unique_ptr<llvm::raw_pwrite_stream> os{ci.CreateDefaultOutputFile(
|
|
|
|
/*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName())};
|
|
|
|
if (!os) {
|
|
|
|
return;
|
2020-10-27 12:26:47 +00:00
|
|
|
}
|
2021-08-20 10:25:11 +00:00
|
|
|
|
|
|
|
(*os) << outForPP.str();
|
2020-10-27 12:26:47 +00:00
|
|
|
}
|
2020-12-08 16:27:46 +00:00
|
|
|
|
2021-02-17 15:55:56 +00:00
|
|
|
void DebugDumpProvenanceAction::ExecuteAction() {
|
|
|
|
this->instance().parsing().DumpProvenance(llvm::outs());
|
|
|
|
}
|
|
|
|
|
|
|
|
void ParseSyntaxOnlyAction::ExecuteAction() {
|
|
|
|
}
|
2021-01-06 09:54:30 +00:00
|
|
|
|
2021-03-30 10:35:42 +00:00
|
|
|
void DebugUnparseNoSemaAction::ExecuteAction() {
|
2021-06-04 15:25:58 +01:00
|
|
|
auto &invoc = this->instance().invocation();
|
2021-03-30 10:35:42 +00:00
|
|
|
auto &parseTree{instance().parsing().parseTree()};
|
|
|
|
|
|
|
|
// TODO: Options should come from CompilerInvocation
|
|
|
|
Unparse(llvm::outs(), *parseTree,
|
|
|
|
/*encoding=*/Fortran::parser::Encoding::UTF_8,
|
|
|
|
/*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
|
2021-06-04 15:25:58 +01:00
|
|
|
/*preStatement=*/nullptr,
|
|
|
|
invoc.useAnalyzedObjectsForUnparse() ? &invoc.asFortran() : nullptr);
|
2021-03-30 10:35:42 +00:00
|
|
|
}
|
|
|
|
|
2021-02-04 11:14:57 +00:00
|
|
|
void DebugUnparseAction::ExecuteAction() {
|
2021-06-04 15:25:58 +01:00
|
|
|
auto &invoc = this->instance().invocation();
|
2021-02-04 11:14:57 +00:00
|
|
|
auto &parseTree{instance().parsing().parseTree()};
|
2020-12-08 16:27:46 +00:00
|
|
|
|
2021-07-01 09:33:00 +01:00
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
auto os{ci.CreateDefaultOutputFile(
|
|
|
|
/*Binary=*/false, /*InFile=*/GetCurrentFileOrBufferName())};
|
|
|
|
|
2021-02-04 11:14:57 +00:00
|
|
|
// TODO: Options should come from CompilerInvocation
|
2021-07-01 09:33:00 +01:00
|
|
|
Unparse(*os, *parseTree,
|
2021-02-04 11:14:57 +00:00
|
|
|
/*encoding=*/Fortran::parser::Encoding::UTF_8,
|
|
|
|
/*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
|
2021-06-04 15:25:58 +01:00
|
|
|
/*preStatement=*/nullptr,
|
|
|
|
invoc.useAnalyzedObjectsForUnparse() ? &invoc.asFortran() : nullptr);
|
2021-02-17 15:55:56 +00:00
|
|
|
|
|
|
|
// Report fatal semantic errors
|
2021-08-13 16:27:46 +00:00
|
|
|
reportFatalSemanticErrors();
|
2021-02-04 11:14:57 +00:00
|
|
|
}
|
2020-12-08 16:27:46 +00:00
|
|
|
|
2021-02-04 11:14:57 +00:00
|
|
|
void DebugUnparseWithSymbolsAction::ExecuteAction() {
|
|
|
|
auto &parseTree{*instance().parsing().parseTree()};
|
2020-12-08 16:27:46 +00:00
|
|
|
|
2021-02-04 11:14:57 +00:00
|
|
|
Fortran::semantics::UnparseWithSymbols(
|
|
|
|
llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8);
|
2021-02-17 15:55:56 +00:00
|
|
|
|
|
|
|
// Report fatal semantic errors
|
2021-08-13 16:27:46 +00:00
|
|
|
reportFatalSemanticErrors();
|
2021-02-17 15:55:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DebugDumpSymbolsAction::ExecuteAction() {
|
2021-04-16 14:07:09 +00:00
|
|
|
CompilerInstance &ci = this->instance();
|
2021-02-17 15:55:56 +00:00
|
|
|
|
2022-02-17 13:32:32 +00:00
|
|
|
if (!ci.getRtTyTables().schemata) {
|
2021-04-16 14:07:09 +00:00
|
|
|
unsigned DiagID =
|
|
|
|
ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
|
|
|
|
"could not find module file for __fortran_type_info");
|
|
|
|
ci.diagnostics().Report(DiagID);
|
|
|
|
llvm::errs() << "\n";
|
2022-02-17 13:32:32 +00:00
|
|
|
return;
|
2021-04-16 14:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Dump symbols
|
2022-02-17 13:32:32 +00:00
|
|
|
ci.semantics().DumpSymbols(llvm::outs());
|
2021-02-17 15:55:56 +00:00
|
|
|
}
|
|
|
|
|
2021-06-15 15:30:23 +00:00
|
|
|
void DebugDumpAllAction::ExecuteAction() {
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
|
|
|
|
// Dump parse tree
|
|
|
|
auto &parseTree{instance().parsing().parseTree()};
|
|
|
|
llvm::outs() << "========================";
|
|
|
|
llvm::outs() << " Flang: parse tree dump ";
|
|
|
|
llvm::outs() << "========================\n";
|
2021-06-04 15:25:58 +01:00
|
|
|
Fortran::parser::DumpTree(
|
|
|
|
llvm::outs(), parseTree, &ci.invocation().asFortran());
|
2021-06-15 15:30:23 +00:00
|
|
|
|
2022-02-17 13:32:32 +00:00
|
|
|
if (!ci.getRtTyTables().schemata) {
|
2021-06-15 15:30:23 +00:00
|
|
|
unsigned DiagID =
|
|
|
|
ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
|
|
|
|
"could not find module file for __fortran_type_info");
|
|
|
|
ci.diagnostics().Report(DiagID);
|
|
|
|
llvm::errs() << "\n";
|
2022-02-17 13:32:32 +00:00
|
|
|
return;
|
2021-06-15 15:30:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Dump symbols
|
|
|
|
llvm::outs() << "=====================";
|
|
|
|
llvm::outs() << " Flang: symbols dump ";
|
|
|
|
llvm::outs() << "=====================\n";
|
2022-02-17 13:32:32 +00:00
|
|
|
ci.semantics().DumpSymbols(llvm::outs());
|
2021-06-15 15:30:23 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 10:35:42 +00:00
|
|
|
void DebugDumpParseTreeNoSemaAction::ExecuteAction() {
|
|
|
|
auto &parseTree{instance().parsing().parseTree()};
|
|
|
|
|
|
|
|
// Dump parse tree
|
2021-06-04 15:25:58 +01:00
|
|
|
Fortran::parser::DumpTree(
|
|
|
|
llvm::outs(), parseTree, &this->instance().invocation().asFortran());
|
2021-03-30 10:35:42 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 15:55:56 +00:00
|
|
|
void DebugDumpParseTreeAction::ExecuteAction() {
|
|
|
|
auto &parseTree{instance().parsing().parseTree()};
|
|
|
|
|
|
|
|
// Dump parse tree
|
2021-06-04 15:25:58 +01:00
|
|
|
Fortran::parser::DumpTree(
|
|
|
|
llvm::outs(), parseTree, &this->instance().invocation().asFortran());
|
|
|
|
|
2021-02-17 15:55:56 +00:00
|
|
|
// Report fatal semantic errors
|
2021-08-13 16:27:46 +00:00
|
|
|
reportFatalSemanticErrors();
|
2020-12-08 16:27:46 +00:00
|
|
|
}
|
[flang][driver] Add support for `-c` and `-emit-obj`
This patch adds a frontend action for emitting object files. While Flang
does not support code-generation, this action remains a placeholder.
This patch simply provides glue-code to connect the compiler driver
with the appropriate frontend action.
The new action is triggered with the `-c` compiler driver flag, i.e.
`flang-new -c`. This is then translated to `flang-new -fc1 -emit-obj`,
so `-emit-obj` has to be marked as supported as well.
As code-generation is not available yet, `flang-new -c` results in a
driver error:
```
error: code-generation is not available yet
```
Hopefully this will help communicating the level of available
functionality within Flang.
The definition of `emit-obj` is updated so that it can be shared between
Clang and Flang. As the original definition was enclosed within a
Clang-specific TableGen `let` statement, it is extracted into a new `let`
statement. That felt like the cleanest option.
I also commented out `-triple` in Flang::ConstructJob and updated some
comments there. This is similar to https://reviews.llvm.org/D93027. I
wanted to make sure that it's clear that we can't support `-triple`
until we have code-generation. However, once code-generation is
available we _will need_ `-triple`.
As this patch adds `-emit-obj`, the emit-obj.f90 becomes irrelevant and
is deleted. Instead, phases.f90 is added to demonstrate that users can
control compilation phases (indeed, `-c` is a phase control flag).
Reviewed By: SouraVX, clementval
Differential Revision: https://reviews.llvm.org/D93301
2021-01-07 09:08:54 +00:00
|
|
|
|
2021-02-17 18:53:05 +00:00
|
|
|
void DebugMeasureParseTreeAction::ExecuteAction() {
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
|
|
|
|
// Parse. In case of failure, report and return.
|
|
|
|
ci.parsing().Parse(llvm::outs());
|
|
|
|
|
2021-04-05 12:41:46 -04:00
|
|
|
if (!ci.parsing().messages().empty() &&
|
|
|
|
(ci.invocation().warnAsErr() ||
|
|
|
|
ci.parsing().messages().AnyFatalError())) {
|
2021-02-17 18:53:05 +00:00
|
|
|
unsigned diagID = ci.diagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Could not parse %0");
|
|
|
|
ci.diagnostics().Report(diagID) << GetCurrentFileOrBufferName();
|
|
|
|
|
|
|
|
ci.parsing().messages().Emit(
|
|
|
|
llvm::errs(), this->instance().allCookedSources());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Report the diagnostics from parsing
|
|
|
|
ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
|
|
|
|
|
|
|
|
auto &parseTree{*ci.parsing().parseTree()};
|
|
|
|
|
|
|
|
// Measure the parse tree
|
|
|
|
MeasurementVisitor visitor;
|
|
|
|
Fortran::parser::Walk(parseTree, visitor);
|
|
|
|
llvm::outs() << "Parse tree comprises " << visitor.objects
|
|
|
|
<< " objects and occupies " << visitor.bytes
|
|
|
|
<< " total bytes.\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebugPreFIRTreeAction::ExecuteAction() {
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
// Report and exit if fatal semantic errors are present
|
2021-08-13 16:27:46 +00:00
|
|
|
if (reportFatalSemanticErrors()) {
|
2021-02-17 18:53:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto &parseTree{*ci.parsing().parseTree()};
|
|
|
|
|
|
|
|
// Dump pre-FIR tree
|
|
|
|
if (auto ast{Fortran::lower::createPFT(
|
|
|
|
parseTree, ci.invocation().semanticsContext())}) {
|
|
|
|
Fortran::lower::dumpPFT(llvm::outs(), *ast);
|
|
|
|
} else {
|
|
|
|
unsigned diagID = ci.diagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL.");
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-23 17:59:17 +00:00
|
|
|
void DebugDumpParsingLogAction::ExecuteAction() {
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
|
|
|
|
ci.parsing().Parse(llvm::errs());
|
|
|
|
ci.parsing().DumpParsingLog(llvm::outs());
|
|
|
|
}
|
|
|
|
|
2021-04-14 10:43:14 +00:00
|
|
|
void GetDefinitionAction::ExecuteAction() {
|
2021-08-13 13:03:21 +00:00
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
|
2021-04-14 10:43:14 +00:00
|
|
|
// Report and exit if fatal semantic errors are present
|
2021-08-13 16:27:46 +00:00
|
|
|
if (reportFatalSemanticErrors()) {
|
2021-04-14 10:43:14 +00:00
|
|
|
return;
|
2021-08-13 16:27:46 +00:00
|
|
|
}
|
2021-04-14 10:43:14 +00:00
|
|
|
|
|
|
|
parser::AllCookedSources &cs = ci.allCookedSources();
|
|
|
|
unsigned diagID = ci.diagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Symbol not found");
|
|
|
|
|
2021-07-29 12:39:10 +00:00
|
|
|
auto gdv = ci.invocation().frontendOpts().getDefVals;
|
2021-04-14 10:43:14 +00:00
|
|
|
auto charBlock{cs.GetCharBlockFromLineAndColumns(
|
|
|
|
gdv.line, gdv.startColumn, gdv.endColumn)};
|
|
|
|
if (!charBlock) {
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::outs() << "String range: >" << charBlock->ToString() << "<\n";
|
|
|
|
|
|
|
|
auto *symbol{ci.invocation()
|
|
|
|
.semanticsContext()
|
|
|
|
.FindScope(*charBlock)
|
|
|
|
.FindSymbol(*charBlock)};
|
|
|
|
if (!symbol) {
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n";
|
|
|
|
|
|
|
|
auto sourceInfo{cs.GetSourcePositionRange(symbol->name())};
|
|
|
|
if (!sourceInfo) {
|
|
|
|
llvm_unreachable(
|
|
|
|
"Failed to obtain SourcePosition."
|
|
|
|
"TODO: Please, write a test and replace this with a diagnostic!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n";
|
|
|
|
llvm::outs() << symbol->name().ToString() << ": "
|
|
|
|
<< sourceInfo->first.file.path() << ", "
|
|
|
|
<< sourceInfo->first.line << ", " << sourceInfo->first.column
|
|
|
|
<< "-" << sourceInfo->second.column << "\n";
|
|
|
|
}
|
|
|
|
|
2021-03-08 16:54:11 +00:00
|
|
|
void GetSymbolsSourcesAction::ExecuteAction() {
|
2021-08-13 13:03:21 +00:00
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
|
2021-03-08 16:54:11 +00:00
|
|
|
// Report and exit if fatal semantic errors are present
|
2021-08-13 16:27:46 +00:00
|
|
|
if (reportFatalSemanticErrors()) {
|
2021-03-08 16:54:11 +00:00
|
|
|
return;
|
2021-08-13 16:27:46 +00:00
|
|
|
}
|
2021-03-08 16:54:11 +00:00
|
|
|
|
2021-08-13 13:03:21 +00:00
|
|
|
ci.semantics().DumpSymbolsSources(llvm::outs());
|
2021-03-08 16:54:11 +00:00
|
|
|
}
|
|
|
|
|
2022-02-04 17:15:12 +00:00
|
|
|
#include "flang/Tools/CLOptions.inc"
|
|
|
|
|
|
|
|
// Lower the previously generated MLIR module into an LLVM IR module
|
|
|
|
void CodeGenAction::GenerateLLVMIR() {
|
|
|
|
assert(mlirModule && "The MLIR module has not been generated yet.");
|
|
|
|
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
|
|
|
|
fir::support::loadDialects(*mlirCtx);
|
|
|
|
fir::support::registerLLVMTranslation(*mlirCtx);
|
|
|
|
|
|
|
|
// Set-up the MLIR pass manager
|
|
|
|
mlir::PassManager pm(mlirCtx.get(), mlir::OpPassManager::Nesting::Implicit);
|
|
|
|
|
|
|
|
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
|
|
|
|
pm.enableVerifier(/*verifyPasses=*/true);
|
|
|
|
|
|
|
|
// Create the pass pipeline
|
|
|
|
fir::createMLIRToLLVMPassPipeline(pm);
|
|
|
|
|
|
|
|
// Run the pass manager
|
|
|
|
if (!mlir::succeeded(pm.run(*mlirModule))) {
|
|
|
|
unsigned diagID = ci.diagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Lowering to LLVM IR failed");
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translate to LLVM IR
|
|
|
|
llvm::Optional<llvm::StringRef> moduleName = mlirModule->getName();
|
|
|
|
llvmCtx = std::make_unique<llvm::LLVMContext>();
|
|
|
|
llvmModule = mlir::translateModuleToLLVMIR(
|
|
|
|
*mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule");
|
|
|
|
|
|
|
|
if (!llvmModule) {
|
|
|
|
unsigned diagID = ci.diagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "failed to create the LLVM module");
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmitLLVMAction::ExecuteAction() {
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
GenerateLLVMIR();
|
|
|
|
|
|
|
|
// If set, use the predefined outupt stream to print the generated module.
|
|
|
|
if (!ci.IsOutputStreamNull()) {
|
|
|
|
llvmModule->print(
|
|
|
|
ci.GetOutputStream(), /*AssemblyAnnotationWriter=*/nullptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No predefined output stream was set. Create an output file and dump the
|
|
|
|
// generated module there.
|
|
|
|
std::unique_ptr<llvm::raw_ostream> os = ci.CreateDefaultOutputFile(
|
|
|
|
/*Binary=*/false, /*InFile=*/GetCurrentFileOrBufferName(), "ll");
|
|
|
|
if (!os) {
|
|
|
|
unsigned diagID = ci.diagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "failed to create the output file");
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
llvmModule->print(*os, /*AssemblyAnnotationWriter=*/nullptr);
|
|
|
|
}
|
|
|
|
|
2022-04-06 11:59:28 +00:00
|
|
|
void EmitLLVMBitcodeAction::ExecuteAction() {
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
// Generate an LLVM module if it's not already present (it will already be
|
|
|
|
// present if the input file is an LLVM IR/BC file).
|
|
|
|
if (!llvmModule)
|
|
|
|
GenerateLLVMIR();
|
|
|
|
|
|
|
|
// Create and configure `Target`
|
|
|
|
std::string error;
|
|
|
|
std::string theTriple = llvmModule->getTargetTriple();
|
|
|
|
const llvm::Target *theTarget =
|
|
|
|
llvm::TargetRegistry::lookupTarget(theTriple, error);
|
|
|
|
assert(theTarget && "Failed to create Target");
|
|
|
|
|
|
|
|
// Create and configure `TargetMachine`
|
|
|
|
std::unique_ptr<llvm::TargetMachine> TM(
|
|
|
|
theTarget->createTargetMachine(theTriple, /*CPU=*/"",
|
|
|
|
/*Features=*/"", llvm::TargetOptions(), llvm::None));
|
|
|
|
assert(TM && "Failed to create TargetMachine");
|
|
|
|
llvmModule->setDataLayout(TM->createDataLayout());
|
|
|
|
|
|
|
|
// Generate an output file
|
|
|
|
std::unique_ptr<llvm::raw_ostream> os = ci.CreateDefaultOutputFile(
|
|
|
|
/*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName(), "bc");
|
|
|
|
if (!os) {
|
|
|
|
unsigned diagID = ci.diagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "failed to create the output file");
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set-up the pass manager
|
|
|
|
llvm::ModulePassManager MPM;
|
|
|
|
llvm::ModuleAnalysisManager MAM;
|
|
|
|
llvm::PassBuilder PB(TM.get());
|
|
|
|
PB.registerModuleAnalyses(MAM);
|
|
|
|
MPM.addPass(llvm::BitcodeWriterPass(*os));
|
|
|
|
|
|
|
|
// Run the passes
|
|
|
|
MPM.run(*llvmModule, MAM);
|
|
|
|
}
|
|
|
|
|
2022-02-03 17:00:27 +00:00
|
|
|
void EmitMLIRAction::ExecuteAction() {
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
|
|
|
|
// Print the output. If a pre-defined output stream exists, dump the MLIR
|
|
|
|
// content there.
|
|
|
|
if (!ci.IsOutputStreamNull()) {
|
|
|
|
mlirModule->print(ci.GetOutputStream());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ... otherwise, print to a file.
|
|
|
|
std::unique_ptr<llvm::raw_pwrite_stream> os{ci.CreateDefaultOutputFile(
|
|
|
|
/*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName(), "mlir")};
|
|
|
|
if (!os) {
|
|
|
|
unsigned diagID = ci.diagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "failed to create the output file");
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mlirModule->print(*os);
|
|
|
|
}
|
|
|
|
|
2022-02-24 17:34:27 +00:00
|
|
|
void BackendAction::ExecuteAction() {
|
[flang][driver] Add support for `-c` and `-emit-obj`
This patch adds a frontend action for emitting object files. While Flang
does not support code-generation, this action remains a placeholder.
This patch simply provides glue-code to connect the compiler driver
with the appropriate frontend action.
The new action is triggered with the `-c` compiler driver flag, i.e.
`flang-new -c`. This is then translated to `flang-new -fc1 -emit-obj`,
so `-emit-obj` has to be marked as supported as well.
As code-generation is not available yet, `flang-new -c` results in a
driver error:
```
error: code-generation is not available yet
```
Hopefully this will help communicating the level of available
functionality within Flang.
The definition of `emit-obj` is updated so that it can be shared between
Clang and Flang. As the original definition was enclosed within a
Clang-specific TableGen `let` statement, it is extracted into a new `let`
statement. That felt like the cleanest option.
I also commented out `-triple` in Flang::ConstructJob and updated some
comments there. This is similar to https://reviews.llvm.org/D93027. I
wanted to make sure that it's clear that we can't support `-triple`
until we have code-generation. However, once code-generation is
available we _will need_ `-triple`.
As this patch adds `-emit-obj`, the emit-obj.f90 becomes irrelevant and
is deleted. Instead, phases.f90 is added to demonstrate that users can
control compilation phases (indeed, `-c` is a phase control flag).
Reviewed By: SouraVX, clementval
Differential Revision: https://reviews.llvm.org/D93301
2021-01-07 09:08:54 +00:00
|
|
|
CompilerInstance &ci = this->instance();
|
2022-02-24 17:34:27 +00:00
|
|
|
// Generate an LLVM module if it's not already present (it will already be
|
|
|
|
// present if the input file is an LLVM IR/BC file).
|
|
|
|
if (!llvmModule)
|
|
|
|
GenerateLLVMIR();
|
|
|
|
|
|
|
|
// Create `Target`
|
|
|
|
std::string error;
|
|
|
|
const std::string &theTriple = llvmModule->getTargetTriple();
|
|
|
|
const llvm::Target *theTarget =
|
|
|
|
llvm::TargetRegistry::lookupTarget(theTriple, error);
|
|
|
|
// TODO: Make this a diagnostic once `flang-new` can consume LLVM IR files
|
|
|
|
// (in which users could use unsupported triples)
|
|
|
|
assert(theTarget && "Failed to create Target");
|
|
|
|
|
|
|
|
// Create `TargetMachine`
|
2022-04-13 10:28:49 +00:00
|
|
|
std::unique_ptr<llvm::TargetMachine> TM(
|
|
|
|
theTarget->createTargetMachine(theTriple, /*CPU=*/"",
|
|
|
|
/*Features=*/"", llvm::TargetOptions(), llvm::None));
|
2022-02-24 17:34:27 +00:00
|
|
|
assert(TM && "Failed to create TargetMachine");
|
|
|
|
llvmModule->setDataLayout(TM->createDataLayout());
|
|
|
|
|
|
|
|
// If the output stream is a file, generate it and define the corresponding
|
|
|
|
// output stream. If a pre-defined output stream is available, we will use
|
|
|
|
// that instead.
|
|
|
|
//
|
|
|
|
// NOTE: `os` is a smart pointer that will be destroyed at the end of this
|
|
|
|
// method. However, it won't be written to until `CodeGenPasses` is
|
|
|
|
// destroyed. By defining `os` before `CodeGenPasses`, we make sure that the
|
|
|
|
// output stream won't be destroyed before it is written to. This only
|
|
|
|
// applies when an output file is used (i.e. there is no pre-defined output
|
|
|
|
// stream).
|
|
|
|
// TODO: Revisit once the new PM is ready (i.e. when `CodeGenPasses` is
|
|
|
|
// updated to use it).
|
|
|
|
std::unique_ptr<llvm::raw_pwrite_stream> os;
|
|
|
|
if (ci.IsOutputStreamNull()) {
|
|
|
|
// Get the output buffer/file
|
|
|
|
switch (action) {
|
|
|
|
case BackendActionTy::Backend_EmitAssembly:
|
|
|
|
os = ci.CreateDefaultOutputFile(
|
|
|
|
/*Binary=*/false, /*InFile=*/GetCurrentFileOrBufferName(), "s");
|
|
|
|
break;
|
|
|
|
case BackendActionTy::Backend_EmitObj:
|
|
|
|
os = ci.CreateDefaultOutputFile(
|
|
|
|
/*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName(), "o");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!os) {
|
|
|
|
unsigned diagID = ci.diagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "failed to create the output file");
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an LLVM code-gen pass pipeline. Currently only the legacy pass
|
|
|
|
// manager is supported.
|
|
|
|
// TODO: Switch to the new PM once it's available in the backend.
|
|
|
|
llvm::legacy::PassManager CodeGenPasses;
|
|
|
|
CodeGenPasses.add(
|
|
|
|
createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
|
|
|
|
llvm::Triple triple(theTriple);
|
|
|
|
|
|
|
|
std::unique_ptr<llvm::TargetLibraryInfoImpl> TLII =
|
|
|
|
std::make_unique<llvm::TargetLibraryInfoImpl>(triple);
|
|
|
|
assert(TLII && "Failed to create TargetLibraryInfo");
|
|
|
|
CodeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*TLII));
|
|
|
|
|
|
|
|
llvm::CodeGenFileType cgft = (action == BackendActionTy::Backend_EmitAssembly)
|
|
|
|
? llvm::CodeGenFileType::CGFT_AssemblyFile
|
|
|
|
: llvm::CodeGenFileType::CGFT_ObjectFile;
|
|
|
|
if (TM->addPassesToEmitFile(CodeGenPasses,
|
|
|
|
ci.IsOutputStreamNull() ? *os : ci.GetOutputStream(), nullptr,
|
|
|
|
cgft)) {
|
|
|
|
unsigned diagID =
|
|
|
|
ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
|
|
|
|
"emission of this file type is not supported");
|
|
|
|
ci.diagnostics().Report(diagID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run the code-gen passes
|
|
|
|
CodeGenPasses.run(*llvmModule);
|
[flang][driver] Add support for `-c` and `-emit-obj`
This patch adds a frontend action for emitting object files. While Flang
does not support code-generation, this action remains a placeholder.
This patch simply provides glue-code to connect the compiler driver
with the appropriate frontend action.
The new action is triggered with the `-c` compiler driver flag, i.e.
`flang-new -c`. This is then translated to `flang-new -fc1 -emit-obj`,
so `-emit-obj` has to be marked as supported as well.
As code-generation is not available yet, `flang-new -c` results in a
driver error:
```
error: code-generation is not available yet
```
Hopefully this will help communicating the level of available
functionality within Flang.
The definition of `emit-obj` is updated so that it can be shared between
Clang and Flang. As the original definition was enclosed within a
Clang-specific TableGen `let` statement, it is extracted into a new `let`
statement. That felt like the cleanest option.
I also commented out `-triple` in Flang::ConstructJob and updated some
comments there. This is similar to https://reviews.llvm.org/D93027. I
wanted to make sure that it's clear that we can't support `-triple`
until we have code-generation. However, once code-generation is
available we _will need_ `-triple`.
As this patch adds `-emit-obj`, the emit-obj.f90 becomes irrelevant and
is deleted. Instead, phases.f90 is added to demonstrate that users can
control compilation phases (indeed, `-c` is a phase control flag).
Reviewed By: SouraVX, clementval
Differential Revision: https://reviews.llvm.org/D93301
2021-01-07 09:08:54 +00:00
|
|
|
}
|
2021-06-07 15:40:26 +01:00
|
|
|
|
|
|
|
void InitOnlyAction::ExecuteAction() {
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
unsigned DiagID =
|
|
|
|
ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Warning,
|
|
|
|
"Use `-init-only` for testing purposes only");
|
|
|
|
ci.diagnostics().Report(DiagID);
|
|
|
|
}
|
2021-08-12 11:42:08 +01:00
|
|
|
|
|
|
|
void PluginParseTreeAction::ExecuteAction() {}
|
2022-03-08 10:01:55 +00:00
|
|
|
|
|
|
|
void DebugDumpPFTAction::ExecuteAction() {
|
|
|
|
CompilerInstance &ci = this->instance();
|
|
|
|
|
|
|
|
if (auto ast = Fortran::lower::createPFT(
|
|
|
|
*ci.parsing().parseTree(), ci.semantics().context())) {
|
|
|
|
Fortran::lower::dumpPFT(llvm::outs(), *ast);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned DiagID = ci.diagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL.");
|
|
|
|
ci.diagnostics().Report(DiagID);
|
|
|
|
}
|