forked from OSchip/llvm-project
[flang][driver] Add the new flang compiler and frontend drivers
Summary: This is the first patch implementing the new Flang driver as outlined in [1], [2] & [3]. It creates Flang driver (`flang-new`) and Flang frontend driver (`flang-new -fc1`). These will be renamed as `flang` and `flang -fc1` once the current Flang throwaway driver, `flang`, can be replaced with `flang-new`. Currently only 2 options are supported: `-help` and `--version`. `flang-new` is implemented in terms of libclangDriver, defaulting the driver mode to `FlangMode` (added to libclangDriver in [4]). This ensures that the driver runs in Flang mode regardless of the name of the binary inferred from argv[0]. The design of the new Flang compiler and frontend drivers is inspired by it counterparts in Clang [3]. Currently, the new Flang compiler and frontend drivers re-use Clang libraries: clangBasic, clangDriver and clangFrontend. To identify Flang options, this patch adds FlangOption/FC1Option enums. Driver::printHelp is updated so that `flang-new` prints only Flang options. The new Flang driver is disabled by default. To enable it, set `-DBUILD_FLANG_NEW_DRIVER=ON` when configuring CMake and add clang to `LLVM_ENABLE_PROJECTS` (e.g. -DLLVM_ENABLE_PROJECTS=“clang;flang;mlir”). [1] “RFC: new Flang driver - next steps” http://lists.llvm.org/pipermail/flang-dev/2020-July/000470.html [2] “RFC: Adding a fortran mode to the clang driver for flang” http://lists.llvm.org/pipermail/cfe-dev/2019-June/062669.html [3] “RFC: refactoring libclangDriver/libclangFrontend to share with Flang” http://lists.llvm.org/pipermail/cfe-dev/2020-July/066393.html [4] https://reviews.llvm.org/rG6bf55804924d5a1d902925ad080b1a2b57c5c75c co-authored-by: Andrzej Warzynski <andrzej.warzynski@arm.com> Reviewed By: richard.barton.arm, sameeranjoshi Differential Revision: https://reviews.llvm.org/D86089
This commit is contained in:
parent
002f5ab3b1
commit
257b29715b
|
@ -301,7 +301,7 @@ public:
|
|||
StringRef CustomResourceDir = "");
|
||||
|
||||
Driver(StringRef ClangExecutable, StringRef TargetTriple,
|
||||
DiagnosticsEngine &Diags,
|
||||
DiagnosticsEngine &Diags, std::string Title = "clang LLVM compiler",
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr);
|
||||
|
||||
/// @name Accessors
|
||||
|
|
|
@ -34,7 +34,9 @@ enum ClangFlags {
|
|||
CC1AsOption = (1 << 11),
|
||||
NoDriverOption = (1 << 12),
|
||||
LinkOption = (1 << 13),
|
||||
Ignored = (1 << 14),
|
||||
FlangOption = (1 << 14),
|
||||
FC1Option = (1 << 15),
|
||||
Ignored = (1 << 16),
|
||||
};
|
||||
|
||||
enum ID {
|
||||
|
|
|
@ -56,6 +56,13 @@ def NoDriverOption : OptionFlag;
|
|||
// be used), add this flag.
|
||||
def LinkOption : OptionFlag;
|
||||
|
||||
// FlangOption - This is considered a "core" Flang option, available in
|
||||
// flang mode.
|
||||
def FlangOption : OptionFlag;
|
||||
|
||||
// FC1Option - This option should be accepted by flang -fc1.
|
||||
def FC1Option : OptionFlag;
|
||||
|
||||
// A short name to show in documentation. The name will be interpreted as rST.
|
||||
class DocName<string name> { string DocName = name; }
|
||||
|
||||
|
@ -2100,7 +2107,7 @@ def gno_embed_source : Flag<["-"], "gno-embed-source">, Group<g_flags_Group>,
|
|||
Flags<[DriverOption]>,
|
||||
HelpText<"Restore the default behavior of not embedding source text in DWARF debug sections">;
|
||||
def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">;
|
||||
def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption]>,
|
||||
def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption, FC1Option, FlangOption]>,
|
||||
HelpText<"Display available options">;
|
||||
def ibuiltininc : Flag<["-"], "ibuiltininc">,
|
||||
HelpText<"Enable builtin #include directories even when -nostdinc is used "
|
||||
|
@ -3049,7 +3056,8 @@ def _rtlib : Separate<["--"], "rtlib">, Alias<rtlib_EQ>;
|
|||
def _serialize_diags : Separate<["-", "--"], "serialize-diagnostics">, Flags<[DriverOption]>,
|
||||
HelpText<"Serialize compiler diagnostics to a file">;
|
||||
// We give --version different semantics from -version.
|
||||
def _version : Flag<["--"], "version">, Flags<[CoreOption, CC1Option]>,
|
||||
def _version : Flag<["--"], "version">,
|
||||
Flags<[CoreOption, CC1Option, FC1Option, FlangOption]>,
|
||||
HelpText<"Print version information">;
|
||||
def _signed_char : Flag<["--"], "signed-char">, Alias<fsigned_char>;
|
||||
def _std : Separate<["--"], "std">, Alias<std_EQ>;
|
||||
|
|
|
@ -128,12 +128,12 @@ std::string Driver::GetResourcesPath(StringRef BinaryPath,
|
|||
}
|
||||
|
||||
Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
|
||||
DiagnosticsEngine &Diags,
|
||||
DiagnosticsEngine &Diags, std::string Title,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
|
||||
: Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode),
|
||||
SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None),
|
||||
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
|
||||
DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr),
|
||||
DriverTitle(Title), CCPrintOptionsFilename(nullptr),
|
||||
CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr),
|
||||
CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(false),
|
||||
CCLogDiagnostics(false), CCGenDiagnostics(false),
|
||||
|
@ -1571,6 +1571,9 @@ void Driver::PrintHelp(bool ShowHidden) const {
|
|||
if (!ShowHidden)
|
||||
ExcludedFlagsBitmask |= HelpHidden;
|
||||
|
||||
if (IsFlangMode())
|
||||
IncludedFlagsBitmask |= options::FlangOption;
|
||||
|
||||
std::string Usage = llvm::formatv("{0} [options] file...", Name).str();
|
||||
getOpts().PrintHelp(llvm::outs(), Usage.c_str(), DriverTitle.c_str(),
|
||||
IncludedFlagsBitmask, ExcludedFlagsBitmask,
|
||||
|
@ -1578,9 +1581,13 @@ void Driver::PrintHelp(bool ShowHidden) const {
|
|||
}
|
||||
|
||||
void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
|
||||
// FIXME: The following handlers should use a callback mechanism, we don't
|
||||
// know what the client would like to do.
|
||||
OS << getClangFullVersion() << '\n';
|
||||
if (IsFlangMode()) {
|
||||
OS << getClangToolFullVersion("flang-new") << '\n';
|
||||
} else {
|
||||
// FIXME: The following handlers should use a callback mechanism, we don't
|
||||
// know what the client would like to do.
|
||||
OS << getClangFullVersion() << '\n';
|
||||
}
|
||||
const ToolChain &TC = C.getDefaultToolChain();
|
||||
OS << "Target: " << TC.getTripleString() << '\n';
|
||||
|
||||
|
@ -1618,7 +1625,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const {
|
|||
std::vector<std::string> SuggestedCompletions;
|
||||
std::vector<std::string> Flags;
|
||||
|
||||
unsigned short DisableFlags =
|
||||
unsigned int DisableFlags =
|
||||
options::NoDriverOption | options::Unsupported | options::Ignored;
|
||||
|
||||
// Distinguish "--autocomplete=-someflag" and "--autocomplete=-someflag,"
|
||||
|
|
|
@ -69,11 +69,13 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
CmdArgs.push_back(Input.getFilename());
|
||||
|
||||
const auto& D = C.getDriver();
|
||||
const char* Exec = Args.MakeArgString(D.GetProgramPath("flang", TC));
|
||||
// TODO: Replace flang-new with flang once the new driver replaces the
|
||||
// throwaway driver
|
||||
const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC));
|
||||
C.addCommand(std::make_unique<Command>(
|
||||
JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs));
|
||||
}
|
||||
|
||||
Flang::Flang(const ToolChain &TC) : Tool("flang", "flang frontend", TC) {}
|
||||
Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {}
|
||||
|
||||
Flang::~Flang() {}
|
||||
|
|
|
@ -40,8 +40,8 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
|
|||
Args.push_back("-fsyntax-only");
|
||||
|
||||
// FIXME: We shouldn't have to pass in the path info.
|
||||
driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(),
|
||||
*Diags, VFS);
|
||||
driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(), *Diags,
|
||||
"clang LLVM compiler", VFS);
|
||||
|
||||
// Don't check that inputs exist, they may have been remapped.
|
||||
TheDriver.setCheckInputsExist(false);
|
||||
|
|
|
@ -78,7 +78,7 @@ newDriver(DiagnosticsEngine *Diagnostics, const char *BinaryName,
|
|||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
|
||||
driver::Driver *CompilerDriver =
|
||||
new driver::Driver(BinaryName, llvm::sys::getDefaultTargetTriple(),
|
||||
*Diagnostics, std::move(VFS));
|
||||
*Diagnostics, "clang LLVM compiler", std::move(VFS));
|
||||
CompilerDriver->setTitle("clang_based_tool");
|
||||
return CompilerDriver;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
! * (no type specified, resulting in an object file)
|
||||
|
||||
! All invocations should begin with flang -fc1, consume up to here.
|
||||
! ALL-LABEL: "{{[^"]*}}flang" "-fc1"
|
||||
! ALL-LABEL: "{{[^"]*}}flang-new" "-fc1"
|
||||
|
||||
! Check that f90 files are not treated as "previously preprocessed"
|
||||
! ... in --driver-mode=flang.
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
! * (no type specified, resulting in an object file)
|
||||
|
||||
! All invocations should begin with flang -fc1, consume up to here.
|
||||
! ALL-LABEL: "{{[^"]*}}flang" "-fc1"
|
||||
! ALL-LABEL: "{{[^"]*}}flang-new" "-fc1"
|
||||
|
||||
! Check that f90 files are not treated as "previously preprocessed"
|
||||
! ... in --driver-mode=flang.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
! Check that flang can handle mixed C and fortran inputs.
|
||||
|
||||
! RUN: %clang --driver-mode=flang -### -fsyntax-only %S/Inputs/one.f90 %S/Inputs/other.c 2>&1 | FileCheck --check-prefixes=CHECK-SYNTAX-ONLY %s
|
||||
! CHECK-SYNTAX-ONLY-LABEL: "{{[^"]*}}flang{{[^"/]*}}" "-fc1"
|
||||
! CHECK-SYNTAX-ONLY-LABEL: "{{[^"]*}}flang-new{{[^"/]*}}" "-fc1"
|
||||
! CHECK-SYNTAX-ONLY: "{{[^"]*}}/Inputs/one.f90"
|
||||
! CHECK-SYNTAX-ONLY-LABEL: "{{[^"]*}}clang{{[^"/]*}}" "-cc1"
|
||||
! CHECK-SYNTAX-ONLY: "{{[^"]*}}/Inputs/other.c"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
! Check that flang driver can handle multiple inputs at once.
|
||||
|
||||
! RUN: %clang --driver-mode=flang -### -fsyntax-only %S/Inputs/one.f90 %S/Inputs/two.f90 2>&1 | FileCheck --check-prefixes=CHECK-SYNTAX-ONLY %s
|
||||
! CHECK-SYNTAX-ONLY-LABEL: "{{[^"]*}}flang" "-fc1"
|
||||
! CHECK-SYNTAX-ONLY-LABEL: "{{[^"]*}}flang-new" "-fc1"
|
||||
! CHECK-SYNTAX-ONLY: "{{[^"]*}}/Inputs/one.f90"
|
||||
! CHECK-SYNTAX-ONLY-LABEL: "{{[^"]*}}flang" "-fc1"
|
||||
! CHECK-SYNTAX-ONLY-LABEL: "{{[^"]*}}flang-new" "-fc1"
|
||||
! CHECK-SYNTAX-ONLY: "{{[^"]*}}/Inputs/two.f90"
|
||||
|
|
|
@ -57,7 +57,7 @@ protected:
|
|||
new DiagnosticIDs, Opts,
|
||||
new TextDiagnosticPrinter(llvm::errs(), Opts.get()));
|
||||
DriverInstance.emplace(ClangBinary, "x86_64-unknown-linux-gnu", Diags,
|
||||
prepareFS(ExtraFiles));
|
||||
"clang LLVM compiler", prepareFS(ExtraFiles));
|
||||
|
||||
std::vector<const char *> Args = {ClangBinary};
|
||||
for (const auto &A : ExtraArgs)
|
||||
|
|
|
@ -35,7 +35,7 @@ TEST(ToolChainTest, VFSGCCInstallation) {
|
|||
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new llvm::vfs::InMemoryFileSystem);
|
||||
Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
|
||||
InMemoryFileSystem);
|
||||
"clang LLVM compiler", InMemoryFileSystem);
|
||||
|
||||
const char *EmptyFiles[] = {
|
||||
"foo.cpp",
|
||||
|
@ -89,7 +89,7 @@ TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
|
|||
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new llvm::vfs::InMemoryFileSystem);
|
||||
Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
|
||||
InMemoryFileSystem);
|
||||
"clang LLVM compiler", InMemoryFileSystem);
|
||||
|
||||
const char *EmptyFiles[] = {
|
||||
"foo.cpp", "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
|
||||
|
@ -130,13 +130,13 @@ TEST(ToolChainTest, DefaultDriverMode) {
|
|||
new llvm::vfs::InMemoryFileSystem);
|
||||
|
||||
Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
|
||||
InMemoryFileSystem);
|
||||
"clang LLVM compiler", InMemoryFileSystem);
|
||||
CCDriver.setCheckInputsExist(false);
|
||||
Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags,
|
||||
InMemoryFileSystem);
|
||||
"clang LLVM compiler", InMemoryFileSystem);
|
||||
CXXDriver.setCheckInputsExist(false);
|
||||
Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags,
|
||||
InMemoryFileSystem);
|
||||
"clang LLVM compiler", InMemoryFileSystem);
|
||||
CLDriver.setCheckInputsExist(false);
|
||||
|
||||
std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation(
|
||||
|
|
|
@ -17,6 +17,7 @@ if (POLICY CMP0077)
|
|||
endif()
|
||||
|
||||
option(LINK_WITH_FIR "Link driver with FIR and LLVM" ON)
|
||||
option(FLANG_BUILD_NEW_DRIVER "Build the flang compiler driver" OFF)
|
||||
|
||||
# Flang requires C++17.
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
@ -61,6 +62,12 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
|||
get_filename_component(LLVM_DIR_ABSOLUTE ${LLVM_DIR} REALPATH)
|
||||
list(APPEND CMAKE_MODULE_PATH ${LLVM_DIR_ABSOLUTE})
|
||||
|
||||
if(FLANG_BUILD_NEW_DRIVER)
|
||||
# TODO: Remove when libclangDriver is lifted out of Clang
|
||||
list(APPEND CMAKE_MODULE_PATH ${CLANG_DIR})
|
||||
find_package(Clang REQUIRED HINTS "${CLANG_DIR}")
|
||||
endif()
|
||||
|
||||
# If LLVM links to zlib we need the imported targets so we can too.
|
||||
if(LLVM_ENABLE_ZLIB)
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
@ -200,6 +207,21 @@ else()
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(FLANG_BUILD_NEW_DRIVER)
|
||||
# TODO: Remove when libclangDriver is lifted out of Clang
|
||||
if(FLANG_STANDALONE_BUILD)
|
||||
set(CLANG_INCLUDE_DIR ${CLANG_INCLUDE_DIRS} )
|
||||
# No need to specify TableGen output dir as that's embedded in CLANG_DIR
|
||||
else()
|
||||
set(CLANG_INCLUDE_DIR ${LLVM_MAIN_SRC_DIR}/../clang/include )
|
||||
# Specify TableGen output dir for things like DiagnosticCommonKinds.inc,
|
||||
# DiagnosticDriverKinds.inc (required for reporting diagnostics)
|
||||
set(CLANG_TABLEGEN_OUTPUT_DIR ${CMAKE_BINARY_DIR}/tools/clang/include)
|
||||
include_directories(SYSTEM ${CLANG_TABLEGEN_OUTPUT_DIR})
|
||||
endif()
|
||||
include_directories(SYSTEM ${CLANG_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
if(LINK_WITH_FIR)
|
||||
# tco tool and FIR lib output directories
|
||||
if(FLANG_STANDALONE_BUILD)
|
||||
|
|
|
@ -143,6 +143,21 @@ cd ~/flang/build
|
|||
cmake -DLLVM_DIR=$LLVM -DMLIR_DIR=$MLIR ~/flang/src
|
||||
make
|
||||
```
|
||||
|
||||
### Build The New Flang Driver
|
||||
The new Flang driver, `flang-new`, is currently under active development and
|
||||
should be considered as an experimental feature. For this reason it is disabled
|
||||
by default. This will change once the new driver replaces the _throwaway_
|
||||
driver, `flang`.
|
||||
|
||||
In order to build the new driver, add `-DBUILD_FLANG_NEW_DRIVER=ON` to your
|
||||
CMake invocation line. Additionally, when building out-of-tree, use `CLANG_DIR`
|
||||
(similarly to `LLVM_DIR` and `MLIR_DIR`) to find the installed Clang
|
||||
components.
|
||||
|
||||
**Note:** `CLANG_DIR` is only required when building the new Flang driver,
|
||||
which currently depends on Clang.
|
||||
|
||||
# How to Run Tests
|
||||
|
||||
Flang supports 2 different categories of tests
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
//===-- CompilerInstance.h - Flang Compiler Instance ------------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H
|
||||
#define LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H
|
||||
|
||||
#include "flang/Frontend/CompilerInvocation.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
namespace Fortran::frontend {
|
||||
|
||||
class CompilerInstance {
|
||||
|
||||
/// The options used in this compiler instance.
|
||||
std::shared_ptr<CompilerInvocation> invocation_;
|
||||
|
||||
/// The diagnostics engine instance.
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_;
|
||||
|
||||
public:
|
||||
explicit CompilerInstance();
|
||||
|
||||
~CompilerInstance();
|
||||
CompilerInvocation &GetInvocation() {
|
||||
assert(invocation_ && "Compiler instance has no invocation!");
|
||||
return *invocation_;
|
||||
};
|
||||
|
||||
/// }
|
||||
/// @name Forwarding Methods
|
||||
/// {
|
||||
|
||||
clang::DiagnosticOptions &GetDiagnosticOpts() {
|
||||
return invocation_->GetDiagnosticOpts();
|
||||
}
|
||||
const clang::DiagnosticOptions &GetDiagnosticOpts() const {
|
||||
return invocation_->GetDiagnosticOpts();
|
||||
}
|
||||
|
||||
FrontendOptions &GetFrontendOpts() { return invocation_->GetFrontendOpts(); }
|
||||
const FrontendOptions &GetFrontendOpts() const {
|
||||
return invocation_->GetFrontendOpts();
|
||||
}
|
||||
|
||||
/// }
|
||||
/// @name Diagnostics Engine
|
||||
/// {
|
||||
|
||||
bool HasDiagnostics() const { return diagnostics_ != nullptr; }
|
||||
|
||||
/// Get the current diagnostics engine.
|
||||
clang::DiagnosticsEngine &GetDiagnostics() const {
|
||||
assert(diagnostics_ && "Compiler instance has no diagnostics!");
|
||||
return *diagnostics_;
|
||||
}
|
||||
|
||||
/// SetDiagnostics - Replace the current diagnostics engine.
|
||||
void SetDiagnostics(clang::DiagnosticsEngine *value);
|
||||
|
||||
clang::DiagnosticConsumer &GetDiagnosticClient() const {
|
||||
assert(diagnostics_ && diagnostics_->getClient() &&
|
||||
"Compiler instance has no diagnostic client!");
|
||||
return *diagnostics_->getClient();
|
||||
}
|
||||
|
||||
/// Get the current diagnostics engine.
|
||||
clang::DiagnosticsEngine &getDiagnostics() const {
|
||||
assert(diagnostics_ && "Compiler instance has no diagnostics!");
|
||||
return *diagnostics_;
|
||||
}
|
||||
|
||||
/// }
|
||||
/// @name Construction Utility Methods
|
||||
/// {
|
||||
|
||||
/// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter.
|
||||
///
|
||||
/// If no diagnostic client is provided, this creates a
|
||||
/// DiagnosticConsumer that is owned by the returned diagnostic
|
||||
/// object, if using directly the caller is responsible for
|
||||
/// releasing the returned DiagnosticsEngine's client eventually.
|
||||
///
|
||||
/// \param opts - The diagnostic options; note that the created text
|
||||
/// diagnostic object contains a reference to these options.
|
||||
///
|
||||
/// \param client If non-NULL, a diagnostic client that will be
|
||||
/// attached to (and, then, owned by) the returned DiagnosticsEngine
|
||||
/// object.
|
||||
///
|
||||
/// \return The new object on success, or null on failure.
|
||||
static clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine> CreateDiagnostics(
|
||||
clang::DiagnosticOptions *opts,
|
||||
clang::DiagnosticConsumer *client = nullptr, bool shouldOwnClient = true);
|
||||
void CreateDiagnostics(
|
||||
clang::DiagnosticConsumer *client = nullptr, bool shouldOwnClient = true);
|
||||
};
|
||||
|
||||
} // end namespace Fortran::frontend
|
||||
#endif // LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H
|
|
@ -0,0 +1,53 @@
|
|||
//===- CompilerInvocation.h - Compiler Invocation Helper Data ---*- C -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_FLANG_FRONTEND_COMPILERINVOCATION_H
|
||||
#define LLVM_FLANG_FRONTEND_COMPILERINVOCATION_H
|
||||
|
||||
#include "flang/Frontend/FrontendOptions.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
|
||||
namespace Fortran::frontend {
|
||||
class CompilerInvocationBase {
|
||||
public:
|
||||
/// Options controlling the diagnostic engine.$
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagnosticOpts_;
|
||||
|
||||
CompilerInvocationBase();
|
||||
CompilerInvocationBase(const CompilerInvocationBase &x);
|
||||
~CompilerInvocationBase();
|
||||
|
||||
clang::DiagnosticOptions &GetDiagnosticOpts() {
|
||||
return *diagnosticOpts_.get();
|
||||
}
|
||||
const clang::DiagnosticOptions &GetDiagnosticOpts() const {
|
||||
return *diagnosticOpts_.get();
|
||||
}
|
||||
};
|
||||
|
||||
class CompilerInvocation : public CompilerInvocationBase {
|
||||
/// Options controlling the frontend itself.
|
||||
FrontendOptions frontendOpts_;
|
||||
|
||||
public:
|
||||
CompilerInvocation() = default;
|
||||
|
||||
FrontendOptions &GetFrontendOpts() { return frontendOpts_; }
|
||||
const FrontendOptions &GetFrontendOpts() const { return frontendOpts_; }
|
||||
|
||||
/// Create a compiler invocation from a list of input options.
|
||||
/// \returns true on success.
|
||||
/// \returns false if an error was encountered while parsing the arguments
|
||||
/// \param [out] res - The resulting invocation.
|
||||
static bool CreateFromArgs(CompilerInvocation &res,
|
||||
llvm::ArrayRef<const char *> commandLineArgs,
|
||||
clang::DiagnosticsEngine &diags);
|
||||
};
|
||||
|
||||
} // end namespace Fortran::frontend
|
||||
#endif // LLVM_FLANG_FRONTEND_COMPILERINVOCATION_H
|
|
@ -0,0 +1,58 @@
|
|||
//===- FrontendOptions.h ----------------------------------------*- C -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_FLANG_FRONTEND_FRONTENDOPTIONS_H
|
||||
#define LLVM_FLANG_FRONTEND_FRONTENDOPTIONS_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
namespace Fortran::frontend {
|
||||
|
||||
enum class Language : uint8_t {
|
||||
Unknown,
|
||||
|
||||
/// LLVM IR: we accept this so that we can run the optimizer on it,
|
||||
/// and compile it to assembly or object code.
|
||||
LLVM_IR,
|
||||
|
||||
///@{ Languages that the frontend can parse and compile.
|
||||
Fortran,
|
||||
///@}
|
||||
};
|
||||
|
||||
/// The kind of a file that we've been handed as an input.
|
||||
class InputKind {
|
||||
private:
|
||||
Language lang_;
|
||||
|
||||
public:
|
||||
/// The input file format.
|
||||
enum Format { Source, ModuleMap, Precompiled };
|
||||
|
||||
constexpr InputKind(Language l = Language::Unknown) : lang_(l) {}
|
||||
|
||||
Language GetLanguage() const { return static_cast<Language>(lang_); }
|
||||
|
||||
/// Is the input kind fully-unknown?
|
||||
bool IsUnknown() const { return lang_ == Language::Unknown; }
|
||||
};
|
||||
|
||||
/// FrontendOptions - Options for controlling the behavior of the frontend.
|
||||
class FrontendOptions {
|
||||
public:
|
||||
/// Show the -help text.
|
||||
unsigned showHelp_ : 1;
|
||||
|
||||
/// Show the -version text.
|
||||
unsigned showVersion_ : 1;
|
||||
|
||||
public:
|
||||
FrontendOptions() : showHelp_(false), showVersion_(false) {}
|
||||
};
|
||||
} // namespace Fortran::frontend
|
||||
|
||||
#endif // LLVM_FLANG_FRONTEND_FRONTENDOPTIONS_H
|
|
@ -0,0 +1,29 @@
|
|||
//===--- Utils.h - Misc utilities for the flang front-end --------*- C++-*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header contains miscellaneous utilities for various front-end actions
|
||||
// which were split from Frontend to minimise Frontend's dependencies.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FLANG_FRONTENDTOOL_UTILS_H
|
||||
#define LLVM_FLANG_FRONTENDTOOL_UTILS_H
|
||||
|
||||
namespace Fortran::frontend {
|
||||
|
||||
class CompilerInstance;
|
||||
|
||||
/// ExecuteCompilerInvocation - Execute the given actions described by the
|
||||
/// compiler invocation object in the given compiler instance.
|
||||
///
|
||||
/// \return - True on success.
|
||||
bool ExecuteCompilerInvocation(CompilerInstance *flang);
|
||||
|
||||
} // end namespace Fortran::frontend
|
||||
|
||||
#endif // LLVM_FLANG_FRONTENDTOOL_UTILS_H
|
|
@ -5,6 +5,11 @@ add_subdirectory(Lower)
|
|||
add_subdirectory(Parser)
|
||||
add_subdirectory(Semantics)
|
||||
|
||||
if(FLANG_BUILD_NEW_DRIVER)
|
||||
add_subdirectory(Frontend)
|
||||
add_subdirectory(FrontendTool)
|
||||
endif()
|
||||
|
||||
if(LINK_WITH_FIR)
|
||||
add_subdirectory(Optimizer)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
add_flang_library(flangFrontend
|
||||
CompilerInstance.cpp
|
||||
CompilerInvocation.cpp
|
||||
FrontendOptions.cpp
|
||||
|
||||
LINK_LIBS
|
||||
clangBasic
|
||||
clangDriver
|
||||
# TODO: Added to re-use clang's TextDiagnosticBuffer & TextDiagnosticPrinter.
|
||||
# Add a custom implementation for Flang and remove this dependency.
|
||||
clangFrontend
|
||||
|
||||
LINK_COMPONENTS
|
||||
Option
|
||||
Support
|
||||
)
|
|
@ -0,0 +1,42 @@
|
|||
//===--- CompilerInstance.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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "flang/Frontend/CompilerInstance.h"
|
||||
#include "flang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace Fortran::frontend;
|
||||
|
||||
CompilerInstance::CompilerInstance() : invocation_(new CompilerInvocation()) {}
|
||||
|
||||
CompilerInstance::~CompilerInstance() = default;
|
||||
|
||||
void CompilerInstance::CreateDiagnostics(
|
||||
clang::DiagnosticConsumer *client, bool shouldOwnClient) {
|
||||
diagnostics_ =
|
||||
CreateDiagnostics(&GetDiagnosticOpts(), client, shouldOwnClient);
|
||||
}
|
||||
|
||||
clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine>
|
||||
CompilerInstance::CreateDiagnostics(clang::DiagnosticOptions *opts,
|
||||
clang::DiagnosticConsumer *client, bool shouldOwnClient) {
|
||||
clang::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
|
||||
new clang::DiagnosticIDs());
|
||||
clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags(
|
||||
new clang::DiagnosticsEngine(diagID, opts));
|
||||
|
||||
// Create the diagnostic client for reporting errors or for
|
||||
// implementing -verify.
|
||||
if (client) {
|
||||
diags->setClient(client, shouldOwnClient);
|
||||
} else {
|
||||
diags->setClient(new clang::TextDiagnosticPrinter(llvm::errs(), opts));
|
||||
}
|
||||
return diags;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
//===- CompilerInvocation.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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "flang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Basic/AllDiagnostics.h"
|
||||
#include "clang/Basic/DiagnosticDriver.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Driver/DriverDiagnostic.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Option/Arg.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Option/OptTable.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace Fortran::frontend;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Initialization.
|
||||
//===----------------------------------------------------------------------===//
|
||||
CompilerInvocationBase::CompilerInvocationBase()
|
||||
: diagnosticOpts_(new clang::DiagnosticOptions()) {}
|
||||
|
||||
CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &x)
|
||||
: diagnosticOpts_(new clang::DiagnosticOptions(x.GetDiagnosticOpts())) {}
|
||||
|
||||
CompilerInvocationBase::~CompilerInvocationBase() = default;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Deserialization (from args)
|
||||
//===----------------------------------------------------------------------===//
|
||||
static InputKind ParseFrontendArgs(FrontendOptions &opts,
|
||||
llvm::opt::ArgList &args, clang::DiagnosticsEngine &diags) {
|
||||
// Identify the action (i.e. opts.ProgramAction)
|
||||
if (const llvm::opt::Arg *a =
|
||||
args.getLastArg(clang::driver::options::OPT_Action_Group)) {
|
||||
switch (a->getOption().getID()) {
|
||||
default: {
|
||||
llvm_unreachable("Invalid option in group!");
|
||||
}
|
||||
// TODO:
|
||||
// case clang::driver::options::OPT_E:
|
||||
// case clang::driver::options::OPT_emit_obj:
|
||||
// case calng::driver::options::OPT_emit_llvm:
|
||||
// case clang::driver::options::OPT_emit_llvm_only:
|
||||
// case clang::driver::options::OPT_emit_codegen_only:
|
||||
// case clang::driver::options::OPT_emit_module:
|
||||
// (...)
|
||||
}
|
||||
}
|
||||
|
||||
opts.showHelp_ = args.hasArg(clang::driver::options::OPT_help);
|
||||
opts.showVersion_ = args.hasArg(clang::driver::options::OPT_version);
|
||||
|
||||
// Get the input kind (from the value passed via `-x`)
|
||||
InputKind dashX(Language::Unknown);
|
||||
if (const llvm::opt::Arg *a =
|
||||
args.getLastArg(clang::driver::options::OPT_x)) {
|
||||
llvm::StringRef XValue = a->getValue();
|
||||
// Principal languages.
|
||||
dashX = llvm::StringSwitch<InputKind>(XValue)
|
||||
.Case("f90", Language::Fortran)
|
||||
.Default(Language::Unknown);
|
||||
|
||||
// Some special cases cannot be combined with suffixes.
|
||||
if (dashX.IsUnknown())
|
||||
dashX = llvm::StringSwitch<InputKind>(XValue)
|
||||
.Case("ir", Language::LLVM_IR)
|
||||
.Default(Language::Unknown);
|
||||
|
||||
if (dashX.IsUnknown())
|
||||
diags.Report(clang::diag::err_drv_invalid_value)
|
||||
<< a->getAsString(args) << a->getValue();
|
||||
}
|
||||
|
||||
return dashX;
|
||||
}
|
||||
|
||||
bool CompilerInvocation::CreateFromArgs(CompilerInvocation &res,
|
||||
llvm::ArrayRef<const char *> commandLineArgs,
|
||||
clang::DiagnosticsEngine &diags) {
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Parse the arguments
|
||||
const llvm::opt::OptTable &opts = clang::driver::getDriverOptTable();
|
||||
const unsigned includedFlagsBitmask =
|
||||
clang::driver::options::FC1Option;
|
||||
unsigned missingArgIndex, missingArgCount;
|
||||
llvm::opt::InputArgList args = opts.ParseArgs(
|
||||
commandLineArgs, missingArgIndex, missingArgCount, includedFlagsBitmask);
|
||||
|
||||
// Issue errors on unknown arguments
|
||||
for (const auto *a : args.filtered(clang::driver::options::OPT_UNKNOWN)) {
|
||||
auto argString = a->getAsString(args);
|
||||
std::string nearest;
|
||||
if (opts.findNearest(argString, nearest, includedFlagsBitmask) > 1)
|
||||
diags.Report(clang::diag::err_drv_unknown_argument) << argString;
|
||||
else
|
||||
diags.Report(clang::diag::err_drv_unknown_argument_with_suggestion)
|
||||
<< argString << nearest;
|
||||
success = false;
|
||||
}
|
||||
|
||||
// Parse the frontend args
|
||||
ParseFrontendArgs(res.GetFrontendOpts(), args, diags);
|
||||
|
||||
return success;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
//===- FrontendOptions.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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "flang/Frontend/FrontendOptions.h"
|
|
@ -0,0 +1,11 @@
|
|||
add_flang_library(flangFrontendTool
|
||||
ExecuteCompilerInvocation.cpp
|
||||
|
||||
LINK_LIBS
|
||||
clangBasic
|
||||
clangDriver
|
||||
|
||||
LINK_COMPONENTS
|
||||
Option
|
||||
Support
|
||||
)
|
|
@ -0,0 +1,39 @@
|
|||
//===--- ExecuteCompilerInvocation.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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file holds ExecuteCompilerInvocation(). It is split into its own file to
|
||||
// minimize the impact of pulling in essentially everything else in Flang.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "flang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "llvm/Option/OptTable.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
namespace Fortran::frontend {
|
||||
bool ExecuteCompilerInvocation(CompilerInstance *flang) {
|
||||
// Honor -help.
|
||||
if (flang->GetFrontendOpts().showHelp_) {
|
||||
clang::driver::getDriverOptTable().PrintHelp(llvm::outs(),
|
||||
"flang-new -fc1 [options] file...", "LLVM 'Flang' Compiler",
|
||||
/*Include=*/clang::driver::options::FlangOption,
|
||||
/*Exclude=*/0, /*ShowAllAliases=*/false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Honor -version.
|
||||
if (flang->GetFrontendOpts().showVersion_) {
|
||||
llvm::cl::PrintVersionMessage();
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Fortran::frontend
|
|
@ -41,6 +41,10 @@ if (LINK_WITH_FIR)
|
|||
list(APPEND FLANG_TEST_DEPENDS tco)
|
||||
endif()
|
||||
|
||||
if (FLANG_BUILD_NEW_DRIVER)
|
||||
list(APPEND FLANG_TEST_DEPENDS flang-new)
|
||||
endif()
|
||||
|
||||
if (FLANG_INCLUDE_TESTS)
|
||||
if (FLANG_GTEST_AVAIL)
|
||||
list(APPEND FLANG_TEST_DEPENDS FlangUnitTests)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
// RUN: not %flang-new %s 2>&1 | FileCheck %s
|
||||
|
||||
// REQUIRES: new-flang-driver
|
||||
|
||||
// C files are currently not supported (i.e. `flang -cc1`)
|
||||
|
||||
// CHECK:error: unknown integrated tool '-cc1'. Valid tools include '-fc1'.
|
|
@ -0,0 +1,7 @@
|
|||
// RUN: not %flang-new %s 2>&1 | FileCheck %s
|
||||
|
||||
// REQUIRES: new-flang-driver
|
||||
|
||||
// C++ files are currently not supported (i.e. `flang -cc1`)
|
||||
|
||||
// CHECK:error: unknown integrated tool '-cc1'. Valid tools include '-fc1'.
|
|
@ -0,0 +1,13 @@
|
|||
! RUN: %flang-new -help 2>&1 | FileCheck %s
|
||||
! RUN: %flang-new -fc1 -help 2>&1 | FileCheck %s
|
||||
! RUN: not %flang-new -helps 2>&1 | FileCheck %s --check-prefix=ERROR
|
||||
|
||||
! REQUIRES: new-flang-driver
|
||||
|
||||
! CHECK:USAGE: flang-new
|
||||
! CHECK-EMPTY:
|
||||
! CHECK-NEXT:OPTIONS:
|
||||
! CHECK-NEXT: -help Display available options
|
||||
! CHECK-NEXT: --version Print version information
|
||||
|
||||
! ERROR: error: unknown argument '-helps'; did you mean '-help'
|
|
@ -0,0 +1,11 @@
|
|||
! RUN: %flang-new --version 2>&1 | FileCheck %s
|
||||
! RUN: not %flang-new --versions 2>&1 | FileCheck %s --check-prefix=ERROR
|
||||
|
||||
! REQUIRES: new-flang-driver
|
||||
|
||||
! CHECK:flang-new version
|
||||
! CHECK-NEXT:Target:
|
||||
! CHECK-NEXT:Thread model:
|
||||
! CHECK-NEXT:InstalledDir:
|
||||
|
||||
! ERROR: error: unsupported option '--versions'; did you mean '--version'?
|
|
@ -0,0 +1,17 @@
|
|||
! RUN: not %flang-new %s 2>&1 | FileCheck %s --check-prefix=ERROR-IMPLICIT
|
||||
! RUN: not %flang-new -emit-obj %s 2>&1 | FileCheck %s --check-prefix=ERROR-EXPLICIT
|
||||
! RUN: not %flang-new -fc1 -emit-obj %s 2>&1 | FileCheck %s --check-prefix=ERROR-FC1
|
||||
|
||||
! REQUIRES: new-flang-driver
|
||||
|
||||
! By default (e.g. when no options like `-E` are passed) flang-new
|
||||
! creates a job that corresponds to `-emit-obj`. This option/action is
|
||||
! not yet supported. Verify that this is correctly reported as error.
|
||||
|
||||
! ERROR-IMPLICIT: error: unknown argument: '-triple'
|
||||
! ERROR-IMPLICIT: error: unknown argument: '-emit-obj'
|
||||
! ERROR-IMPLICIT: error: unknown argument: '-o'
|
||||
|
||||
! ERROR-EXPLICIT: error: unknown argument: '-o'
|
||||
|
||||
! ERROR-FC1: error: unknown argument: '-emit-obj'
|
|
@ -0,0 +1,5 @@
|
|||
! RUN: not %flang-new 2>&1 | FileCheck %s
|
||||
|
||||
! REQUIRES: new-flang-driver
|
||||
|
||||
! CHECK: error: no input files
|
|
@ -25,7 +25,7 @@ config.name = 'Flang'
|
|||
config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
|
||||
|
||||
# suffixes: A list of file extensions to treat as test files.
|
||||
config.suffixes = ['.f', '.F', '.ff', '.FOR', '.for', '.f77', '.f90', '.F90',
|
||||
config.suffixes = ['.c', '.cpp', '.f', '.F', '.ff', '.FOR', '.for', '.f77', '.f90', '.F90',
|
||||
'.ff90', '.f95', '.F95', '.ff95', '.fpp', '.FPP', '.cuf',
|
||||
'.CUF', '.f18', '.F18', '.fir']
|
||||
|
||||
|
@ -38,6 +38,13 @@ llvm_config.use_default_substitutions()
|
|||
# directories.
|
||||
config.excludes = ['Inputs', 'CMakeLists.txt', 'README.txt', 'LICENSE.txt']
|
||||
|
||||
# If the new Flang driver is enabled, add the corresponding feature to
|
||||
# config. Otherwise, exclude the corresponding test directory.
|
||||
if config.include_flang_new_driver_test:
|
||||
config.available_features.add('new-flang-driver')
|
||||
else:
|
||||
config.excludes.append('Flang-Driver')
|
||||
|
||||
# test_source_root: The root path where tests are located.
|
||||
config.test_source_root = os.path.dirname(__file__)
|
||||
|
||||
|
@ -63,6 +70,9 @@ tools = [
|
|||
unresolved='fatal')
|
||||
]
|
||||
|
||||
if config.include_flang_new_driver_test:
|
||||
tools.append(ToolSubst('%flang-new', command=FindTool('flang-new'), unresolved='fatal'))
|
||||
|
||||
if config.flang_standalone_build:
|
||||
llvm_config.add_tool_substitutions(tools, [config.flang_llvm_tools_dir])
|
||||
else:
|
||||
|
|
|
@ -11,6 +11,11 @@ config.flang_llvm_tools_dir = "@CMAKE_BINARY_DIR@/bin"
|
|||
config.python_executable = "@PYTHON_EXECUTABLE@"
|
||||
config.flang_standalone_build = @FLANG_STANDALONE_BUILD@
|
||||
|
||||
# Control the regression test for flang-new driver
|
||||
import lit.util
|
||||
config.include_flang_new_driver_test = \
|
||||
lit.util.pythonize_bool("@FLANG_BUILD_NEW_DRIVER@")
|
||||
|
||||
# Support substitution of the tools_dir with user parameters. This is
|
||||
# used when we can't determine the tool dir at configuration time.
|
||||
try:
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#===------------------------------------------------------------------------===#
|
||||
|
||||
add_subdirectory(f18)
|
||||
if(FLANG_BUILD_NEW_DRIVER)
|
||||
add_subdirectory(flang-driver)
|
||||
endif()
|
||||
if(LINK_WITH_FIR)
|
||||
add_subdirectory(tco)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# Infrastructure to build flang driver entry point. Flang driver depends on
|
||||
# LLVM libraries.
|
||||
|
||||
# Set your project compile flags.
|
||||
link_directories(${LLVM_LIBRARY_DIR})
|
||||
|
||||
add_flang_tool(flang-new
|
||||
driver.cpp
|
||||
fc1_main.cpp
|
||||
)
|
||||
|
||||
# Link against LLVM and Clang libraries
|
||||
target_link_libraries(flang-new
|
||||
PRIVATE
|
||||
${LLVM_COMMON_LIBS}
|
||||
flangFrontend
|
||||
flangFrontendTool
|
||||
clangDriver
|
||||
clangBasic
|
||||
LLVMSupport
|
||||
LLVMTarget
|
||||
LLVMOption
|
||||
)
|
||||
|
||||
install(TARGETS flang-new DESTINATION bin)
|
|
@ -0,0 +1,129 @@
|
|||
//===-- driver.cpp - Flang Driver -----------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the entry point to the flang driver; it is a thin wrapper
|
||||
// for functionality in the Driver flang library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/DiagnosticIDs.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
|
||||
// main frontend method. Lives inside fc1_main.cpp
|
||||
extern int fc1_main(llvm::ArrayRef<const char *> argv, const char *argv0);
|
||||
|
||||
std::string GetExecutablePath(const char *argv0) {
|
||||
// This just needs to be some symbol in the binary
|
||||
void *p = (void *)(intptr_t)GetExecutablePath;
|
||||
return llvm::sys::fs::getMainExecutable(argv0, p);
|
||||
}
|
||||
|
||||
// This lets us create the DiagnosticsEngine with a properly-filled-out
|
||||
// DiagnosticOptions instance
|
||||
static clang::DiagnosticOptions *CreateAndPopulateDiagOpts(
|
||||
llvm::ArrayRef<const char *> argv) {
|
||||
auto *diagOpts = new clang::DiagnosticOptions;
|
||||
return diagOpts;
|
||||
}
|
||||
|
||||
static int ExecuteFC1Tool(llvm::SmallVectorImpl<const char *> &argV) {
|
||||
llvm::StringRef tool = argV[1];
|
||||
if (tool == "-fc1")
|
||||
return fc1_main(makeArrayRef(argV).slice(2), argV[0]);
|
||||
|
||||
// Reject unknown tools.
|
||||
// ATM it only supports fc1. Any fc1[*] is rejected.
|
||||
llvm::errs() << "error: unknown integrated tool '" << tool << "'. "
|
||||
<< "Valid tools include '-fc1'.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc_, const char **argv_) {
|
||||
|
||||
// Initialize variables to call the driver
|
||||
llvm::InitLLVM x(argc_, argv_);
|
||||
llvm::SmallVector<const char *, 256> argv(argv_, argv_ + argc_);
|
||||
|
||||
clang::driver::ParsedClangName targetandMode("flang", "--driver-mode=flang");
|
||||
std::string driverPath = GetExecutablePath(argv[0]);
|
||||
|
||||
// Check if flang-new is in the frontend mode
|
||||
auto firstArg = std::find_if(
|
||||
argv.begin() + 1, argv.end(), [](const char *a) { return a != nullptr; });
|
||||
if (firstArg != argv.end()) {
|
||||
if (llvm::StringRef(argv[1]).startswith("-cc1")) {
|
||||
llvm::errs() << "error: unknown integrated tool '" << argv[1] << "'. "
|
||||
<< "Valid tools include '-fc1'.\n";
|
||||
return 1;
|
||||
}
|
||||
// Call flang-new frontend
|
||||
if (llvm::StringRef(argv[1]).startswith("-fc1")) {
|
||||
return ExecuteFC1Tool(argv);
|
||||
}
|
||||
}
|
||||
|
||||
// Not in the frontend mode - continue in the compiler driver mode.
|
||||
|
||||
// Create DiagnosticsEngine for the compiler driver
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts =
|
||||
CreateAndPopulateDiagOpts(argv);
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
|
||||
new clang::DiagnosticIDs());
|
||||
clang::TextDiagnosticPrinter *diagClient =
|
||||
new clang::TextDiagnosticPrinter(llvm::errs(), &*diagOpts);
|
||||
clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagClient);
|
||||
|
||||
// Prepare the driver
|
||||
clang::driver::Driver theDriver(driverPath,
|
||||
llvm::sys::getDefaultTargetTriple(), diags, "flang LLVM compiler");
|
||||
theDriver.setTargetAndMode(targetandMode);
|
||||
std::unique_ptr<clang::driver::Compilation> c(
|
||||
theDriver.BuildCompilation(argv));
|
||||
llvm::SmallVector<std::pair<int, const clang::driver::Command *>, 4>
|
||||
failingCommands;
|
||||
|
||||
// Run the driver
|
||||
int res = 1;
|
||||
bool isCrash = false;
|
||||
res = theDriver.ExecuteCompilation(*c, failingCommands);
|
||||
|
||||
for (const auto &p : failingCommands) {
|
||||
int CommandRes = p.first;
|
||||
const clang::driver::Command *failingCommand = p.second;
|
||||
if (!res)
|
||||
res = CommandRes;
|
||||
|
||||
// If result status is < 0 (e.g. when sys::ExecuteAndWait returns -1),
|
||||
// then the driver command signalled an error. On Windows, abort will
|
||||
// return an exit code of 3. In these cases, generate additional diagnostic
|
||||
// information if possible.
|
||||
isCrash = CommandRes < 0;
|
||||
#ifdef _WIN32
|
||||
IsCrash |= CommandRes == 3;
|
||||
#endif
|
||||
if (isCrash) {
|
||||
theDriver.generateCompilationDiagnostics(*c, *failingCommand);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
diags.getClient()->finish();
|
||||
|
||||
// If we have multiple failing commands, we return the result of the first
|
||||
// failing command.
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
//===-- fc1_main.cpp - Flang FC1 Compiler Frontend ------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the entry point to the flang -fc1 functionality, which implements the
|
||||
// core compiler functionality along with a number of additional tools for
|
||||
// demonstration and testing purposes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "flang/Frontend/CompilerInstance.h"
|
||||
#include "flang/Frontend/CompilerInvocation.h"
|
||||
#include "flang/FrontendTool/Utils.h"
|
||||
#include "clang/Driver/DriverDiagnostic.h"
|
||||
#include "clang/Frontend/TextDiagnosticBuffer.h"
|
||||
#include "llvm/Option/Arg.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Option/OptTable.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
using namespace Fortran::frontend;
|
||||
|
||||
int fc1_main(llvm::ArrayRef<const char *> argv, const char *argv0) {
|
||||
// Create CompilerInstance
|
||||
std::unique_ptr<CompilerInstance> flang(new CompilerInstance());
|
||||
|
||||
// Create DiagnosticsEngine for the frontend driver
|
||||
flang->CreateDiagnostics();
|
||||
if (!flang->HasDiagnostics())
|
||||
return 1;
|
||||
|
||||
// Create CompilerInvocation - use a dedicated instance of DiagnosticsEngine
|
||||
// for parsing the arguments
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
|
||||
new clang::DiagnosticIDs());
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts =
|
||||
new clang::DiagnosticOptions();
|
||||
clang::TextDiagnosticBuffer *diagsBuffer = new clang::TextDiagnosticBuffer;
|
||||
clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagsBuffer);
|
||||
bool success =
|
||||
CompilerInvocation::CreateFromArgs(flang->GetInvocation(), argv, diags);
|
||||
|
||||
diagsBuffer->FlushDiagnostics(flang->getDiagnostics());
|
||||
if (!success)
|
||||
return 1;
|
||||
|
||||
// Execute the frontend actions.
|
||||
success = ExecuteCompilerInvocation(flang.get());
|
||||
|
||||
return !success;
|
||||
}
|
|
@ -22,3 +22,7 @@ add_subdirectory(Decimal)
|
|||
add_subdirectory(Evaluate)
|
||||
add_subdirectory(Runtime)
|
||||
add_subdirectory(Lower)
|
||||
|
||||
if (FLANG_BUILD_NEW_DRIVER)
|
||||
add_subdirectory(Frontend)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
add_flang_unittest(FlangFrontendTests
|
||||
CompilerInstanceTest.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(FlangFrontendTests
|
||||
PRIVATE
|
||||
LLVMSupport
|
||||
clangBasic
|
||||
flangFrontend
|
||||
flangFrontendTool)
|
|
@ -0,0 +1,52 @@
|
|||
//===- unittests/Frontend/CompilerInstanceTest.cpp - CI tests -------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "flang/Frontend/CompilerInstance.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "flang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <filesystem>
|
||||
using namespace llvm;
|
||||
using namespace Fortran::frontend;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
|
||||
// 1. Set-up a basic DiagnosticConsumer
|
||||
std::string diagnosticOutput;
|
||||
llvm::raw_string_ostream diagnosticsOS(diagnosticOutput);
|
||||
auto diagPrinter = std::make_unique<clang::TextDiagnosticPrinter>(
|
||||
diagnosticsOS, new clang::DiagnosticOptions());
|
||||
|
||||
// 2. Create a CompilerInstance (to manage a DiagnosticEngine)
|
||||
CompilerInstance compInst;
|
||||
|
||||
// 3. Set-up DiagnosticOptions
|
||||
auto diagOpts = new clang::DiagnosticOptions();
|
||||
// Tell the diagnostics engine to emit the diagnostic log to STDERR. This
|
||||
// ensures that a chained diagnostic consumer is created so that the test can
|
||||
// exercise the unowned diagnostic consumer in a chained consumer.
|
||||
diagOpts->DiagnosticLogFile = "-";
|
||||
|
||||
// 4. Create a DiagnosticEngine with an unowned consumer
|
||||
IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags =
|
||||
compInst.CreateDiagnostics(diagOpts, diagPrinter.get(),
|
||||
/*ShouldOwnClient=*/false);
|
||||
|
||||
// 5. Report a diagnostic
|
||||
diags->Report(clang::diag::err_expected) << "no crash";
|
||||
|
||||
// 6. Verify that the reported diagnostic wasn't lost and did end up in the
|
||||
// output stream
|
||||
ASSERT_EQ(diagnosticsOS.str(), "error: expected no crash\n");
|
||||
}
|
||||
} // namespace
|
|
@ -50,7 +50,7 @@ public:
|
|||
unsigned ID;
|
||||
unsigned char Kind;
|
||||
unsigned char Param;
|
||||
unsigned short Flags;
|
||||
unsigned int Flags;
|
||||
unsigned short GroupID;
|
||||
unsigned short AliasID;
|
||||
const char *AliasArgs;
|
||||
|
|
Loading…
Reference in New Issue