[clang] 3e782ba - [flang][driver] Fix support for `-x`

Andrzej Warzynski via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 10 03:36:36 PDT 2022


Author: Andrzej Warzynski
Date: 2022-06-10T10:36:25Z
New Revision: 3e782ba21be4b88c761d3b0854df130d7ca08a56

URL: https://github.com/llvm/llvm-project/commit/3e782ba21be4b88c761d3b0854df130d7ca08a56
DIFF: https://github.com/llvm/llvm-project/commit/3e782ba21be4b88c761d3b0854df130d7ca08a56.diff

LOG: [flang][driver] Fix support for `-x`

Until now, `-x` wasn't really taken into account in Flang's compiler and
frontend drivers. `flang-new` and `flang-new -fc1` only recently gained
powers to consume inputs other than Fortran files and that's probably
why this hasn't been noticed yet.

This patch makes sure that `-x` is supported correctly and consistently
with Clang. To this end, verification is added when reading LLVM IR
files (i.e. IR modules are verified with `llvm::verifyModule`). This
way, LLVM IR parsing errors are correctly reported to Flang users. This
also aids testing.

With the new functionality, we can verify that `-x ir` breaks
compilation for e.g. Fortran files and vice-versa. Tests are updated
accordingly.

Differential Revision: https://reviews.llvm.org/D127207

Added: 
    flang/test/Driver/input-from-stdin-llvm.ll
    flang/test/Driver/parse-error.ll
    flang/test/Driver/parse-ir-error.f95

Modified: 
    clang/include/clang/Driver/Options.td
    clang/lib/Driver/ToolChains/Flang.cpp
    flang/lib/Frontend/CompilerInvocation.cpp
    flang/lib/Frontend/FrontendActions.cpp
    flang/test/Driver/input-from-stdin.f90
    flang/test/Driver/linker-flags.f90

Removed: 
    flang/test/Driver/parse-error.f95


################################################################################
diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6707714f170b3..95840760f7746 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4166,7 +4166,8 @@ def why_load : Flag<["-"], "why_load">;
 def whyload : Flag<["-"], "whyload">, Alias<why_load>;
 def w : Flag<["-"], "w">, HelpText<"Suppress all warnings">, Flags<[CC1Option]>,
   MarshallingInfoFlag<DiagnosticOpts<"IgnoreWarnings">>;
-def x : JoinedOrSeparate<["-"], "x">, Flags<[NoXarchOption,CC1Option]>,
+def x : JoinedOrSeparate<["-"], "x">,
+Flags<[NoXarchOption,CC1Option,FlangOption,FC1Option]>,
   HelpText<"Treat subsequent input files as having type <language>">,
   MetaVarName<"<language>">;
 def y : Joined<["-"], "y">;

diff  --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 63e3c080a7e7f..ab9287d880a95 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -19,6 +19,14 @@ using namespace clang::driver::tools;
 using namespace clang;
 using namespace llvm::opt;
 
+/// Add -x lang to \p CmdArgs for \p Input.
+static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
+                             ArgStringList &CmdArgs) {
+  CmdArgs.push_back("-x");
+  // Map the driver type to the frontend type.
+  CmdArgs.push_back(types::getTypeName(Input.getType()));
+}
+
 void Flang::AddFortranDialectOptions(const ArgList &Args,
                                      ArgStringList &CmdArgs) const {
   Args.AddAllArgs(
@@ -126,6 +134,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
   }
 
   assert(Input.isFilename() && "Invalid input.");
+
+  addDashXForInput(Args, Input, CmdArgs);
+
   CmdArgs.push_back(Input.getFilename());
 
   const auto& D = C.getDriver();

diff  --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 9ea4810d64950..cc376f3b7d851 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -263,7 +263,10 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
     llvm::StringRef xValue = a->getValue();
     // Principal languages.
     dashX = llvm::StringSwitch<InputKind>(xValue)
-                .Case("f90", Language::Fortran)
+                // Flang does not 
diff erentiate between pre-processed and not
+                // pre-processed inputs.
+                .Case("f95", Language::Fortran)
+                .Case("f95-cpp-input", Language::Fortran)
                 .Default(Language::Unknown);
 
     // Some special cases cannot be combined with suffixes.

diff  --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 334849ceeb54c..57b6203f94b2e 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -41,6 +41,7 @@
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Bitcode/BitcodeWriterPass.h"
 #include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Verifier.h"
 #include "llvm/IRReader/IRReader.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Passes/PassBuilder.h"
@@ -78,25 +79,36 @@ bool PrescanAndSemaDebugAction::beginSourceFileAction() {
 
 bool CodeGenAction::beginSourceFileAction() {
   llvmCtx = std::make_unique<llvm::LLVMContext>();
+  CompilerInstance &ci = this->getInstance();
 
   // If the input is an LLVM file, just parse it and return.
   if (this->getCurrentInput().getKind().getLanguage() == Language::LLVM_IR) {
     llvm::SMDiagnostic err;
     llvmModule = llvm::parseIRFile(getCurrentInput().getFile(), err, *llvmCtx);
+    if (!llvmModule || llvm::verifyModule(*llvmModule, &llvm::errs())) {
+      err.print("flang-new", llvm::errs());
+      unsigned diagID = ci.getDiagnostics().getCustomDiagID(
+          clang::DiagnosticsEngine::Error, "Could not parse IR");
+      ci.getDiagnostics().Report(diagID);
+      return false;
+    }
 
-    return (nullptr != llvmModule);
+    return true;
   }
 
   // Otherwise, generate an MLIR module from the input Fortran source
-  assert(getCurrentInput().getKind().getLanguage() == Language::Fortran &&
-         "Invalid input type - expecting a Fortran file");
+  if (getCurrentInput().getKind().getLanguage() != Language::Fortran) {
+    unsigned diagID = ci.getDiagnostics().getCustomDiagID(
+        clang::DiagnosticsEngine::Error,
+        "Invalid input type - expecting a Fortran file");
+    ci.getDiagnostics().Report(diagID);
+    return false;
+  }
   bool res = runPrescan() && runParse() && runSemanticChecks() &&
              generateRtTypeTables();
   if (!res)
     return res;
 
-  CompilerInstance &ci = this->getInstance();
-
   // Load the MLIR dialects required by Flang
   mlir::DialectRegistry registry;
   mlirCtx = std::make_unique<mlir::MLIRContext>(registry);

diff  --git a/flang/test/Driver/input-from-stdin-llvm.ll b/flang/test/Driver/input-from-stdin-llvm.ll
new file mode 100644
index 0000000000000..142c332af1e53
--- /dev/null
+++ b/flang/test/Driver/input-from-stdin-llvm.ll
@@ -0,0 +1,26 @@
+; Verify that reading from stdin works as expected - LLVM input
+
+;----------
+; RUN LINES
+;----------
+; Input type is implicit - assumed to be Fortran. As the input is provided via
+; stdin, the file extension is not relevant here.
+; RUN: cat %s | not %flang -S - -o -
+; RUN: cat %s | not %flang_fc1 -S - -o -
+
+; Input type is explicit
+; RUN: cat %s | %flang -x ir -S - -o - | FileCheck %s
+; RUN: cat %s | %flang_fc1 -x ir -S - -o - | FileCheck %s
+
+;----------------
+; EXPECTED OUTPUT
+;----------------
+; CHECK-LABEL: foo:
+; CHECK: ret
+
+;------
+; INPUT
+;------
+define void @foo() {
+  ret void
+}

diff  --git a/flang/test/Driver/input-from-stdin.f90 b/flang/test/Driver/input-from-stdin.f90
index f05318bdec4c1..58bf03b46f219 100644
--- a/flang/test/Driver/input-from-stdin.f90
+++ b/flang/test/Driver/input-from-stdin.f90
@@ -1,4 +1,4 @@
-! Verify that reading from stdin works as expected
+! Verify that reading from stdin works as expected - Fortran input
 
 !--------------------------
 ! FLANG DRIVER (flang)

diff  --git a/flang/test/Driver/linker-flags.f90 b/flang/test/Driver/linker-flags.f90
index 1210554927399..c46331f37029b 100644
--- a/flang/test/Driver/linker-flags.f90
+++ b/flang/test/Driver/linker-flags.f90
@@ -20,7 +20,7 @@
 !----------------
 ! Compiler invocation to generate the object file
 ! CHECK-LABEL: {{.*}} "-emit-obj"
-! CHECK-SAME:  "-o" "[[object_file:.*]]" {{.*}}Inputs/hello.f90
+! CHECK-SAME:  "-o" "[[object_file:.*\.o]]" {{.*}}Inputs/hello.f90
 
 ! Linker invocation to generate the executable
 ! CHECK-LABEL:  "/usr/bin/ld"

diff  --git a/flang/test/Driver/parse-error.f95 b/flang/test/Driver/parse-error.f95
deleted file mode 100644
index 3b9ad93ea5147..0000000000000
--- a/flang/test/Driver/parse-error.f95
+++ /dev/null
@@ -1,11 +0,0 @@
-! Verify that parsing errors are correctly reported by the driver
-! Focuses on actions inheriting from the following:
-! * PrescanAndSemaAction (-fsyntax-only)
-! * PrescanAndParseAction (-fdebug-unparse-no-sema)
-
-! RUN: not %flang_fc1 -fdebug-unparse-no-sema %s 2>&1 | FileCheck %s --check-prefix=ERROR
-! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=ERROR
-
-! ERROR: Could not parse {{.*}}parse-error.f95
-
-"This file will not parse"

diff  --git a/flang/test/Driver/parse-error.ll b/flang/test/Driver/parse-error.ll
new file mode 100644
index 0000000000000..374b218fc098f
--- /dev/null
+++ b/flang/test/Driver/parse-error.ll
@@ -0,0 +1,23 @@
+; This file is a valid LLVM IR file, but we force the driver to treat it as
+; Fortran (with the `-x` flag). This way we verify that the driver
+; correctly rejects invalid Fortran input.
+
+;----------
+; RUN LINES
+;----------
+; Input type is implicit (correctly assumed to be LLVM IR)
+; RUN: %flang_fc1 -S %s -o -
+
+; Input type is explicitly set as Fortran
+; Verify that parsing errors are correctly reported by the driver
+; Focuses on actions inheriting from the following:
+; * PrescanAndSemaAction (-fsyntax-only)
+; * PrescanAndParseAction (-fdebug-unparse-no-sema)
+; RUN: not %flang_fc1 -fdebug-unparse-no-sema -x f95 %s 2>&1 | FileCheck %s --check-prefix=ERROR
+; RUN: not %flang_fc1 -fsyntax-only %s -x f95 2>&1 | FileCheck %s --check-prefix=ERROR
+
+; ERROR: Could not parse {{.*}}parse-error.f95
+
+define void @foo() {
+  ret void
+}

diff  --git a/flang/test/Driver/parse-ir-error.f95 b/flang/test/Driver/parse-ir-error.f95
new file mode 100644
index 0000000000000..d10d71dc77542
--- /dev/null
+++ b/flang/test/Driver/parse-ir-error.f95
@@ -0,0 +1,18 @@
+! This file is a valid Fortran file, but we force the driver to treat it as an
+! LLVM file (with the `-x` flag). This way we verify that the driver correctly
+! rejects invalid LLVM IR input.
+
+!----------
+! RUN LINES
+!----------
+! Input type is implicit (correctly assumed to be Fortran)
+! RUN: %flang_fc1 -S %s
+! Input type is explicitly set as LLVM IR
+! RUN: not %flang -S -x ir %s 2>&1 | FileCheck %s
+
+!----------------
+! EXPECTED OUTPUT
+!----------------
+! CHECK: error: Could not parse IR
+
+end program


        


More information about the cfe-commits mailing list