peterwaller-arm updated this revision to Diff 219538. peterwaller-arm retitled this revision from "[clang][driver] Prototype --driver-mode=fortran support for new flang" to "[clang][driver] Add basic --driver-mode=fortran support for flang". peterwaller-arm added a comment.
I updated this "prototype" revision into the real thing I would like to submit. Please let me know if that was the wrong thing to do and I will resubmit it. This is an initial implementation which naturally doesn't implement very much. More will come in future patches. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D63607/new/ https://reviews.llvm.org/D63607 Files: clang/include/clang/Driver/Driver.h clang/include/clang/Driver/ToolChain.h clang/include/clang/Driver/Types.h clang/lib/Driver/CMakeLists.txt clang/lib/Driver/Driver.cpp clang/lib/Driver/ToolChain.cpp clang/lib/Driver/ToolChains/Flang.cpp clang/lib/Driver/ToolChains/Flang.h clang/lib/Driver/Types.cpp clang/test/Driver/flang/flang.F90 clang/test/Driver/flang/flang.f90 clang/test/Driver/fortran.f95 clang/test/Driver/lit.local.cfg
Index: clang/test/Driver/lit.local.cfg =================================================================== --- clang/test/Driver/lit.local.cfg +++ clang/test/Driver/lit.local.cfg @@ -1,4 +1,4 @@ -config.suffixes = ['.c', '.cpp', '.h', '.m', '.mm', '.S', '.s', '.f90', '.f95', +config.suffixes = ['.c', '.cpp', '.h', '.m', '.mm', '.S', '.s', '.f90', '.F90', '.f95', '.cu', '.rs', '.cl', '.hip'] config.substitutions = list(config.substitutions) config.substitutions.insert(0, Index: clang/test/Driver/fortran.f95 =================================================================== --- clang/test/Driver/fortran.f95 +++ clang/test/Driver/fortran.f95 @@ -1,21 +1,21 @@ -// Check that the clang driver can invoke gcc to compile Fortran. +! Check that the clang driver can invoke gcc to compile Fortran. -// RUN: %clang -target x86_64-unknown-linux-gnu -integrated-as -c %s -### 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-OBJECT %s -// CHECK-OBJECT: gcc -// CHECK-OBJECT: "-c" -// CHECK-OBJECT: "-x" "f95" -// CHECK-OBJECT-NOT: cc1as +! RUN: %clang -target x86_64-unknown-linux-gnu -integrated-as -c %s -### 2>&1 \ +! RUN: | FileCheck --check-prefix=CHECK-OBJECT %s +! CHECK-OBJECT: gcc +! CHECK-OBJECT: "-c" +! CHECK-OBJECT: "-x" "f95" +! CHECK-OBJECT-NOT: cc1as -// RUN: %clang -target x86_64-unknown-linux-gnu -integrated-as -S %s -### 2>&1 \ -// RUN: | FileCheck --check-prefix=CHECK-ASM %s -// CHECK-ASM: gcc -// CHECK-ASM: "-S" -// CHECK-ASM: "-x" "f95" -// CHECK-ASM-NOT: cc1 +! RUN: %clang -target x86_64-unknown-linux-gnu -integrated-as -S %s -### 2>&1 \ +! RUN: | FileCheck --check-prefix=CHECK-ASM %s +! CHECK-ASM: gcc +! CHECK-ASM: "-S" +! CHECK-ASM: "-x" "f95" +! CHECK-ASM-NOT: cc1 -// RUN: %clang -Wall -target x86_64-unknown-linux-gnu -integrated-as %s -o %t -### 2>&1 | FileCheck --check-prefix=CHECK-WARN %s -// CHECK-WARN: gcc -// CHECK-WARN-NOT: "-Wall" -// CHECK-WARN: ld -// CHECK-WARN-NOT: "-Wall" +! RUN: %clang -Wall -target x86_64-unknown-linux-gnu -integrated-as %s -o %t -### 2>&1 | FileCheck --check-prefix=CHECK-WARN %s +! CHECK-WARN: gcc +! CHECK-WARN-NOT: "-Wall" +! CHECK-WARN: ld +! CHECK-WARN-NOT: "-Wall" Index: clang/test/Driver/flang/flang.f90 =================================================================== --- /dev/null +++ clang/test/Driver/flang/flang.f90 @@ -0,0 +1,56 @@ +! Check that flang -fc1 is invoked when in --driver-mode=fortran. + +! See also: flang.F90 - "an input which also requires preprocessing". + +! Test various output types: +! * The default (-emit-obj) +! * -fsyntax-only +! * -emit-llvm +! * -emit-llvm -S +! * -S + +! Most tests use ALL-LABEL to bracket the checks with the compiler invocation and the source, which appear at the beginning and end. +! Use of "...-DAG" allows the order of options to change within that bracket. + + +! All invocations should begin with flang -fc1, consume up to here. +! ALL-LABEL: "{{[^"]*}}flang" "-fc1" + +! RUN: %clang --driver-mode=fortran -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-PLAIN %s +! CHECK-PLAIN-DAG: "-triple" +! CHECK-PLAIN-DAG: "-emit-obj" +! CHECK-PLAIN-DAG: "-o" "{{[^"]*}}.o" + +! RUN: %clang --driver-mode=fortran -emit-ast -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-AST %s +! CHECK-EMIT-AST-DAG: "-triple" +! CHECK-EMIT-AST-DAG: "-emit-ast" +! CHECK-EMIT-AST-DAG: "-o" "{{[^"]*}}.ast" + +! RUN: %clang --driver-mode=fortran -fsyntax-only -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-SYNTAX-ONLY %s +! CHECK-SYNTAX-ONLY-NOT: "-o" +! CHECK-SYNTAX-ONLY-DAG: "-fsyntax-only" + +! RUN: %clang --driver-mode=fortran -emit-llvm -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-LLVM %s +! CHECK-EMIT-LLVM-NOT: "-emit-llvm" +! CHECK-EMIT-LLVM-DAG: "-emit-llvm-uselists" +! CHECK-EMIT-LLVM-DAG: "-emit-llvm-bc" +! CHECK-EMIT-LLVM-DAG: "-o" "{{[^"]*}}.bc" + +! RUN: %clang --driver-mode=fortran -emit-llvm -S -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-LLVM-S %s +! CHECK-EMIT-LLVM-S-DAG: "-emit-llvm" +! CHECK-EMIT-LLVM-S-DAG: "-o" "{{[^"]*}}.ll" + +! RUN: %clang --driver-mode=fortran -S -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-S %s +! CHECK-S-NOT: "-emit-llvm" +! CHECK-S-NOT: "-emit-llvm-bc" +! CHECK-S-DAG: "-S" +! CHECK-S-DAG: "-o" "{{[^"]*}}.s" + + +! Should end in the input file. +! ALL-LABEL: "{{.*}}flang.f90"{{$}} + +! NOTE: This one does not use ALL because it does not invoke the frontend, only emit a warning. + +! RUN: %clang --driver-mode=fortran -E -### %s 2>&1 | FileCheck --check-prefixes=CHECK-E %s +! CHECK-E-DAG: previously preprocessed input \ No newline at end of file Index: clang/test/Driver/flang/flang.F90 =================================================================== --- /dev/null +++ clang/test/Driver/flang/flang.F90 @@ -0,0 +1,46 @@ +! Check that flang -fc1 is invoked when in --driver-mode=fortran. + +! See also: flang.f90 - "an input which has already been preprocessed". + +! Test various output types: +! * Behaviour of the C preprocessor. + +! All invocations should begin with flang -fc1, consume up to here. +! ALL-LABEL: "{{[^"]*}}flang" "-fc1" + +! RUN: %clang --driver-mode=fortran -E -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-E %s +! CHECK-E-DAG: "-E" +! CHECK-E-DAG: "-o" "-" + +! RUN: %clang --driver-mode=fortran -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-PLAIN %s +! CHECK-PLAIN-DAG: "-triple" +! CHECK-PLAIN-DAG: "-emit-obj" +! CHECK-PLAIN-DAG: "-o" "{{[^"]*}}.o" + +! RUN: %clang --driver-mode=fortran -emit-ast -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-AST %s +! CHECK-EMIT-AST-DAG: "-triple" +! CHECK-EMIT-AST-DAG: "-emit-ast" +! CHECK-EMIT-AST-DAG: "-o" "{{[^"]*}}.ast" + +! RUN: %clang --driver-mode=fortran -fsyntax-only -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-SYNTAX-ONLY %s +! CHECK-SYNTAX-ONLY-NOT: "-o" +! CHECK-SYNTAX-ONLY-DAG: "-fsyntax-only" + +! RUN: %clang --driver-mode=fortran -emit-llvm -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-LLVM %s +! CHECK-EMIT-LLVM-NOT: "-emit-llvm" +! CHECK-EMIT-LLVM-DAG: "-emit-llvm-uselists" +! CHECK-EMIT-LLVM-DAG: "-emit-llvm-bc" +! CHECK-EMIT-LLVM-DAG: "-o" "{{[^"]*}}.bc" + +! RUN: %clang --driver-mode=fortran -emit-llvm -S -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-LLVM-S %s +! CHECK-EMIT-LLVM-S-DAG: "-emit-llvm" +! CHECK-EMIT-LLVM-S-DAG: "-o" "{{[^"]*}}.ll" + +! RUN: %clang --driver-mode=fortran -S -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-S %s +! CHECK-S-NOT: "-emit-llvm" +! CHECK-S-NOT: "-emit-llvm-bc" +! CHECK-S-DAG: "-S" +! CHECK-S-DAG: "-o" "{{[^"]*}}.s" + +! Should end in the input file. +! ALL: "{{.*}}flang.F90"{{$}} Index: clang/lib/Driver/Types.cpp =================================================================== --- clang/lib/Driver/Types.cpp +++ clang/lib/Driver/Types.cpp @@ -212,6 +212,16 @@ } } +bool types::isFortran(ID Id) { + switch (Id) { + default: + return false; + + case TY_Fortran: case TY_PP_Fortran: + return true; + } +} + bool types::isSrcFile(ID Id) { return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID; } Index: clang/lib/Driver/ToolChains/Flang.h =================================================================== --- /dev/null +++ clang/lib/Driver/ToolChains/Flang.h @@ -0,0 +1,46 @@ +//===--- Flang.h - Flang Tool and ToolChain Implementations ====-*- 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_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace driver { + +namespace tools { + +/// Flang compiler tool. +class LLVM_LIBRARY_VISIBILITY Flang : public Tool { +public: + Flang(const ToolChain &TC); + ~Flang() override; + + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedAssembler() const override { return true; } + bool hasIntegratedCPP() const override { return true; } + bool canEmitIR() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // end namespace tools + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H Index: clang/lib/Driver/ToolChains/Flang.cpp =================================================================== --- /dev/null +++ clang/lib/Driver/ToolChains/Flang.cpp @@ -0,0 +1,88 @@ +//===-- Flang.cpp - Flang+LLVM ToolChain Implementations --------*- 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 +// +//===----------------------------------------------------------------------===// + + +#include "Flang.h" +#include "CommonArgs.h" + +#include "clang/Driver/Options.h" + +#include <cassert> + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +void Flang::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const ArgList &Args, const char *LinkingOutput) const { + const auto &TC = getToolChain(); + const llvm::Triple &Triple = TC.getEffectiveTriple(); + const std::string &TripleStr = Triple.getTriple(); + + ArgStringList CmdArgs; + + CmdArgs.push_back("-fc1"); + + CmdArgs.push_back("-triple"); + CmdArgs.push_back(Args.MakeArgString(TripleStr)); + + if (isa<AssembleJobAction>(JA)) { + CmdArgs.push_back("-emit-obj"); + } else if (isa<PreprocessJobAction>(JA)) { + CmdArgs.push_back("-E"); + } else { + assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && + "Invalid action for flang tool."); + if (JA.getType() == types::TY_Nothing) { + CmdArgs.push_back("-fsyntax-only"); + } else if (JA.getType() == types::TY_LLVM_IR || + JA.getType() == types::TY_LTO_IR) { + CmdArgs.push_back("-emit-llvm"); + } else if (JA.getType() == types::TY_LLVM_BC || + JA.getType() == types::TY_LTO_BC) { + CmdArgs.push_back("-emit-llvm-bc"); + // Preserve use-list order by default when emitting bitcode, so that + // loading the bitcode up in 'opt' or 'llc' and running passes gives the + // same result as running passes here. For LTO, we don't need to preserve + // the use-list order, since serialization to bitcode is part of the flow. + if (JA.getType() == types::TY_LLVM_BC) + CmdArgs.push_back("-emit-llvm-uselists"); + } else if (JA.getType() == types::TY_PP_Asm) { + CmdArgs.push_back("-S"); + } else if (JA.getType() == types::TY_AST) { + CmdArgs.push_back("-emit-ast"); + } else { + assert(false && "Unexpected output type!"); + } + } + + Args.AddAllArgs(CmdArgs, options::OPT_R_Group); // "Rpass-"" options passthrough. + Args.AddAllArgs(CmdArgs, options::OPT_gfortran_Group); // gfortran options passthrough. + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Input output."); + } + + const InputInfo &Input = Inputs[0]; + assert(Input.isFilename() && "Invalid input."); + CmdArgs.push_back(Input.getFilename()); + + const auto& D = C.getDriver(); + const char* Exec = Args.MakeArgString(D.GetProgramPath("flang", TC)); + C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +Flang::Flang(const ToolChain &TC) + : Tool("flang", "flang frontend", TC, RF_Full) {} + +Flang::~Flang() {} Index: clang/lib/Driver/ToolChain.cpp =================================================================== --- clang/lib/Driver/ToolChain.cpp +++ clang/lib/Driver/ToolChain.cpp @@ -10,6 +10,7 @@ #include "InputInfo.h" #include "ToolChains/Arch/ARM.h" #include "ToolChains/Clang.h" +#include "ToolChains/Flang.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Sanitizers.h" #include "clang/Config/config.h" @@ -150,6 +151,7 @@ {"cpp", "--driver-mode=cpp"}, {"cl", "--driver-mode=cl"}, {"++", "--driver-mode=g++"}, + {"flang", "--driver-mode=fortran"}, }; for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) { @@ -253,6 +255,12 @@ return Clang.get(); } +Tool *ToolChain::getFlang() const { + if (!Flang) + Flang.reset(new tools::Flang(*this)); + return Flang.get(); +} + Tool *ToolChain::buildAssembler() const { return new tools::ClangAs(*this); } @@ -309,6 +317,9 @@ case Action::MigrateJobClass: case Action::VerifyPCHJobClass: case Action::BackendJobClass: + if (D.IsFortranMode()) { + return getFlang(); + } return getClang(); case Action::OffloadBundlingJobClass: @@ -474,6 +485,7 @@ } Tool *ToolChain::SelectTool(const JobAction &JA) const { + if (D.IsFortranMode() && getDriver().ShouldUseFlangCompiler(JA)) return getFlang(); if (getDriver().ShouldUseClangCompiler(JA)) return getClang(); Action::ActionClass AC = JA.getKind(); if (AC == Action::AssembleJobClass && useIntegratedAs()) Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -177,6 +177,7 @@ .Case("g++", GXXMode) .Case("cpp", CPPMode) .Case("cl", CLMode) + .Case("fortran", FortranMode) .Default(None)) Mode = *M; else @@ -4783,6 +4784,19 @@ return true; } +bool Driver::ShouldUseFlangCompiler(const JobAction &JA) const { + // Say "no" if there is not exactly one input of a type flang understands. + if (JA.size() != 1 || + !types::isFortran((*JA.input_begin())->getType())) + return false; + + // And say "no" if this is not a kind of action flang understands. + if (!isa<PreprocessJobAction>(JA) && !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA)) + return false; + + return true; +} + /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the /// grouped values as integers. Numbers which are not provided are set to 0. /// Index: clang/lib/Driver/CMakeLists.txt =================================================================== --- clang/lib/Driver/CMakeLists.txt +++ clang/lib/Driver/CMakeLists.txt @@ -42,6 +42,7 @@ ToolChains/Cuda.cpp ToolChains/Darwin.cpp ToolChains/DragonFly.cpp + ToolChains/Flang.cpp ToolChains/FreeBSD.cpp ToolChains/Fuchsia.cpp ToolChains/Gnu.cpp Index: clang/include/clang/Driver/Types.h =================================================================== --- clang/include/clang/Driver/Types.h +++ clang/include/clang/Driver/Types.h @@ -84,6 +84,9 @@ /// isObjC - Is this an "ObjC" input (Obj-C and Obj-C++ sources and headers). bool isObjC(ID Id); + /// isFortran - Is this a Fortran input. + bool isFortran(ID Id); + /// isSrcFile - Is this a source file, i.e. something that still has to be /// preprocessed. The logic behind this is the same that decides if the first /// compilation phase is a preprocessing one. Index: clang/include/clang/Driver/ToolChain.h =================================================================== --- clang/include/clang/Driver/ToolChain.h +++ clang/include/clang/Driver/ToolChain.h @@ -134,11 +134,13 @@ path_list ProgramPaths; mutable std::unique_ptr<Tool> Clang; + mutable std::unique_ptr<Tool> Flang; mutable std::unique_ptr<Tool> Assemble; mutable std::unique_ptr<Tool> Link; mutable std::unique_ptr<Tool> OffloadBundler; Tool *getClang() const; + Tool *getFlang() const; Tool *getAssemble() const; Tool *getLink() const; Tool *getClangAs() const; Index: clang/include/clang/Driver/Driver.h =================================================================== --- clang/include/clang/Driver/Driver.h +++ clang/include/clang/Driver/Driver.h @@ -22,6 +22,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/StringSaver.h" +#include "llvm/Support/Path.h" #include <list> #include <map> @@ -65,7 +66,8 @@ GCCMode, GXXMode, CPPMode, - CLMode + CLMode, + FortranMode, } Mode; enum SaveTempsMode { @@ -180,6 +182,9 @@ /// Whether the driver should follow cl.exe like behavior. bool IsCLMode() const { return Mode == CLMode; } + /// Whether the driver should follow gfortran like behavior. + bool IsFortranMode() const { return Mode == FortranMode; } + /// Only print tool bindings, don't build any jobs. unsigned CCCPrintBindings : 1; @@ -534,6 +539,10 @@ /// handle this action. bool ShouldUseClangCompiler(const JobAction &JA) const; + /// ShouldUseFlangCompiler - Should the flang compiler be used to + /// handle this action. + bool ShouldUseFlangCompiler(const JobAction &JA) const; + /// Returns true if we are performing any kind of LTO. bool isUsingLTO() const { return LTOMode != LTOK_None; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits