[flang-commits] [flang] 257b297 - [flang][driver] Add the new flang compiler and frontend drivers
Caroline Concatto via flang-commits
flang-commits at lists.llvm.org
Fri Sep 11 03:00:42 PDT 2020
Author: Caroline Concatto
Date: 2020-09-11T10:55:54+01:00
New Revision: 257b29715bb27b7d9f6c3c40c481b6a4af0b37e5
URL: https://github.com/llvm/llvm-project/commit/257b29715bb27b7d9f6c3c40c481b6a4af0b37e5
DIFF: https://github.com/llvm/llvm-project/commit/257b29715bb27b7d9f6c3c40c481b6a4af0b37e5.diff
LOG: [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 at arm.com>
Reviewed By: richard.barton.arm, sameeranjoshi
Differential Revision: https://reviews.llvm.org/D86089
Added:
flang/include/flang/Frontend/CompilerInstance.h
flang/include/flang/Frontend/CompilerInvocation.h
flang/include/flang/Frontend/FrontendOptions.h
flang/include/flang/FrontendTool/Utils.h
flang/lib/Frontend/CMakeLists.txt
flang/lib/Frontend/CompilerInstance.cpp
flang/lib/Frontend/CompilerInvocation.cpp
flang/lib/Frontend/FrontendOptions.cpp
flang/lib/FrontendTool/CMakeLists.txt
flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
flang/test/Flang-Driver/driver-error-cc1.c
flang/test/Flang-Driver/driver-error-cc1.cpp
flang/test/Flang-Driver/driver-help.f90
flang/test/Flang-Driver/driver-version.f90
flang/test/Flang-Driver/emit-obj.f90
flang/test/Flang-Driver/missing-input.f90
flang/tools/flang-driver/CMakeLists.txt
flang/tools/flang-driver/driver.cpp
flang/tools/flang-driver/fc1_main.cpp
flang/unittests/Frontend/CMakeLists.txt
flang/unittests/Frontend/CompilerInstanceTest.cpp
Modified:
clang/include/clang/Driver/Driver.h
clang/include/clang/Driver/Options.h
clang/include/clang/Driver/Options.td
clang/lib/Driver/Driver.cpp
clang/lib/Driver/ToolChains/Flang.cpp
clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
clang/lib/Tooling/Tooling.cpp
clang/test/Driver/flang/flang.f90
clang/test/Driver/flang/flang_ucase.F90
clang/test/Driver/flang/multiple-inputs-mixed.f90
clang/test/Driver/flang/multiple-inputs.f90
clang/unittests/Driver/SanitizerArgsTest.cpp
clang/unittests/Driver/ToolChainTest.cpp
flang/CMakeLists.txt
flang/README.md
flang/lib/CMakeLists.txt
flang/test/CMakeLists.txt
flang/test/lit.cfg.py
flang/test/lit.site.cfg.py.in
flang/tools/CMakeLists.txt
flang/unittests/CMakeLists.txt
llvm/include/llvm/Option/OptTable.h
Removed:
################################################################################
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index dc18f1314f81..7a476199ff7f 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -301,7 +301,7 @@ class Driver {
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
diff --git a/clang/include/clang/Driver/Options.h b/clang/include/clang/Driver/Options.h
index 9831efda4e58..06dd3652be94 100644
--- a/clang/include/clang/Driver/Options.h
+++ b/clang/include/clang/Driver/Options.h
@@ -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 {
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 4ba5d40117e7..922ad580a53e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -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
diff erent 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>;
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 4ac813718eac..65b44597bc16 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -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,"
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 80f6db7ea642..93401c662663 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -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() {}
diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 1d5a6c06b34f..ff0aa6faf33f 100644
--- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -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);
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 1ee8ce28c2ef..b0d3f5caf67a 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -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;
}
diff --git a/clang/test/Driver/flang/flang.f90 b/clang/test/Driver/flang/flang.f90
index a68be31343f9..e4629d527d18 100644
--- a/clang/test/Driver/flang/flang.f90
+++ b/clang/test/Driver/flang/flang.f90
@@ -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.
diff --git a/clang/test/Driver/flang/flang_ucase.F90 b/clang/test/Driver/flang/flang_ucase.F90
index dd1e20088191..4da09e138b59 100644
--- a/clang/test/Driver/flang/flang_ucase.F90
+++ b/clang/test/Driver/flang/flang_ucase.F90
@@ -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.
diff --git a/clang/test/Driver/flang/multiple-inputs-mixed.f90 b/clang/test/Driver/flang/multiple-inputs-mixed.f90
index 98d8cab00bdf..2395dbecf1fe 100644
--- a/clang/test/Driver/flang/multiple-inputs-mixed.f90
+++ b/clang/test/Driver/flang/multiple-inputs-mixed.f90
@@ -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"
diff --git a/clang/test/Driver/flang/multiple-inputs.f90 b/clang/test/Driver/flang/multiple-inputs.f90
index 34592a3dc3a3..f6ee60e48fef 100644
--- a/clang/test/Driver/flang/multiple-inputs.f90
+++ b/clang/test/Driver/flang/multiple-inputs.f90
@@ -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"
diff --git a/clang/unittests/Driver/SanitizerArgsTest.cpp b/clang/unittests/Driver/SanitizerArgsTest.cpp
index dac1caddc055..84bd56852345 100644
--- a/clang/unittests/Driver/SanitizerArgsTest.cpp
+++ b/clang/unittests/Driver/SanitizerArgsTest.cpp
@@ -57,7 +57,7 @@ class SanitizerArgsTest : public ::testing::Test {
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)
diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp
index f84e508b6cbd..67bf545b14e4 100644
--- a/clang/unittests/Driver/ToolChainTest.cpp
+++ b/clang/unittests/Driver/ToolChainTest.cpp
@@ -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(
diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt
index 707c7235a272..daae9e9b1246 100644
--- a/flang/CMakeLists.txt
+++ b/flang/CMakeLists.txt
@@ -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)
diff --git a/flang/README.md b/flang/README.md
index 3a58c277bacf..934169b9ae6a 100644
--- a/flang/README.md
+++ b/flang/README.md
@@ -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
diff erent categories of tests
diff --git a/flang/include/flang/Frontend/CompilerInstance.h b/flang/include/flang/Frontend/CompilerInstance.h
new file mode 100644
index 000000000000..298be676ea4a
--- /dev/null
+++ b/flang/include/flang/Frontend/CompilerInstance.h
@@ -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
diff --git a/flang/include/flang/Frontend/CompilerInvocation.h b/flang/include/flang/Frontend/CompilerInvocation.h
new file mode 100644
index 000000000000..0fa169fd1620
--- /dev/null
+++ b/flang/include/flang/Frontend/CompilerInvocation.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
diff --git a/flang/include/flang/Frontend/FrontendOptions.h b/flang/include/flang/Frontend/FrontendOptions.h
new file mode 100644
index 000000000000..474086f44e3b
--- /dev/null
+++ b/flang/include/flang/Frontend/FrontendOptions.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
diff --git a/flang/include/flang/FrontendTool/Utils.h b/flang/include/flang/FrontendTool/Utils.h
new file mode 100644
index 000000000000..f49c4e6dae62
--- /dev/null
+++ b/flang/include/flang/FrontendTool/Utils.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
diff --git a/flang/lib/CMakeLists.txt b/flang/lib/CMakeLists.txt
index ae321b872a76..d9848bce0fa5 100644
--- a/flang/lib/CMakeLists.txt
+++ b/flang/lib/CMakeLists.txt
@@ -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()
diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt
new file mode 100644
index 000000000000..fac3f955987f
--- /dev/null
+++ b/flang/lib/Frontend/CMakeLists.txt
@@ -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
+)
diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp
new file mode 100644
index 000000000000..bf1461dd16ad
--- /dev/null
+++ b/flang/lib/Frontend/CompilerInstance.cpp
@@ -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;
+}
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
new file mode 100644
index 000000000000..c68ad5c11d65
--- /dev/null
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -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;
+}
diff --git a/flang/lib/Frontend/FrontendOptions.cpp b/flang/lib/Frontend/FrontendOptions.cpp
new file mode 100644
index 000000000000..ea5d54aa7ff0
--- /dev/null
+++ b/flang/lib/Frontend/FrontendOptions.cpp
@@ -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"
diff --git a/flang/lib/FrontendTool/CMakeLists.txt b/flang/lib/FrontendTool/CMakeLists.txt
new file mode 100644
index 000000000000..eda040f7c716
--- /dev/null
+++ b/flang/lib/FrontendTool/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_flang_library(flangFrontendTool
+ ExecuteCompilerInvocation.cpp
+
+ LINK_LIBS
+ clangBasic
+ clangDriver
+
+ LINK_COMPONENTS
+ Option
+ Support
+)
diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
new file mode 100644
index 000000000000..ab773c95c85d
--- /dev/null
+++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -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
diff --git a/flang/test/CMakeLists.txt b/flang/test/CMakeLists.txt
index a1532dc7141f..635d3d88b61c 100644
--- a/flang/test/CMakeLists.txt
+++ b/flang/test/CMakeLists.txt
@@ -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)
diff --git a/flang/test/Flang-Driver/driver-error-cc1.c b/flang/test/Flang-Driver/driver-error-cc1.c
new file mode 100644
index 000000000000..1563ee431579
--- /dev/null
+++ b/flang/test/Flang-Driver/driver-error-cc1.c
@@ -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'.
diff --git a/flang/test/Flang-Driver/driver-error-cc1.cpp b/flang/test/Flang-Driver/driver-error-cc1.cpp
new file mode 100644
index 000000000000..20e469733bc9
--- /dev/null
+++ b/flang/test/Flang-Driver/driver-error-cc1.cpp
@@ -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'.
diff --git a/flang/test/Flang-Driver/driver-help.f90 b/flang/test/Flang-Driver/driver-help.f90
new file mode 100644
index 000000000000..6ecd076efee4
--- /dev/null
+++ b/flang/test/Flang-Driver/driver-help.f90
@@ -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'
diff --git a/flang/test/Flang-Driver/driver-version.f90 b/flang/test/Flang-Driver/driver-version.f90
new file mode 100644
index 000000000000..8552d0b2f28b
--- /dev/null
+++ b/flang/test/Flang-Driver/driver-version.f90
@@ -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'?
diff --git a/flang/test/Flang-Driver/emit-obj.f90 b/flang/test/Flang-Driver/emit-obj.f90
new file mode 100644
index 000000000000..4ddd48382862
--- /dev/null
+++ b/flang/test/Flang-Driver/emit-obj.f90
@@ -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'
diff --git a/flang/test/Flang-Driver/missing-input.f90 b/flang/test/Flang-Driver/missing-input.f90
new file mode 100644
index 000000000000..96818bc4bd38
--- /dev/null
+++ b/flang/test/Flang-Driver/missing-input.f90
@@ -0,0 +1,5 @@
+! RUN: not %flang-new 2>&1 | FileCheck %s
+
+! REQUIRES: new-flang-driver
+
+! CHECK: error: no input files
diff --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py
index 25c63890832f..21d853043431 100644
--- a/flang/test/lit.cfg.py
+++ b/flang/test/lit.cfg.py
@@ -25,7 +25,7 @@
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 @@
# 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 @@
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:
diff --git a/flang/test/lit.site.cfg.py.in b/flang/test/lit.site.cfg.py.in
index 10ec13208154..7a5928028381 100644
--- a/flang/test/lit.site.cfg.py.in
+++ b/flang/test/lit.site.cfg.py.in
@@ -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:
diff --git a/flang/tools/CMakeLists.txt b/flang/tools/CMakeLists.txt
index b973127d3443..0fbf828253ef 100644
--- a/flang/tools/CMakeLists.txt
+++ b/flang/tools/CMakeLists.txt
@@ -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()
diff --git a/flang/tools/flang-driver/CMakeLists.txt b/flang/tools/flang-driver/CMakeLists.txt
new file mode 100644
index 000000000000..d7bab277287f
--- /dev/null
+++ b/flang/tools/flang-driver/CMakeLists.txt
@@ -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)
diff --git a/flang/tools/flang-driver/driver.cpp b/flang/tools/flang-driver/driver.cpp
new file mode 100644
index 000000000000..9d04994d9843
--- /dev/null
+++ b/flang/tools/flang-driver/driver.cpp
@@ -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;
+}
diff --git a/flang/tools/flang-driver/fc1_main.cpp b/flang/tools/flang-driver/fc1_main.cpp
new file mode 100644
index 000000000000..bb69517edde2
--- /dev/null
+++ b/flang/tools/flang-driver/fc1_main.cpp
@@ -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;
+}
diff --git a/flang/unittests/CMakeLists.txt b/flang/unittests/CMakeLists.txt
index a30f0edaec61..c88e9fc660f1 100644
--- a/flang/unittests/CMakeLists.txt
+++ b/flang/unittests/CMakeLists.txt
@@ -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()
diff --git a/flang/unittests/Frontend/CMakeLists.txt b/flang/unittests/Frontend/CMakeLists.txt
new file mode 100644
index 000000000000..dd5cbedb0f91
--- /dev/null
+++ b/flang/unittests/Frontend/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_flang_unittest(FlangFrontendTests
+ CompilerInstanceTest.cpp
+)
+
+target_link_libraries(FlangFrontendTests
+ PRIVATE
+ LLVMSupport
+ clangBasic
+ flangFrontend
+ flangFrontendTool)
diff --git a/flang/unittests/Frontend/CompilerInstanceTest.cpp b/flang/unittests/Frontend/CompilerInstanceTest.cpp
new file mode 100644
index 000000000000..a971c4c2b6c9
--- /dev/null
+++ b/flang/unittests/Frontend/CompilerInstanceTest.cpp
@@ -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
diff --git a/llvm/include/llvm/Option/OptTable.h b/llvm/include/llvm/Option/OptTable.h
index 1aabff0fd659..c0742ebc70ac 100644
--- a/llvm/include/llvm/Option/OptTable.h
+++ b/llvm/include/llvm/Option/OptTable.h
@@ -50,7 +50,7 @@ class OptTable {
unsigned ID;
unsigned char Kind;
unsigned char Param;
- unsigned short Flags;
+ unsigned int Flags;
unsigned short GroupID;
unsigned short AliasID;
const char *AliasArgs;
More information about the flang-commits
mailing list