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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2022-04-29 17:36:26 +00:00
|
|
|
//
|
|
|
|
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
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"
|
2023-03-14 17:40:04 +00:00
|
|
|
#include "flang/Frontend/CompilerInvocation.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"
|
2023-03-08 18:39:40 -08:00
|
|
|
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
|
|
|
|
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
|
2022-02-03 17:00:27 +00:00
|
|
|
#include "flang/Optimizer/Support/InitFIR.h"
|
|
|
|
#include "flang/Optimizer/Support/Utils.h"
|
2023-07-10 10:55:47 -04:00
|
|
|
#include "flang/Optimizer/Transforms/Passes.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"
|
2023-03-28 10:24:35 -05:00
|
|
|
#include "flang/Tools/CrossToolHelpers.h"
|
2022-02-03 17:00:27 +00:00
|
|
|
|
|
|
|
#include "mlir/IR/Dialect.h"
|
2022-06-01 16:00:31 +00:00
|
|
|
#include "mlir/Parser/Parser.h"
|
2022-02-03 17:00:27 +00:00
|
|
|
#include "mlir/Pass/PassManager.h"
|
2022-09-02 10:18:12 +01:00
|
|
|
#include "mlir/Support/LLVM.h"
|
|
|
|
#include "mlir/Target/LLVMIR/Import.h"
|
2022-02-04 17:15:12 +00:00
|
|
|
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
|
2022-04-29 17:36:26 +00:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
[flang][driver] Define the default frontend driver triple
*SUMMARY*
Currently, the frontend driver assumes that a target triple is either:
* provided by the frontend itself (e.g. when lowering and generating
code),
* specified through the `-triple/-target` command line flags.
If `-triple/-target` is not used, the frontend will simply use the host
triple.
This is going to be insufficient when e.g. consuming an LLVM IR file
that has no triple specified (reading LLVM files is WIP, see D124667).
We shouldn't require the triple to be specified via the command line in
such situation. Instead, the frontend driver should contain a good
default, e.g. the host triple.
This patch updates Flang's `CompilerInvocation` to do just that, i.e.
defines its default target triple. Similarly to Clang:
* the default `CompilerInvocation` triple is set as the host triple,
* the value specified with `-triple` takes precedence over the frontend
driver default and the current module triple,
* the frontend driver default takes precedence over the module triple.
*TESTS*
This change requires 2 unit tests to be updated. That's because relevant
frontend actions are updated to assume that there's always a valid
triple available in the current `CompilerInvocation`. This update is
required because the unit tests bypass the regular `CompilerInvocation`
set-up (in particular, they don't call
`CompilerInvocation::CreateFromArgs`). I've also taken the liberty to
disable the pre-precossor formatting in the affected unit tests as well
(it is not required).
No new tests are added. As `flang-new -fc1` does not support consuming
LLVM IR files just yet, it is not possible to compile an LLVM IR file
without a triple. More specifically, atm all LLVM IR files are generated
and stored internally and the driver makes sure that these contain a
valid target triple. This is about to change in D124667 (which adds
support for reading LLVM IR/BC files) and that's where tests for
exercising the default frontend driver triple will be added.
*WHAT DOES CLANG DO?*
For reference, the default target triple for Clang's
`CompilerInvocation` is set through option marshalling infra [1] in
Options.td. Please check the definition of the `-triple` flag:
```
def triple : Separate<["-"], "triple">,
HelpText<"Specify target triple (e.g. i686-apple-darwin9)">,
MarshallingInfoString<TargetOpts<"Triple">, "llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple())">,
AlwaysEmit, Normalizer<"normalizeTriple">;
```
Ideally, we should re-use the marshalling infra in Flang.
[1] https://clang.llvm.org/docs/InternalsManual.html#option-marshalling-infrastructure
Differential Revision: https://reviews.llvm.org/D124664
2022-04-28 14:12:32 +00:00
|
|
|
#include "clang/Basic/DiagnosticFrontend.h"
|
2023-07-27 21:57:54 +00:00
|
|
|
#include "clang/Driver/DriverDiagnostic.h"
|
2023-03-14 17:40:04 +00:00
|
|
|
#include "llvm/ADT/SmallString.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"
|
2023-07-27 21:57:54 +00:00
|
|
|
#include "llvm/IR/LLVMRemarkStreamer.h"
|
2022-02-24 17:34:27 +00:00
|
|
|
#include "llvm/IR/LegacyPassManager.h"
|
2022-06-06 17:57:33 +00:00
|
|
|
#include "llvm/IR/Verifier.h"
|
2022-04-22 09:07:31 +00:00
|
|
|
#include "llvm/IRReader/IRReader.h"
|
2022-02-24 17:34:27 +00:00
|
|
|
#include "llvm/MC/TargetRegistry.h"
|
2023-01-20 14:33:22 -05:00
|
|
|
#include "llvm/Object/OffloadBinary.h"
|
2022-02-24 17:34:27 +00:00
|
|
|
#include "llvm/Passes/PassBuilder.h"
|
2022-11-10 07:56:03 -07:00
|
|
|
#include "llvm/Passes/PassPlugin.h"
|
2022-06-06 09:44:21 +00:00
|
|
|
#include "llvm/Passes/StandardInstrumentations.h"
|
2023-07-27 21:57:54 +00:00
|
|
|
#include "llvm/Support/Error.h"
|
2021-04-14 10:43:14 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2023-03-14 17:40:04 +00:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
2022-04-22 09:07:31 +00:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2023-03-14 17:40:04 +00:00
|
|
|
#include "llvm/Support/ToolOutputFile.h"
|
2022-02-24 17:34:27 +00:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
2023-03-27 07:19:40 -05:00
|
|
|
#include "llvm/TargetParser/TargetParser.h"
|
2023-01-20 14:33:22 -05:00
|
|
|
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
2021-02-17 15:55:56 +00:00
|
|
|
#include <memory>
|
2023-03-14 17:40:04 +00:00
|
|
|
#include <system_error>
|
2020-10-24 12:33:19 +01:00
|
|
|
|
|
|
|
using namespace Fortran::frontend;
|
|
|
|
|
2022-11-10 14:09:51 -08:00
|
|
|
// Declare plugin extension function declarations.
|
|
|
|
#define HANDLE_EXTENSION(Ext) \
|
|
|
|
llvm::PassPluginLibraryInfo get##Ext##PluginInfo();
|
|
|
|
#include "llvm/Support/Extension.def"
|
|
|
|
|
2023-03-14 17:40:04 +00:00
|
|
|
/// Save the given \c mlirModule to a temporary .mlir file, in a location
|
|
|
|
/// decided by the -save-temps flag. No files are produced if the flag is not
|
|
|
|
/// specified.
|
|
|
|
static bool saveMLIRTempFile(const CompilerInvocation &ci,
|
|
|
|
mlir::ModuleOp mlirModule,
|
|
|
|
llvm::StringRef inputFile,
|
|
|
|
llvm::StringRef outputTag) {
|
|
|
|
if (!ci.getCodeGenOpts().SaveTempsDir.has_value())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const llvm::StringRef compilerOutFile = ci.getFrontendOpts().outputFile;
|
|
|
|
const llvm::StringRef saveTempsDir = ci.getCodeGenOpts().SaveTempsDir.value();
|
|
|
|
auto dir = llvm::StringSwitch<llvm::StringRef>(saveTempsDir)
|
|
|
|
.Case("cwd", "")
|
|
|
|
.Case("obj", llvm::sys::path::parent_path(compilerOutFile))
|
|
|
|
.Default(saveTempsDir);
|
|
|
|
|
|
|
|
// Build path from the compiler output file name, triple, cpu and OpenMP
|
|
|
|
// information
|
|
|
|
llvm::SmallString<256> path(dir);
|
|
|
|
llvm::sys::path::append(path, llvm::sys::path::stem(inputFile) + "-" +
|
|
|
|
outputTag + ".mlir");
|
|
|
|
|
|
|
|
std::error_code ec;
|
|
|
|
llvm::ToolOutputFile out(path, ec, llvm::sys::fs::OF_Text);
|
|
|
|
if (ec)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
mlirModule->print(out.os());
|
|
|
|
out.os().close();
|
|
|
|
out.keep();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-13 16:27:46 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Custom BeginSourceFileAction
|
|
|
|
//===----------------------------------------------------------------------===//
|
2022-04-22 09:07:31 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
bool PrescanAction::beginSourceFileAction() { return runPrescan(); }
|
2021-03-30 10:35:42 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
bool PrescanAndParseAction::beginSourceFileAction() {
|
|
|
|
return runPrescan() && runParse();
|
2021-03-30 10:35:42 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
bool PrescanAndSemaAction::beginSourceFileAction() {
|
|
|
|
return runPrescan() && runParse() && runSemanticChecks() &&
|
|
|
|
generateRtTypeTables();
|
2021-02-04 11:14:57 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +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!
|
2022-04-29 17:36:26 +00:00
|
|
|
return runPrescan() && runParse() && (runSemanticChecks() || true) &&
|
|
|
|
(generateRtTypeTables() || true);
|
2021-10-07 11:33:07 +00:00
|
|
|
}
|
|
|
|
|
2023-03-27 07:19:40 -05:00
|
|
|
// Get feature string which represents combined explicit target features
|
|
|
|
// for AMD GPU and the target features specified by the user
|
|
|
|
static std::string
|
|
|
|
getExplicitAndImplicitAMDGPUTargetFeatures(CompilerInstance &ci,
|
|
|
|
const TargetOptions &targetOpts,
|
|
|
|
const llvm::Triple triple) {
|
|
|
|
llvm::StringRef cpu = targetOpts.cpu;
|
|
|
|
llvm::StringMap<bool> implicitFeaturesMap;
|
|
|
|
std::string errorMsg;
|
|
|
|
// Get the set of implicit target features
|
|
|
|
llvm::AMDGPU::fillAMDGPUFeatureMap(cpu, triple, implicitFeaturesMap);
|
|
|
|
|
|
|
|
// Add target features specified by the user
|
|
|
|
for (auto &userFeature : targetOpts.featuresAsWritten) {
|
|
|
|
std::string userKeyString = userFeature.substr(1);
|
|
|
|
implicitFeaturesMap[userKeyString] = (userFeature[0] == '+');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!llvm::AMDGPU::insertWaveSizeFeature(cpu, triple, implicitFeaturesMap,
|
|
|
|
errorMsg)) {
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Unsupported feature ID: %0");
|
|
|
|
ci.getDiagnostics().Report(diagID) << errorMsg.data();
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::SmallVector<std::string> featuresVec;
|
|
|
|
for (auto &implicitFeatureItem : implicitFeaturesMap) {
|
|
|
|
featuresVec.push_back((llvm::Twine(implicitFeatureItem.second ? "+" : "-") +
|
|
|
|
implicitFeatureItem.first().str())
|
|
|
|
.str());
|
|
|
|
}
|
2023-07-22 15:57:41 -07:00
|
|
|
llvm::sort(featuresVec);
|
2023-03-27 07:19:40 -05:00
|
|
|
return llvm::join(featuresVec, ",");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Produces the string which represents target feature
|
|
|
|
static std::string getTargetFeatures(CompilerInstance &ci) {
|
|
|
|
const TargetOptions &targetOpts = ci.getInvocation().getTargetOpts();
|
|
|
|
const llvm::Triple triple(targetOpts.triple);
|
|
|
|
|
|
|
|
// Clang does not append all target features to the clang -cc1 invocation.
|
|
|
|
// Some target features are parsed implicitly by clang::TargetInfo child
|
|
|
|
// class. Clang::TargetInfo classes are the basic clang classes and
|
|
|
|
// they cannot be reused by Flang.
|
|
|
|
// That's why we need to extract implicit target features and add
|
|
|
|
// them to the target features specified by the user
|
|
|
|
if (triple.isAMDGPU()) {
|
|
|
|
return getExplicitAndImplicitAMDGPUTargetFeatures(ci, targetOpts, triple);
|
|
|
|
}
|
|
|
|
return llvm::join(targetOpts.featuresAsWritten.begin(),
|
|
|
|
targetOpts.featuresAsWritten.end(), ",");
|
|
|
|
}
|
|
|
|
|
2022-09-02 10:18:12 +01:00
|
|
|
static void setMLIRDataLayout(mlir::ModuleOp &mlirModule,
|
|
|
|
const llvm::DataLayout &dl) {
|
|
|
|
mlir::MLIRContext *context = mlirModule.getContext();
|
|
|
|
mlirModule->setAttr(
|
|
|
|
mlir::LLVM::LLVMDialect::getDataLayoutAttrName(),
|
|
|
|
mlir::StringAttr::get(context, dl.getStringRepresentation()));
|
|
|
|
mlir::DataLayoutSpecInterface dlSpec = mlir::translateDataLayout(dl, context);
|
|
|
|
mlirModule->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
|
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
bool CodeGenAction::beginSourceFileAction() {
|
2022-04-22 09:07:31 +00:00
|
|
|
llvmCtx = std::make_unique<llvm::LLVMContext>();
|
2022-06-06 17:57:33 +00:00
|
|
|
CompilerInstance &ci = this->getInstance();
|
2022-04-22 09:07:31 +00:00
|
|
|
|
|
|
|
// If the input is an LLVM file, just parse it and return.
|
2022-04-29 17:36:26 +00:00
|
|
|
if (this->getCurrentInput().getKind().getLanguage() == Language::LLVM_IR) {
|
2022-04-22 09:07:31 +00:00
|
|
|
llvm::SMDiagnostic err;
|
2022-04-29 17:36:26 +00:00
|
|
|
llvmModule = llvm::parseIRFile(getCurrentInput().getFile(), err, *llvmCtx);
|
2022-06-06 17:57:33 +00:00
|
|
|
if (!llvmModule || llvm::verifyModule(*llvmModule, &llvm::errs())) {
|
|
|
|
err.print("flang-new", llvm::errs());
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Could not parse IR");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
|
|
|
return false;
|
|
|
|
}
|
2022-04-22 09:07:31 +00:00
|
|
|
|
2022-06-06 17:57:33 +00:00
|
|
|
return true;
|
2022-04-22 09:07:31 +00:00
|
|
|
}
|
|
|
|
|
2022-06-01 16:00:31 +00:00
|
|
|
// 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);
|
|
|
|
fir::support::loadDialects(*mlirCtx);
|
|
|
|
fir::support::registerLLVMTranslation(*mlirCtx);
|
|
|
|
|
|
|
|
// If the input is an MLIR file, just parse it and return.
|
|
|
|
if (this->getCurrentInput().getKind().getLanguage() == Language::MLIR) {
|
|
|
|
llvm::SourceMgr sourceMgr;
|
|
|
|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =
|
|
|
|
llvm::MemoryBuffer::getFileOrSTDIN(getCurrentInput().getFile());
|
|
|
|
sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), llvm::SMLoc());
|
|
|
|
mlir::OwningOpRef<mlir::ModuleOp> module =
|
|
|
|
mlir::parseSourceFile<mlir::ModuleOp>(sourceMgr, mlirCtx.get());
|
|
|
|
|
|
|
|
if (!module || mlir::failed(module->verifyInvariants())) {
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Could not parse FIR");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mlirModule = std::make_unique<mlir::ModuleOp>(module.release());
|
2023-03-20 12:05:18 -07:00
|
|
|
if (!setUpTargetMachine())
|
|
|
|
return false;
|
2022-09-02 10:18:12 +01:00
|
|
|
const llvm::DataLayout &dl = tm->createDataLayout();
|
|
|
|
setMLIRDataLayout(*mlirModule, dl);
|
2022-06-01 16:00:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-04-22 09:07:31 +00:00
|
|
|
// Otherwise, generate an MLIR module from the input Fortran source
|
2022-06-06 17:57:33 +00:00
|
|
|
if (getCurrentInput().getKind().getLanguage() != Language::Fortran) {
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error,
|
|
|
|
"Invalid input type - expecting a Fortran file");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
|
|
|
return false;
|
|
|
|
}
|
2022-06-08 14:37:12 +00:00
|
|
|
bool res = runPrescan() && runParse() && runSemanticChecks() &&
|
|
|
|
generateRtTypeTables();
|
2022-02-03 17:00:27 +00:00
|
|
|
if (!res)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
// Create a LoweringBridge
|
|
|
|
const common::IntrinsicTypeDefaultKinds &defKinds =
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getInvocation().getSemanticsContext().defaultKinds();
|
2022-08-12 21:22:30 +02:00
|
|
|
fir::KindMapping kindMap(mlirCtx.get(), llvm::ArrayRef<fir::KindTy>{
|
|
|
|
fir::fromDefaultKinds(defKinds)});
|
2022-04-29 17:36:26 +00:00
|
|
|
lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create(
|
2022-08-12 21:22:30 +02:00
|
|
|
*mlirCtx, ci.getInvocation().getSemanticsContext(), defKinds,
|
|
|
|
ci.getInvocation().getSemanticsContext().intrinsics(),
|
2022-07-01 11:40:44 -07:00
|
|
|
ci.getInvocation().getSemanticsContext().targetCharacteristics(),
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple,
|
2022-07-19 11:47:25 -07:00
|
|
|
kindMap, ci.getInvocation().getLoweringOpts(),
|
2023-01-19 16:49:26 +00:00
|
|
|
ci.getInvocation().getFrontendOpts().envDefaults);
|
2022-02-03 17:00:27 +00:00
|
|
|
|
2022-09-02 10:18:12 +01:00
|
|
|
// Fetch module from lb, so we can set
|
|
|
|
mlirModule = std::make_unique<mlir::ModuleOp>(lb.getModule());
|
2023-03-07 12:39:16 -06:00
|
|
|
|
2023-03-30 08:42:53 -05:00
|
|
|
if (!setUpTargetMachine())
|
|
|
|
return false;
|
|
|
|
|
2023-03-07 12:39:16 -06:00
|
|
|
if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
|
|
|
|
Fortran::common::LanguageFeature::OpenMP)) {
|
2023-04-05 12:34:57 -05:00
|
|
|
setOffloadModuleInterfaceAttributes(*mlirModule,
|
|
|
|
ci.getInvocation().getLangOpts());
|
2023-03-30 08:42:53 -05:00
|
|
|
setOffloadModuleInterfaceTargetAttribute(*mlirModule, tm->getTargetCPU(),
|
|
|
|
tm->getTargetFeatureString());
|
2023-05-19 06:14:52 -05:00
|
|
|
setOpenMPVersionAttribute(*mlirModule,
|
|
|
|
ci.getInvocation().getLangOpts().OpenMPVersion);
|
2023-03-07 12:39:16 -06:00
|
|
|
}
|
|
|
|
|
2022-09-02 10:18:12 +01:00
|
|
|
const llvm::DataLayout &dl = tm->createDataLayout();
|
|
|
|
setMLIRDataLayout(*mlirModule, dl);
|
|
|
|
|
2022-02-03 17:00:27 +00:00
|
|
|
// Create a parse tree and lower it to FIR
|
2022-04-29 17:36:26 +00:00
|
|
|
Fortran::parser::Program &parseTree{*ci.getParsing().parseTree()};
|
|
|
|
lb.lower(parseTree, ci.getInvocation().getSemanticsContext());
|
2022-02-03 17:00:27 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
// run the default passes.
|
2022-11-08 23:23:28 -05:00
|
|
|
mlir::PassManager pm((*mlirModule)->getName(),
|
|
|
|
mlir::OpPassManager::Nesting::Implicit);
|
2023-07-10 10:55:47 -04:00
|
|
|
// Add OpenMP-related passes
|
|
|
|
// WARNING: These passes must be run immediately after the lowering to ensure
|
|
|
|
// that the FIR is correct with respect to OpenMP operations/attributes.
|
|
|
|
if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
|
|
|
|
Fortran::common::LanguageFeature::OpenMP)) {
|
|
|
|
bool isDevice = false;
|
|
|
|
if (auto offloadMod = llvm::dyn_cast<mlir::omp::OffloadModuleInterface>(
|
|
|
|
mlirModule->getOperation()))
|
|
|
|
isDevice = offloadMod.getIsTargetDevice();
|
|
|
|
|
2023-07-17 08:20:13 -05:00
|
|
|
pm.addPass(fir::createOMPMarkDeclareTargetPass());
|
2023-07-18 15:08:58 -05:00
|
|
|
if (isDevice) {
|
2023-07-10 10:55:47 -04:00
|
|
|
pm.addPass(fir::createOMPEarlyOutliningPass());
|
2023-07-18 15:08:58 -05:00
|
|
|
// FIXME: This should eventually be moved out of the
|
|
|
|
// if, so that it also functions for host, however,
|
|
|
|
// we must fix the filtering to function reasonably
|
|
|
|
// for host first.
|
|
|
|
pm.addPass(fir::createOMPFunctionFilteringPass());
|
|
|
|
}
|
2023-07-10 10:55:47 -04:00
|
|
|
}
|
|
|
|
|
2022-02-03 17:00:27 +00:00
|
|
|
pm.enableVerifier(/*verifyPasses=*/true);
|
|
|
|
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
|
|
|
|
|
|
|
|
if (mlir::failed(pm.run(*mlirModule))) {
|
2022-04-29 17:36:26 +00:00
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error,
|
|
|
|
"verification of lowering to FIR failed");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
2022-02-03 17:00:27 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-03-14 17:40:04 +00:00
|
|
|
// Print initial full MLIR module, before lowering or transformations, if
|
|
|
|
// -save-temps has been specified.
|
|
|
|
if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(),
|
|
|
|
"fir")) {
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Saving MLIR temp file failed");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-02-03 17:00:27 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-13 16:27:46 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Custom ExecuteAction
|
|
|
|
//===----------------------------------------------------------------------===//
|
2022-04-29 17:36:26 +00:00
|
|
|
void InputOutputTestAction::executeAction() {
|
|
|
|
CompilerInstance &ci = getInstance();
|
2021-02-04 16:23:42 +00:00
|
|
|
|
|
|
|
// Create a stream for errors
|
2020-10-24 12:33:19 +01:00
|
|
|
std::string buf;
|
2022-04-29 17:36:26 +00:00
|
|
|
llvm::raw_string_ostream errorStream{buf};
|
2020-10-24 12:33:19 +01:00
|
|
|
|
2021-02-04 16:23:42 +00:00
|
|
|
// Read the input file
|
2022-04-29 17:36:26 +00:00
|
|
|
Fortran::parser::AllSources &allSources{ci.getAllSources()};
|
|
|
|
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 == "-")
|
2022-04-29 17:36:26 +00:00
|
|
|
sf = allSources.ReadStandardInput(errorStream);
|
2021-02-04 16:23:42 +00:00
|
|
|
else
|
2022-04-29 17:36:26 +00:00
|
|
|
sf = allSources.Open(path, errorStream, 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
|
2022-04-29 17:36:26 +00:00
|
|
|
if (!ci.isOutputStreamNull()) {
|
2021-02-04 16:23:42 +00:00
|
|
|
// An output stream (outputStream_) was set earlier
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.writeOutputStream(fileContent.data());
|
2021-02-04 16:23:42 +00:00
|
|
|
} else {
|
|
|
|
// No pre-set output stream - create an output file
|
2022-04-29 17:36:26 +00:00
|
|
|
os = ci.createDefaultOutputFile(
|
|
|
|
/*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
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void PrintPreprocessedAction::executeAction() {
|
2020-10-27 12:26:47 +00:00
|
|
|
std::string buf;
|
|
|
|
llvm::raw_string_ostream outForPP{buf};
|
|
|
|
|
2021-07-23 16:41:04 -07:00
|
|
|
// Format or dump the prescanner's output
|
2022-04-29 17:36:26 +00:00
|
|
|
CompilerInstance &ci = this->getInstance();
|
|
|
|
if (ci.getInvocation().getPreprocessorOpts().noReformat) {
|
|
|
|
ci.getParsing().DumpCookedChars(outForPP);
|
2021-07-23 16:41:04 -07:00
|
|
|
} else {
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getParsing().EmitPreprocessedSource(
|
|
|
|
outForPP, !ci.getInvocation().getPreprocessorOpts().noLineDirectives);
|
2021-07-23 16:41:04 -07:00
|
|
|
}
|
2020-10-27 12:26:47 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
// Print getDiagnostics from the prescanner
|
|
|
|
ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());
|
2021-08-20 10:25:11 +00:00
|
|
|
|
2020-10-27 12:26:47 +00:00
|
|
|
// If a pre-defined output stream exists, dump the preprocessed content there
|
2022-04-29 17:36:26 +00:00
|
|
|
if (!ci.isOutputStreamNull()) {
|
2020-10-27 12:26:47 +00:00
|
|
|
// Send the output to the pre-defined output buffer.
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.writeOutputStream(outForPP.str());
|
2020-10-27 12:26:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a file and save the preprocessed output there
|
2022-04-29 17:36:26 +00:00
|
|
|
std::unique_ptr<llvm::raw_pwrite_stream> os{ci.createDefaultOutputFile(
|
|
|
|
/*Binary=*/true, /*InFile=*/getCurrentFileOrBufferName())};
|
2021-08-20 10:25:11 +00:00
|
|
|
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
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugDumpProvenanceAction::executeAction() {
|
|
|
|
this->getInstance().getParsing().DumpProvenance(llvm::outs());
|
2021-02-17 15:55:56 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void ParseSyntaxOnlyAction::executeAction() {}
|
2021-01-06 09:54:30 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugUnparseNoSemaAction::executeAction() {
|
|
|
|
auto &invoc = this->getInstance().getInvocation();
|
|
|
|
auto &parseTree{getInstance().getParsing().parseTree()};
|
2021-03-30 10:35:42 +00:00
|
|
|
|
|
|
|
// TODO: Options should come from CompilerInvocation
|
|
|
|
Unparse(llvm::outs(), *parseTree,
|
2022-04-29 17:36:26 +00:00
|
|
|
/*encoding=*/Fortran::parser::Encoding::UTF_8,
|
|
|
|
/*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
|
|
|
|
/*preStatement=*/nullptr,
|
|
|
|
invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran()
|
|
|
|
: nullptr);
|
2021-03-30 10:35:42 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugUnparseAction::executeAction() {
|
|
|
|
auto &invoc = this->getInstance().getInvocation();
|
|
|
|
auto &parseTree{getInstance().getParsing().parseTree()};
|
2020-12-08 16:27:46 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
CompilerInstance &ci = this->getInstance();
|
|
|
|
auto os{ci.createDefaultOutputFile(
|
|
|
|
/*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName())};
|
2021-07-01 09:33:00 +01:00
|
|
|
|
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,
|
2022-04-29 17:36:26 +00:00
|
|
|
/*encoding=*/Fortran::parser::Encoding::UTF_8,
|
|
|
|
/*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
|
|
|
|
/*preStatement=*/nullptr,
|
|
|
|
invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran()
|
|
|
|
: 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
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugUnparseWithSymbolsAction::executeAction() {
|
|
|
|
auto &parseTree{*getInstance().getParsing().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
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugDumpSymbolsAction::executeAction() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
2021-02-17 15:55:56 +00:00
|
|
|
|
2022-02-17 13:32:32 +00:00
|
|
|
if (!ci.getRtTyTables().schemata) {
|
2022-04-29 17:36:26 +00:00
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error,
|
|
|
|
"could not find module file for __fortran_type_info");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
2021-04-16 14:07:09 +00:00
|
|
|
llvm::errs() << "\n";
|
2022-02-17 13:32:32 +00:00
|
|
|
return;
|
2021-04-16 14:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Dump symbols
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getSemantics().DumpSymbols(llvm::outs());
|
2021-02-17 15:55:56 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugDumpAllAction::executeAction() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
2021-06-15 15:30:23 +00:00
|
|
|
|
|
|
|
// Dump parse tree
|
2022-04-29 17:36:26 +00:00
|
|
|
auto &parseTree{getInstance().getParsing().parseTree()};
|
2021-06-15 15:30:23 +00:00
|
|
|
llvm::outs() << "========================";
|
|
|
|
llvm::outs() << " Flang: parse tree dump ";
|
|
|
|
llvm::outs() << "========================\n";
|
2022-04-29 17:36:26 +00:00
|
|
|
Fortran::parser::DumpTree(llvm::outs(), parseTree,
|
|
|
|
&ci.getInvocation().getAsFortran());
|
2021-06-15 15:30:23 +00:00
|
|
|
|
2022-02-17 13:32:32 +00:00
|
|
|
if (!ci.getRtTyTables().schemata) {
|
2022-04-29 17:36:26 +00:00
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error,
|
|
|
|
"could not find module file for __fortran_type_info");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
2021-06-15 15:30:23 +00:00
|
|
|
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-04-29 17:36:26 +00:00
|
|
|
ci.getSemantics().DumpSymbols(llvm::outs());
|
2021-06-15 15:30:23 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugDumpParseTreeNoSemaAction::executeAction() {
|
|
|
|
auto &parseTree{getInstance().getParsing().parseTree()};
|
2021-03-30 10:35:42 +00:00
|
|
|
|
|
|
|
// Dump parse tree
|
2021-06-04 15:25:58 +01:00
|
|
|
Fortran::parser::DumpTree(
|
2022-04-29 17:36:26 +00:00
|
|
|
llvm::outs(), parseTree,
|
|
|
|
&this->getInstance().getInvocation().getAsFortran());
|
2021-03-30 10:35:42 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugDumpParseTreeAction::executeAction() {
|
|
|
|
auto &parseTree{getInstance().getParsing().parseTree()};
|
2021-02-17 15:55:56 +00:00
|
|
|
|
|
|
|
// Dump parse tree
|
2021-06-04 15:25:58 +01:00
|
|
|
Fortran::parser::DumpTree(
|
2022-04-29 17:36:26 +00:00
|
|
|
llvm::outs(), parseTree,
|
|
|
|
&this->getInstance().getInvocation().getAsFortran());
|
2021-06-04 15:25:58 +01:00
|
|
|
|
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
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugMeasureParseTreeAction::executeAction() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
2021-02-17 18:53:05 +00:00
|
|
|
|
|
|
|
// Parse. In case of failure, report and return.
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getParsing().Parse(llvm::outs());
|
2021-02-17 18:53:05 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
if (!ci.getParsing().messages().empty() &&
|
|
|
|
(ci.getInvocation().getWarnAsErr() ||
|
|
|
|
ci.getParsing().messages().AnyFatalError())) {
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
2021-02-17 18:53:05 +00:00
|
|
|
clang::DiagnosticsEngine::Error, "Could not parse %0");
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getDiagnostics().Report(diagID) << getCurrentFileOrBufferName();
|
2021-02-17 18:53:05 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getParsing().messages().Emit(llvm::errs(),
|
|
|
|
this->getInstance().getAllCookedSources());
|
2021-02-17 18:53:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
// Report the getDiagnostics from parsing
|
|
|
|
ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());
|
2021-02-17 18:53:05 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
auto &parseTree{*ci.getParsing().parseTree()};
|
2021-02-17 18:53:05 +00:00
|
|
|
|
|
|
|
// 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";
|
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugPreFIRTreeAction::executeAction() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
2021-02-17 18:53:05 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
auto &parseTree{*ci.getParsing().parseTree()};
|
2021-02-17 18:53:05 +00:00
|
|
|
|
|
|
|
// Dump pre-FIR tree
|
|
|
|
if (auto ast{Fortran::lower::createPFT(
|
2022-04-29 17:36:26 +00:00
|
|
|
parseTree, ci.getInvocation().getSemanticsContext())}) {
|
2021-02-17 18:53:05 +00:00
|
|
|
Fortran::lower::dumpPFT(llvm::outs(), *ast);
|
|
|
|
} else {
|
2022-04-29 17:36:26 +00:00
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
2021-02-17 18:53:05 +00:00
|
|
|
clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL.");
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getDiagnostics().Report(diagID);
|
2021-02-17 18:53:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugDumpParsingLogAction::executeAction() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
2021-02-23 17:59:17 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getParsing().Parse(llvm::errs());
|
|
|
|
ci.getParsing().DumpParsingLog(llvm::outs());
|
2021-02-23 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void GetDefinitionAction::executeAction() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
2021-08-13 13:03:21 +00:00
|
|
|
|
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
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
parser::AllCookedSources &cs = ci.getAllCookedSources();
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
2021-04-14 10:43:14 +00:00
|
|
|
clang::DiagnosticsEngine::Error, "Symbol not found");
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
auto gdv = ci.getInvocation().getFrontendOpts().getDefVals;
|
2022-08-12 21:22:30 +02:00
|
|
|
auto charBlock{cs.GetCharBlockFromLineAndColumns(gdv.line, gdv.startColumn,
|
|
|
|
gdv.endColumn)};
|
2021-04-14 10:43:14 +00:00
|
|
|
if (!charBlock) {
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getDiagnostics().Report(diagID);
|
2021-04-14 10:43:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::outs() << "String range: >" << charBlock->ToString() << "<\n";
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
auto *symbol{ci.getInvocation()
|
|
|
|
.getSemanticsContext()
|
2021-04-14 10:43:14 +00:00
|
|
|
.FindScope(*charBlock)
|
|
|
|
.FindSymbol(*charBlock)};
|
|
|
|
if (!symbol) {
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getDiagnostics().Report(diagID);
|
2021-04-14 10:43:14 +00:00
|
|
|
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";
|
2023-06-23 11:01:33 -07:00
|
|
|
llvm::outs() << symbol->name().ToString() << ": " << sourceInfo->first.path
|
|
|
|
<< ", " << sourceInfo->first.line << ", "
|
|
|
|
<< sourceInfo->first.column << "-" << sourceInfo->second.column
|
|
|
|
<< "\n";
|
2021-04-14 10:43:14 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void GetSymbolsSourcesAction::executeAction() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
2021-08-13 13:03:21 +00:00
|
|
|
|
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
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getSemantics().DumpSymbolsSources(llvm::outs());
|
2021-03-08 16:54:11 +00:00
|
|
|
}
|
|
|
|
|
2022-04-22 09:07:31 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// CodeGenActions
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
CodeGenAction::~CodeGenAction() = default;
|
|
|
|
|
2022-02-04 17:15:12 +00:00
|
|
|
#include "flang/Tools/CLOptions.inc"
|
|
|
|
|
2022-07-14 16:50:41 -07:00
|
|
|
static llvm::OptimizationLevel
|
|
|
|
mapToLevel(const Fortran::frontend::CodeGenOptions &opts) {
|
|
|
|
switch (opts.OptimizationLevel) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Invalid optimization level!");
|
|
|
|
case 0:
|
|
|
|
return llvm::OptimizationLevel::O0;
|
|
|
|
case 1:
|
|
|
|
return llvm::OptimizationLevel::O1;
|
|
|
|
case 2:
|
|
|
|
return llvm::OptimizationLevel::O2;
|
|
|
|
case 3:
|
|
|
|
return llvm::OptimizationLevel::O3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-22 12:55:10 +00:00
|
|
|
// Lower using HLFIR then run the FIR to HLFIR pipeline
|
|
|
|
void CodeGenAction::lowerHLFIRToFIR() {
|
|
|
|
assert(mlirModule && "The MLIR module has not been generated yet.");
|
|
|
|
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
|
|
|
auto opts = ci.getInvocation().getCodeGenOpts();
|
|
|
|
llvm::OptimizationLevel level = mapToLevel(opts);
|
|
|
|
|
|
|
|
fir::support::loadDialects(*mlirCtx);
|
|
|
|
|
|
|
|
// Set-up the MLIR pass manager
|
|
|
|
mlir::PassManager pm((*mlirModule)->getName(),
|
|
|
|
mlir::OpPassManager::Nesting::Implicit);
|
|
|
|
|
|
|
|
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
|
|
|
|
pm.enableVerifier(/*verifyPasses=*/true);
|
|
|
|
|
|
|
|
// Create the pass pipeline
|
|
|
|
fir::createHLFIRToFIRPassPipeline(pm, level);
|
|
|
|
(void)mlir::applyPassManagerCLOptions(pm);
|
|
|
|
|
|
|
|
if (!mlir::succeeded(pm.run(*mlirModule))) {
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Lowering to FIR failed");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-04 17:15:12 +00:00
|
|
|
// Lower the previously generated MLIR module into an LLVM IR module
|
2022-04-29 17:36:26 +00:00
|
|
|
void CodeGenAction::generateLLVMIR() {
|
2022-02-04 17:15:12 +00:00
|
|
|
assert(mlirModule && "The MLIR module has not been generated yet.");
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
CompilerInstance &ci = this->getInstance();
|
2022-07-14 16:50:41 -07:00
|
|
|
auto opts = ci.getInvocation().getCodeGenOpts();
|
|
|
|
llvm::OptimizationLevel level = mapToLevel(opts);
|
2022-02-04 17:15:12 +00:00
|
|
|
|
|
|
|
fir::support::loadDialects(*mlirCtx);
|
|
|
|
fir::support::registerLLVMTranslation(*mlirCtx);
|
|
|
|
|
|
|
|
// Set-up the MLIR pass manager
|
2022-11-08 23:23:28 -05:00
|
|
|
mlir::PassManager pm((*mlirModule)->getName(),
|
|
|
|
mlir::OpPassManager::Nesting::Implicit);
|
2022-02-04 17:15:12 +00:00
|
|
|
|
|
|
|
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
|
|
|
|
pm.enableVerifier(/*verifyPasses=*/true);
|
|
|
|
|
|
|
|
// Create the pass pipeline
|
2023-02-21 16:33:06 -05:00
|
|
|
fir::createMLIRToLLVMPassPipeline(pm, level, opts.StackArrays,
|
2023-01-09 15:30:29 +00:00
|
|
|
opts.Underscoring, opts.LoopVersioning,
|
|
|
|
opts.getDebugInfo());
|
2023-04-02 16:30:33 +08:00
|
|
|
(void)mlir::applyPassManagerCLOptions(pm);
|
2022-02-04 17:15:12 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
// run the pass manager
|
2022-02-04 17:15:12 +00:00
|
|
|
if (!mlir::succeeded(pm.run(*mlirModule))) {
|
2022-04-29 17:36:26 +00:00
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
2022-02-04 17:15:12 +00:00
|
|
|
clang::DiagnosticsEngine::Error, "Lowering to LLVM IR failed");
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getDiagnostics().Report(diagID);
|
2022-02-04 17:15:12 +00:00
|
|
|
}
|
|
|
|
|
2023-03-14 17:40:04 +00:00
|
|
|
// Print final MLIR module, just before translation into LLVM IR, if
|
|
|
|
// -save-temps has been specified.
|
|
|
|
if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(),
|
|
|
|
"llvmir")) {
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "Saving MLIR temp file failed");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-04 17:15:12 +00:00
|
|
|
// Translate to LLVM IR
|
2022-12-14 11:39:19 +01:00
|
|
|
std::optional<llvm::StringRef> moduleName = mlirModule->getName();
|
2022-02-04 17:15:12 +00:00
|
|
|
llvmModule = mlir::translateModuleToLLVMIR(
|
|
|
|
*mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule");
|
|
|
|
|
2023-02-18 22:14:20 -08:00
|
|
|
if (!llvmModule) {
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "failed to create the LLVM module");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-22 10:24:49 -07:00
|
|
|
// Set PIC/PIE level LLVM module flags.
|
|
|
|
if (opts.PICLevel > 0) {
|
|
|
|
llvmModule->setPICLevel(static_cast<llvm::PICLevel::Level>(opts.PICLevel));
|
|
|
|
if (opts.IsPIE)
|
|
|
|
llvmModule->setPIELevel(
|
|
|
|
static_cast<llvm::PIELevel::Level>(opts.PICLevel));
|
|
|
|
}
|
2022-02-04 17:15:12 +00:00
|
|
|
}
|
|
|
|
|
2023-03-20 12:05:18 -07:00
|
|
|
bool CodeGenAction::setUpTargetMachine() {
|
2022-04-29 17:36:26 +00:00
|
|
|
CompilerInstance &ci = this->getInstance();
|
2022-04-06 11:59:28 +00:00
|
|
|
|
2022-11-30 13:15:43 -08:00
|
|
|
const TargetOptions &targetOpts = ci.getInvocation().getTargetOpts();
|
|
|
|
const std::string &theTriple = targetOpts.triple;
|
[flang][driver] Define the default frontend driver triple
*SUMMARY*
Currently, the frontend driver assumes that a target triple is either:
* provided by the frontend itself (e.g. when lowering and generating
code),
* specified through the `-triple/-target` command line flags.
If `-triple/-target` is not used, the frontend will simply use the host
triple.
This is going to be insufficient when e.g. consuming an LLVM IR file
that has no triple specified (reading LLVM files is WIP, see D124667).
We shouldn't require the triple to be specified via the command line in
such situation. Instead, the frontend driver should contain a good
default, e.g. the host triple.
This patch updates Flang's `CompilerInvocation` to do just that, i.e.
defines its default target triple. Similarly to Clang:
* the default `CompilerInvocation` triple is set as the host triple,
* the value specified with `-triple` takes precedence over the frontend
driver default and the current module triple,
* the frontend driver default takes precedence over the module triple.
*TESTS*
This change requires 2 unit tests to be updated. That's because relevant
frontend actions are updated to assume that there's always a valid
triple available in the current `CompilerInvocation`. This update is
required because the unit tests bypass the regular `CompilerInvocation`
set-up (in particular, they don't call
`CompilerInvocation::CreateFromArgs`). I've also taken the liberty to
disable the pre-precossor formatting in the affected unit tests as well
(it is not required).
No new tests are added. As `flang-new -fc1` does not support consuming
LLVM IR files just yet, it is not possible to compile an LLVM IR file
without a triple. More specifically, atm all LLVM IR files are generated
and stored internally and the driver makes sure that these contain a
valid target triple. This is about to change in D124667 (which adds
support for reading LLVM IR/BC files) and that's where tests for
exercising the default frontend driver triple will be added.
*WHAT DOES CLANG DO?*
For reference, the default target triple for Clang's
`CompilerInvocation` is set through option marshalling infra [1] in
Options.td. Please check the definition of the `-triple` flag:
```
def triple : Separate<["-"], "triple">,
HelpText<"Specify target triple (e.g. i686-apple-darwin9)">,
MarshallingInfoString<TargetOpts<"Triple">, "llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple())">,
AlwaysEmit, Normalizer<"normalizeTriple">;
```
Ideally, we should re-use the marshalling infra in Flang.
[1] https://clang.llvm.org/docs/InternalsManual.html#option-marshalling-infrastructure
Differential Revision: https://reviews.llvm.org/D124664
2022-04-28 14:12:32 +00:00
|
|
|
|
|
|
|
// Create `Target`
|
2022-04-06 11:59:28 +00:00
|
|
|
std::string error;
|
|
|
|
const llvm::Target *theTarget =
|
|
|
|
llvm::TargetRegistry::lookupTarget(theTriple, error);
|
2023-03-20 12:05:18 -07:00
|
|
|
if (!theTarget) {
|
|
|
|
ci.getDiagnostics().Report(clang::diag::err_fe_unable_to_create_target)
|
|
|
|
<< error;
|
|
|
|
return false;
|
|
|
|
}
|
2022-04-06 11:59:28 +00:00
|
|
|
|
2022-04-22 09:07:31 +00:00
|
|
|
// Create `TargetMachine`
|
2022-08-22 10:24:49 -07:00
|
|
|
const auto &CGOpts = ci.getInvocation().getCodeGenOpts();
|
2023-01-16 23:55:22 +00:00
|
|
|
std::optional<llvm::CodeGenOpt::Level> OptLevelOrNone =
|
2023-01-23 23:50:44 +00:00
|
|
|
llvm::CodeGenOpt::getLevel(CGOpts.OptimizationLevel);
|
2023-01-16 23:55:22 +00:00
|
|
|
assert(OptLevelOrNone && "Invalid optimization level!");
|
|
|
|
llvm::CodeGenOpt::Level OptLevel = *OptLevelOrNone;
|
2023-03-27 07:19:40 -05:00
|
|
|
std::string featuresStr = getTargetFeatures(ci);
|
2022-06-17 13:08:42 +00:00
|
|
|
tm.reset(theTarget->createTargetMachine(
|
2022-11-30 13:15:43 -08:00
|
|
|
theTriple, /*CPU=*/targetOpts.cpu,
|
|
|
|
/*Features=*/featuresStr, llvm::TargetOptions(),
|
2022-08-22 10:24:49 -07:00
|
|
|
/*Reloc::Model=*/CGOpts.getRelocationModel(),
|
2022-12-03 12:14:21 -08:00
|
|
|
/*CodeModel::Model=*/std::nullopt, OptLevel));
|
2022-04-29 17:36:26 +00:00
|
|
|
assert(tm && "Failed to create TargetMachine");
|
2023-03-20 12:05:18 -07:00
|
|
|
return true;
|
2022-04-22 09:07:31 +00:00
|
|
|
}
|
2022-04-06 11:59:28 +00:00
|
|
|
|
2022-04-22 09:07:31 +00:00
|
|
|
static std::unique_ptr<llvm::raw_pwrite_stream>
|
2022-04-29 17:36:26 +00:00
|
|
|
getOutputStream(CompilerInstance &ci, llvm::StringRef inFile,
|
2022-04-22 09:07:31 +00:00
|
|
|
BackendActionTy action) {
|
|
|
|
switch (action) {
|
|
|
|
case BackendActionTy::Backend_EmitAssembly:
|
2022-04-29 17:36:26 +00:00
|
|
|
return ci.createDefaultOutputFile(
|
2022-04-22 09:07:31 +00:00
|
|
|
/*Binary=*/false, inFile, /*extension=*/"s");
|
|
|
|
case BackendActionTy::Backend_EmitLL:
|
2022-04-29 17:36:26 +00:00
|
|
|
return ci.createDefaultOutputFile(
|
2022-04-22 09:07:31 +00:00
|
|
|
/*Binary=*/false, inFile, /*extension=*/"ll");
|
2023-05-22 12:55:10 +00:00
|
|
|
case BackendActionTy::Backend_EmitFIR:
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
case BackendActionTy::Backend_EmitHLFIR:
|
2022-04-29 17:36:26 +00:00
|
|
|
return ci.createDefaultOutputFile(
|
2022-04-22 09:07:31 +00:00
|
|
|
/*Binary=*/false, inFile, /*extension=*/"mlir");
|
|
|
|
case BackendActionTy::Backend_EmitBC:
|
2022-04-29 17:36:26 +00:00
|
|
|
return ci.createDefaultOutputFile(
|
2022-04-22 09:07:31 +00:00
|
|
|
/*Binary=*/true, inFile, /*extension=*/"bc");
|
|
|
|
case BackendActionTy::Backend_EmitObj:
|
2022-04-29 17:36:26 +00:00
|
|
|
return ci.createDefaultOutputFile(
|
2022-04-22 09:07:31 +00:00
|
|
|
/*Binary=*/true, inFile, /*extension=*/"o");
|
2022-04-06 11:59:28 +00:00
|
|
|
}
|
|
|
|
|
2022-04-22 09:07:31 +00:00
|
|
|
llvm_unreachable("Invalid action!");
|
2022-04-06 11:59:28 +00:00
|
|
|
}
|
|
|
|
|
2022-04-22 09:07:31 +00:00
|
|
|
/// Generate target-specific machine-code or assembly file from the input LLVM
|
|
|
|
/// module.
|
|
|
|
///
|
|
|
|
/// \param [in] diags Diagnostics engine for reporting errors
|
2022-04-29 17:36:26 +00:00
|
|
|
/// \param [in] tm Target machine to aid the code-gen pipeline set-up
|
2022-04-22 09:07:31 +00:00
|
|
|
/// \param [in] act Backend act to run (assembly vs machine-code generation)
|
|
|
|
/// \param [in] llvmModule LLVM module to lower to assembly/machine-code
|
|
|
|
/// \param [out] os Output stream to emit the generated code to
|
2022-04-29 17:36:26 +00:00
|
|
|
static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags,
|
|
|
|
llvm::TargetMachine &tm,
|
2022-04-22 09:07:31 +00:00
|
|
|
BackendActionTy act,
|
|
|
|
llvm::Module &llvmModule,
|
|
|
|
llvm::raw_pwrite_stream &os) {
|
2022-05-05 17:58:08 +00:00
|
|
|
assert(((act == BackendActionTy::Backend_EmitObj) ||
|
|
|
|
(act == BackendActionTy::Backend_EmitAssembly)) &&
|
|
|
|
"Unsupported action");
|
2022-04-22 09:07:31 +00:00
|
|
|
|
|
|
|
// Set-up the pass manager, i.e 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.
|
2022-04-29 17:36:26 +00:00
|
|
|
llvm::legacy::PassManager codeGenPasses;
|
|
|
|
codeGenPasses.add(
|
|
|
|
createTargetTransformInfoWrapperPass(tm.getTargetIRAnalysis()));
|
2022-02-03 17:00:27 +00:00
|
|
|
|
2022-04-22 09:07:31 +00:00
|
|
|
llvm::Triple triple(llvmModule.getTargetTriple());
|
2022-04-29 17:36:26 +00:00
|
|
|
std::unique_ptr<llvm::TargetLibraryInfoImpl> tlii =
|
2022-04-22 09:07:31 +00:00
|
|
|
std::make_unique<llvm::TargetLibraryInfoImpl>(triple);
|
2022-04-29 17:36:26 +00:00
|
|
|
assert(tlii && "Failed to create TargetLibraryInfo");
|
|
|
|
codeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*tlii));
|
2022-02-03 17:00:27 +00:00
|
|
|
|
2022-04-22 09:07:31 +00:00
|
|
|
llvm::CodeGenFileType cgft = (act == BackendActionTy::Backend_EmitAssembly)
|
|
|
|
? llvm::CodeGenFileType::CGFT_AssemblyFile
|
|
|
|
: llvm::CodeGenFileType::CGFT_ObjectFile;
|
2022-04-29 17:36:26 +00:00
|
|
|
if (tm.addPassesToEmitFile(codeGenPasses, os, nullptr, cgft)) {
|
2022-04-22 09:07:31 +00:00
|
|
|
unsigned diagID =
|
|
|
|
diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
|
|
|
|
"emission of this file type is not supported");
|
|
|
|
diags.Report(diagID);
|
2022-02-03 17:00:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-22 09:07:31 +00:00
|
|
|
// Run the passes
|
2022-04-29 17:36:26 +00:00
|
|
|
codeGenPasses.run(llvmModule);
|
2022-02-03 17:00:27 +00:00
|
|
|
}
|
|
|
|
|
2022-06-06 09:44:21 +00:00
|
|
|
void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
|
|
|
|
auto opts = getInstance().getInvocation().getCodeGenOpts();
|
2022-11-10 07:56:03 -07:00
|
|
|
auto &diags = getInstance().getDiagnostics();
|
2022-06-06 09:44:21 +00:00
|
|
|
llvm::OptimizationLevel level = mapToLevel(opts);
|
|
|
|
|
|
|
|
// Create the analysis managers.
|
|
|
|
llvm::LoopAnalysisManager lam;
|
|
|
|
llvm::FunctionAnalysisManager fam;
|
|
|
|
llvm::CGSCCAnalysisManager cgam;
|
2022-04-29 17:36:26 +00:00
|
|
|
llvm::ModuleAnalysisManager mam;
|
2022-06-06 09:44:21 +00:00
|
|
|
|
|
|
|
// Create the pass manager builder.
|
|
|
|
llvm::PassInstrumentationCallbacks pic;
|
|
|
|
llvm::PipelineTuningOptions pto;
|
2022-12-04 21:29:00 +00:00
|
|
|
std::optional<llvm::PGOOptions> pgoOpt;
|
2023-01-19 16:49:26 +00:00
|
|
|
llvm::StandardInstrumentations si(llvmModule->getContext(),
|
|
|
|
opts.DebugPassManager);
|
2023-03-15 11:46:44 -07:00
|
|
|
si.registerCallbacks(pic, &mam);
|
2022-06-06 09:44:21 +00:00
|
|
|
llvm::PassBuilder pb(tm.get(), pto, pgoOpt, &pic);
|
|
|
|
|
2022-11-10 07:56:03 -07:00
|
|
|
// Attempt to load pass plugins and register their callbacks with PB.
|
|
|
|
for (auto &pluginFile : opts.LLVMPassPlugins) {
|
|
|
|
auto passPlugin = llvm::PassPlugin::Load(pluginFile);
|
|
|
|
if (passPlugin) {
|
|
|
|
passPlugin->registerPassBuilderCallbacks(pb);
|
|
|
|
} else {
|
|
|
|
diags.Report(clang::diag::err_fe_unable_to_load_plugin)
|
|
|
|
<< pluginFile << passPlugin.takeError();
|
|
|
|
}
|
|
|
|
}
|
2022-11-10 14:09:51 -08:00
|
|
|
// Register static plugin extensions.
|
|
|
|
#define HANDLE_EXTENSION(Ext) \
|
|
|
|
get##Ext##PluginInfo().RegisterPassBuilderCallbacks(pb);
|
|
|
|
#include "llvm/Support/Extension.def"
|
2022-11-10 07:56:03 -07:00
|
|
|
|
2022-06-06 09:44:21 +00:00
|
|
|
// Register all the basic analyses with the managers.
|
2022-04-29 17:36:26 +00:00
|
|
|
pb.registerModuleAnalyses(mam);
|
2022-06-06 09:44:21 +00:00
|
|
|
pb.registerCGSCCAnalyses(cgam);
|
|
|
|
pb.registerFunctionAnalyses(fam);
|
|
|
|
pb.registerLoopAnalyses(lam);
|
|
|
|
pb.crossRegisterProxies(lam, fam, cgam, mam);
|
|
|
|
|
|
|
|
// Create the pass manager.
|
|
|
|
llvm::ModulePassManager mpm;
|
2023-03-16 09:57:44 +01:00
|
|
|
if (opts.PrepareForFullLTO)
|
2023-02-01 15:09:23 -08:00
|
|
|
mpm = pb.buildLTOPreLinkDefaultPipeline(level);
|
|
|
|
else if (opts.PrepareForThinLTO)
|
|
|
|
mpm = pb.buildThinLTOPreLinkDefaultPipeline(level);
|
2022-06-06 09:44:21 +00:00
|
|
|
else
|
|
|
|
mpm = pb.buildPerModuleDefaultPipeline(level);
|
2022-04-29 17:36:26 +00:00
|
|
|
|
2022-06-06 09:44:21 +00:00
|
|
|
if (action == BackendActionTy::Backend_EmitBC)
|
|
|
|
mpm.addPass(llvm::BitcodeWriterPass(os));
|
|
|
|
|
|
|
|
// Run the passes.
|
|
|
|
mpm.run(*llvmModule, mam);
|
2022-04-22 09:07:31 +00:00
|
|
|
}
|
2022-02-24 17:34:27 +00:00
|
|
|
|
2023-01-20 14:33:22 -05:00
|
|
|
void CodeGenAction::embedOffloadObjects() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
|
|
|
const auto &cgOpts = ci.getInvocation().getCodeGenOpts();
|
|
|
|
|
|
|
|
for (llvm::StringRef offloadObject : cgOpts.OffloadObjects) {
|
|
|
|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> objectOrErr =
|
|
|
|
llvm::MemoryBuffer::getFileOrSTDIN(offloadObject);
|
|
|
|
if (std::error_code ec = objectOrErr.getError()) {
|
|
|
|
auto diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Error, "could not open '%0' for embedding");
|
|
|
|
ci.getDiagnostics().Report(diagID) << offloadObject;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
llvm::embedBufferInModule(
|
|
|
|
*llvmModule, **objectOrErr, ".llvm.offloading",
|
|
|
|
llvm::Align(llvm::object::OffloadBinary::getAlignment()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-27 21:57:54 +00:00
|
|
|
static void reportOptRecordError(llvm::Error e, clang::DiagnosticsEngine &diags,
|
|
|
|
const CodeGenOptions &codeGenOpts) {
|
|
|
|
handleAllErrors(
|
|
|
|
std::move(e),
|
|
|
|
[&](const llvm::LLVMRemarkSetupFileError &e) {
|
|
|
|
diags.Report(clang::diag::err_cannot_open_file)
|
|
|
|
<< codeGenOpts.OptRecordFile << e.message();
|
|
|
|
},
|
|
|
|
[&](const llvm::LLVMRemarkSetupPatternError &e) {
|
|
|
|
diags.Report(clang::diag::err_drv_optimization_remark_pattern)
|
|
|
|
<< e.message() << codeGenOpts.OptRecordPasses;
|
|
|
|
},
|
|
|
|
[&](const llvm::LLVMRemarkSetupFormatError &e) {
|
|
|
|
diags.Report(clang::diag::err_drv_optimization_remark_format)
|
|
|
|
<< codeGenOpts.OptRecordFormat;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void CodeGenAction::executeAction() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
2022-02-24 17:34:27 +00:00
|
|
|
|
2023-07-27 21:57:54 +00:00
|
|
|
clang::DiagnosticsEngine &diags = ci.getDiagnostics();
|
|
|
|
const CodeGenOptions &codeGenOpts = ci.getInvocation().getCodeGenOpts();
|
|
|
|
Fortran::lower::LoweringOptions &loweringOpts =
|
|
|
|
ci.getInvocation().getLoweringOpts();
|
|
|
|
|
2022-02-24 17:34:27 +00:00
|
|
|
// 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
|
2022-04-29 17:36:26 +00:00
|
|
|
// method. However, it won't be written to until `codeGenPasses` is
|
|
|
|
// destroyed. By defining `os` before `codeGenPasses`, we make sure that the
|
2022-02-24 17:34:27 +00:00
|
|
|
// 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).
|
2022-04-29 17:36:26 +00:00
|
|
|
// TODO: Revisit once the new PM is ready (i.e. when `codeGenPasses` is
|
2022-02-24 17:34:27 +00:00
|
|
|
// updated to use it).
|
|
|
|
std::unique_ptr<llvm::raw_pwrite_stream> os;
|
2022-04-29 17:36:26 +00:00
|
|
|
if (ci.isOutputStreamNull()) {
|
|
|
|
os = getOutputStream(ci, getCurrentFileOrBufferName(), action);
|
2022-04-22 09:07:31 +00:00
|
|
|
|
2022-02-24 17:34:27 +00:00
|
|
|
if (!os) {
|
2023-07-27 21:57:54 +00:00
|
|
|
unsigned diagID = diags.getCustomDiagID(
|
2022-02-24 17:34:27 +00:00
|
|
|
clang::DiagnosticsEngine::Error, "failed to create the output file");
|
2023-07-27 21:57:54 +00:00
|
|
|
diags.Report(diagID);
|
2022-02-24 17:34:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-22 12:55:10 +00:00
|
|
|
if (action == BackendActionTy::Backend_EmitFIR) {
|
2023-07-27 21:57:54 +00:00
|
|
|
if (loweringOpts.getLowerToHighLevelFIR()) {
|
2023-05-22 12:55:10 +00:00
|
|
|
lowerHLFIRToFIR();
|
|
|
|
}
|
|
|
|
mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action == BackendActionTy::Backend_EmitHLFIR) {
|
2023-07-27 21:57:54 +00:00
|
|
|
assert(loweringOpts.getLowerToHighLevelFIR() &&
|
2023-05-22 12:55:10 +00:00
|
|
|
"Lowering must have been configured to emit HLFIR");
|
2022-04-29 17:36:26 +00:00
|
|
|
mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
|
2022-04-22 09:07:31 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-02-24 17:34:27 +00:00
|
|
|
|
2022-06-06 09:44:21 +00:00
|
|
|
// Generate an LLVM module if it's not already present (it will already be
|
2022-04-22 09:07:31 +00:00
|
|
|
// present if the input file is an LLVM IR/BC file).
|
|
|
|
if (!llvmModule)
|
2022-04-29 17:36:26 +00:00
|
|
|
generateLLVMIR();
|
2022-02-24 17:34:27 +00:00
|
|
|
|
2022-09-02 10:18:12 +01:00
|
|
|
// Set the triple based on the targetmachine (this comes compiler invocation
|
|
|
|
// and the command-line target option if specified, or the default if not
|
|
|
|
// given on the command-line).
|
2023-03-20 12:05:18 -07:00
|
|
|
if (!setUpTargetMachine())
|
|
|
|
return;
|
2022-09-02 10:18:12 +01:00
|
|
|
const std::string &theTriple = tm->getTargetTriple().str();
|
|
|
|
|
|
|
|
if (llvmModule->getTargetTriple() != theTriple) {
|
2023-07-27 21:57:54 +00:00
|
|
|
diags.Report(clang::diag::warn_fe_override_module) << theTriple;
|
2022-09-02 10:18:12 +01:00
|
|
|
}
|
2023-01-20 14:33:22 -05:00
|
|
|
|
2022-09-02 10:18:12 +01:00
|
|
|
// Always set the triple and data layout, to make sure they match and are set.
|
|
|
|
// Note that this overwrites any datalayout stored in the LLVM-IR. This avoids
|
|
|
|
// an assert for incompatible data layout when the code-generation happens.
|
|
|
|
llvmModule->setTargetTriple(theTriple);
|
|
|
|
llvmModule->setDataLayout(tm->createDataLayout());
|
|
|
|
|
2023-01-20 14:33:22 -05:00
|
|
|
// Embed offload objects specified with -fembed-offload-object
|
2023-07-27 21:57:54 +00:00
|
|
|
if (!codeGenOpts.OffloadObjects.empty())
|
2023-01-20 14:33:22 -05:00
|
|
|
embedOffloadObjects();
|
|
|
|
|
2023-07-27 21:57:54 +00:00
|
|
|
// write optimization-record
|
|
|
|
llvm::Expected<std::unique_ptr<llvm::ToolOutputFile>> optRecordFileOrErr =
|
|
|
|
setupLLVMOptimizationRemarks(
|
|
|
|
llvmModule->getContext(), codeGenOpts.OptRecordFile,
|
|
|
|
codeGenOpts.OptRecordPasses, codeGenOpts.OptRecordFormat,
|
|
|
|
/*DiagnosticsWithHotness=*/false,
|
|
|
|
/*DiagnosticsHotnessThreshold=*/0);
|
|
|
|
|
|
|
|
if (llvm::Error e = optRecordFileOrErr.takeError()) {
|
|
|
|
reportOptRecordError(std::move(e), diags, codeGenOpts);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<llvm::ToolOutputFile> optRecordFile =
|
|
|
|
std::move(*optRecordFileOrErr);
|
|
|
|
|
|
|
|
if (optRecordFile) {
|
|
|
|
optRecordFile->keep();
|
|
|
|
optRecordFile->os().flush();
|
|
|
|
}
|
|
|
|
|
2022-06-06 09:44:21 +00:00
|
|
|
// Run LLVM's middle-end (i.e. the optimizer).
|
2023-01-26 14:17:13 -08:00
|
|
|
runOptimizationPipeline(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
|
2022-06-06 09:44:21 +00:00
|
|
|
|
2022-04-22 09:07:31 +00:00
|
|
|
if (action == BackendActionTy::Backend_EmitLL) {
|
2022-04-29 17:36:26 +00:00
|
|
|
llvmModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream(),
|
2022-04-22 09:07:31 +00:00
|
|
|
/*AssemblyAnnotationWriter=*/nullptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action == BackendActionTy::Backend_EmitBC) {
|
2022-06-06 09:44:21 +00:00
|
|
|
// This action has effectively been completed in runOptimizationPipeline.
|
2022-02-24 17:34:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-06 09:44:21 +00:00
|
|
|
// Run LLVM's backend and generate either assembly or machine code
|
2022-04-22 09:07:31 +00:00
|
|
|
if (action == BackendActionTy::Backend_EmitAssembly ||
|
|
|
|
action == BackendActionTy::Backend_EmitObj) {
|
2022-04-29 17:36:26 +00:00
|
|
|
generateMachineCodeOrAssemblyImpl(
|
2023-07-27 21:57:54 +00:00
|
|
|
diags, *tm, action, *llvmModule,
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.isOutputStreamNull() ? *os : ci.getOutputStream());
|
2022-04-22 09:07:31 +00:00
|
|
|
return;
|
|
|
|
}
|
[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
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void InitOnlyAction::executeAction() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
|
|
|
clang::DiagnosticsEngine::Warning,
|
|
|
|
"Use `-init-only` for testing purposes only");
|
|
|
|
ci.getDiagnostics().Report(diagID);
|
2021-06-07 15:40:26 +01:00
|
|
|
}
|
2021-08-12 11:42:08 +01:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void PluginParseTreeAction::executeAction() {}
|
2022-03-08 10:01:55 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
void DebugDumpPFTAction::executeAction() {
|
|
|
|
CompilerInstance &ci = this->getInstance();
|
2022-03-08 10:01:55 +00:00
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
if (auto ast = Fortran::lower::createPFT(*ci.getParsing().parseTree(),
|
|
|
|
ci.getSemantics().context())) {
|
2022-03-08 10:01:55 +00:00
|
|
|
Fortran::lower::dumpPFT(llvm::outs(), *ast);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
|
2022-03-08 10:01:55 +00:00
|
|
|
clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL.");
|
2022-04-29 17:36:26 +00:00
|
|
|
ci.getDiagnostics().Report(diagID);
|
2022-03-08 10:01:55 +00:00
|
|
|
}
|
2022-03-04 13:05:21 +00:00
|
|
|
|
|
|
|
Fortran::parser::Parsing &PluginParseTreeAction::getParsing() {
|
2022-04-29 17:36:26 +00:00
|
|
|
return getInstance().getParsing();
|
2022-03-04 13:05:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<llvm::raw_pwrite_stream>
|
|
|
|
PluginParseTreeAction::createOutputFile(llvm::StringRef extension = "") {
|
|
|
|
|
2022-04-29 17:36:26 +00:00
|
|
|
std::unique_ptr<llvm::raw_pwrite_stream> os{
|
|
|
|
getInstance().createDefaultOutputFile(
|
|
|
|
/*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName(),
|
2022-03-04 13:05:21 +00:00
|
|
|
extension)};
|
2022-04-29 17:36:26 +00:00
|
|
|
return os;
|
2022-03-04 13:05:21 +00:00
|
|
|
}
|