[flang][driver] Make `flang-new -fc1` accept MLIR files
authorAndrzej Warzynski <andrzej.warzynski@arm.com>
Wed, 1 Jun 2022 16:00:31 +0000 (16:00 +0000)
committerAndrzej Warzynski <andrzej.warzynski@arm.com>
Fri, 10 Jun 2022 10:58:54 +0000 (10:58 +0000)
This relatively small change will allow Flang's frontend driver,
`flang-new -fc1`, to consume and parse MLIR files.  Semantically (i.e.
from user's perspective) this is identical to reading LLVM IR files.

Two file extensions are associated with MLIR files: .fir and .mlir. Note
that reading MLIR files makes only sense when running one of the
code-generation actions, i.e. when using one of the following action
flags: -S, -emit-obj, -emit-llvm, -emit-llvm-bc.

The majority of tests that required `tco` to run are updated to also run
with `flang-new -fc1`. A few tests are updated to use `fir-opt` instead
of `tco` (that's the preferred choice when testing a particular MLIR
pass). basic-program.fir is not updated as that test is intended to
verify the behaviour of `tco` specifically.

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

22 files changed:
flang/include/flang/Frontend/FrontendOptions.h
flang/lib/Frontend/CompilerInvocation.cpp
flang/lib/Frontend/FrontendActions.cpp
flang/lib/Frontend/FrontendOptions.cpp
flang/test/Driver/emit-asm-from-mlir.mlir [new file with mode: 0644]
flang/test/Driver/parse-fir-error.ll [new file with mode: 0644]
flang/test/Fir/addrof.fir
flang/test/Fir/alloc.fir
flang/test/Fir/arrayset.fir
flang/test/Fir/boxchar.fir
flang/test/Fir/embox.fir
flang/test/Fir/global.fir
flang/test/Fir/ignore-missing-type-descriptor.fir
flang/test/Fir/inline.fir
flang/test/Fir/optional.fir
flang/test/Fir/peephole.fir
flang/test/Fir/rebox.fir
flang/test/Fir/select.fir
flang/test/Fir/widechar.fir
flang/test/Lower/common-block.f90
flang/test/Lower/complex-part.f90
flang/test/Lower/forall/character-1.f90

index c8f74e31de432f68ca75f901a32e4770b40a1146..3be87b6f5218da39a59f0adc3234cff0fa09b85e 100644 (file)
@@ -115,12 +115,17 @@ bool isToBePreprocessed(llvm::StringRef suffix);
 enum class Language : uint8_t {
   Unknown,
 
+  /// MLIR: we accept this so that we can run the optimizer on it, and compile
+  /// it to LLVM IR, assembly or object code.
+  MLIR,
+
   /// 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,
+  /// @}
 };
 
 // Source file layout
index cc376f3b7d851c83b8fb0a3308b12d9210dbe85d..8f2167b14f0e629d42e700f52691c0d418ab28bb 100644 (file)
@@ -269,10 +269,12 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
                 .Case("f95-cpp-input", Language::Fortran)
                 .Default(Language::Unknown);
 
-    // Some special cases cannot be combined with suffixes.
+    // Flang's intermediate representations.
     if (dashX.isUnknown())
       dashX = llvm::StringSwitch<InputKind>(xValue)
                   .Case("ir", Language::LLVM_IR)
+                  .Case("fir", Language::MLIR)
+                  .Case("mlir", Language::MLIR)
                   .Default(Language::Unknown);
 
     if (dashX.isUnknown())
index 57b6203f94b2e915b06b032adb731ee9f0f43eee..a842420be887a2bbc5b9e30f83be500f999990e2 100644 (file)
@@ -32,6 +32,7 @@
 #include "flang/Semantics/unparse-with-symbols.h"
 
 #include "mlir/IR/Dialect.h"
+#include "mlir/Parser/Parser.h"
 #include "mlir/Pass/PassManager.h"
 #include "mlir/Target/LLVMIR/ModuleTranslation.h"
 #include "clang/Basic/Diagnostic.h"
@@ -96,6 +97,34 @@ bool CodeGenAction::beginSourceFileAction() {
     return true;
   }
 
+  // Load the MLIR dialects required by Flang
+  mlir::DialectRegistry registry;
+  mlirCtx = std::make_unique<mlir::MLIRContext>(registry);
+  fir::support::registerNonCodegenDialects(registry);
+  fir::support::loadNonCodegenDialects(*mlirCtx);
+  fir::support::loadDialects(*mlirCtx);
+  fir::support::registerLLVMTranslation(*mlirCtx);
+
+  // If the input is an MLIR file, just parse it and return.
+  if (this->getCurrentInput().getKind().getLanguage() == Language::MLIR) {
+    llvm::SourceMgr sourceMgr;
+    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =
+        llvm::MemoryBuffer::getFileOrSTDIN(getCurrentInput().getFile());
+    sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), llvm::SMLoc());
+    mlir::OwningOpRef<mlir::ModuleOp> module =
+        mlir::parseSourceFile<mlir::ModuleOp>(sourceMgr, mlirCtx.get());
+
+    if (!module || mlir::failed(module->verifyInvariants())) {
+      unsigned diagID = ci.getDiagnostics().getCustomDiagID(
+          clang::DiagnosticsEngine::Error, "Could not parse FIR");
+      ci.getDiagnostics().Report(diagID);
+      return false;
+    }
+
+    mlirModule = std::make_unique<mlir::ModuleOp>(module.release());
+    return true;
+  }
+
   // Otherwise, generate an MLIR module from the input Fortran source
   if (getCurrentInput().getKind().getLanguage() != Language::Fortran) {
     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
@@ -109,12 +138,6 @@ bool CodeGenAction::beginSourceFileAction() {
   if (!res)
     return res;
 
-  // Load the MLIR dialects required by Flang
-  mlir::DialectRegistry registry;
-  mlirCtx = std::make_unique<mlir::MLIRContext>(registry);
-  fir::support::registerNonCodegenDialects(registry);
-  fir::support::loadNonCodegenDialects(*mlirCtx);
-
   // Create a LoweringBridge
   const common::IntrinsicTypeDefaultKinds &defKinds =
       ci.getInvocation().getSemanticsContext().defaultKinds();
index 574e007278327f2f974b423541ef3a66ca17ca0c..8353858ff509455ff27ae1f5fc46fd3e052b8455 100644 (file)
@@ -42,6 +42,8 @@ InputKind FrontendOptions::getInputKindForExtension(llvm::StringRef extension) {
 
   if (extension == "bc" || extension == "ll")
     return Language::LLVM_IR;
+  if (extension == "fir" || extension == "mlir")
+    return Language::MLIR;
 
   return Language::Unknown;
 }
diff --git a/flang/test/Driver/emit-asm-from-mlir.mlir b/flang/test/Driver/emit-asm-from-mlir.mlir
new file mode 100644 (file)
index 0000000..d0dbd7b
--- /dev/null
@@ -0,0 +1,19 @@
+; Verify that the driver can consume MLIR/FIR files.
+
+;-------------
+; RUN COMMANDS
+;-------------
+; RUN: %flang_fc1 -S %s -o - | FileCheck %s
+
+;----------------
+; EXPECTED OUTPUT
+;----------------
+; CHECK-LABEL: foo:
+; CHECK: ret
+
+;------
+; INPUT
+;------
+func.func @foo() {
+  return
+}
diff --git a/flang/test/Driver/parse-fir-error.ll b/flang/test/Driver/parse-fir-error.ll
new file mode 100644 (file)
index 0000000..e2ac479
--- /dev/null
@@ -0,0 +1,21 @@
+; This file is a valid LLVM IR file, but we force the driver to treat it as
+; FIR (with the `-x` flag). This way we verify that the driver
+; correctly rejects invalid FIR 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 FIR
+; Verify that parsing errors are correctly reported by the driver
+; RUN: not %flang_fc1 -S -x fir %s 2>&1 | FileCheck %s --check-prefix=ERROR
+; RUN: not %flang_fc1 -S %s -x mlir 2>&1 | FileCheck %s --check-prefix=ERROR
+
+; ERROR: error: unexpected character
+; ERROR: error: Could not parse FIR
+
+define void @foo() {
+  ret void
+}
index 059a43778e5359b5287fd3754b3708895f5dbd69..bc80a6bfca86db9447700e22e5b632a9076f9b78 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
 
 // CHECK: @var_x = external global i32
 fir.global @var_x : !fir.int<4> {}
index dd4efae9968c671294526665a7f6dff3251849fc..d3dddf70433ceeba81a5c7c99a0d43f308228be6 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm  %s -o - | FileCheck %s
 
 // UNSUPPORTED: system-windows
 
index 248fc9420889cb736e8e8efa630d169abaf8547c..a9630c815fc42482766e398286d087c29f00aacc 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
 
 // CHECK-LABEL: define void @x(ptr %0)
 func.func @x(%arr : !fir.ref<!fir.array<10xf32>>) {
index ee20424b001fda6886af1dd5a7f66dc7fb47aeed..06d66202ff894a3312bcc5c388d4fe98bae104ca 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco --target=x86_64-unknown-linux-gnu %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm -triple x86_64-unknown-linux-gnu %s -o - | FileCheck %s
 
 // Test of building and passing boxchar.
 
index 68e59f7055dfc353e0e0f5cd8ed9522ed8309084..aec11dd19ddf79a028d7dcf4968ae9dc7e8b90a4 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -mmlir -disable-external-name-interop  -emit-llvm %s -o -| FileCheck %s
 
 
 // CHECK-LABEL: define void @_QPtest_callee(ptr %0)
index a29c1da4974af80340e47a7f67bc3360284b60bf..598fcb3da60c9b3fec15fe1cede9e4d2a33b420d 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm  %s -o - | FileCheck %s
 
 // CHECK: @g_i0 = global i32 0
 fir.global @g_i0 : i32 {
index 50e11bc6955ddb4b1ba49693ea22238034a827dd..14b210f5a0de7b81411dd23baee5c49e0e57915b 100644 (file)
@@ -3,6 +3,7 @@
 // having to care with providing an ABI compliant derived type descriptor object.
 // Missing derived type descriptor pointers are replaced by null pointers.
 // RUN: tco --ignore-missing-type-desc -o - %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm  -mmlir --ignore-missing-type-desc -o - %s | FileCheck %s
 
 !some_freestyle_type = !fir.type<some_not_mangled_type{j:i32}>
 
index 67e37234be68a8ad42bd0ca3a628e17373c88fe4..48f10c1e851983d8989eaf560d5b1a92c14b28de 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco --target=x86_64-unknown-linux-gnu --inline-all %s -o - | FileCheck %s
+// RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -mmlir --inline-all -emit-llvm %s -o - | FileCheck %s
 
 // CHECK-LABEL: @add
 func.func @add(%a : i32, %b : i32) -> i32 {
index 19653aae06ac21898e228ab05cc21b6052cf54e2..644a7ef8d2198a42250d9e534804e4ffb4d6ecb5 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
 
 // Test fir.is_present and fir.absent codegen
 
index a19519a7c8f6fea487588606c9fe5173590465fa..28fe33c93e7d25d658221b1713931e54d209a149 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
 
 // Test peephole optimizations
 
index b018ec4f4a48d2ceb40160c5dc5424b2621dc9e1..5cdf2cd1b4be7e58121632282319c029c51e3aaa 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
 
 // Test applying slice on fir.box
 //   subroutine foo(x)
index 5b15e205117bfd4c128dc7ce6d64abfafc6bbeae..47cc5e4122076b3b22872a9a1b059ebe231ce250 100644 (file)
@@ -1,6 +1,7 @@
 // Test lowering FIR to LLVM IR of fir.select{|_rank|_case}
 
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
 
 // CHECK-LABEL: @f
 func.func @f(%a : i32) -> i32 {
index 251b77d5dc6800d6a8ba4be235aa86f0b907c76e..c0f8d09789790c458e55fcf3cdc4464fe6bd15c3 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
 
 // CHECK-LABEL: @character_literal1
 func.func @character_literal1() -> !fir.char<1,13> {
index 8ea9daf2bf3c6f9b640b41c0a159f01ee4198a7b..d569adb79dba4a1dd781b4bbac45a3b810436a09 100644 (file)
@@ -1,4 +1,5 @@
 ! RUN: bbc %s -o - | tco | FileCheck %s
+! RUN: %flang -emit-llvm -S -mmlir -disable-external-name-interop %s -o - | FileCheck %s
 
 ! CHECK: @_QB = common global [8 x i8] zeroinitializer
 ! CHECK: @_QBrien = common global [1 x i8] zeroinitializer
index 28051485834de3d455cc0cbe55d58cdb0064c2f9..896f17d91f171182f044f6175f5399f30ea6ee94 100644 (file)
@@ -1,4 +1,5 @@
 ! RUN: bbc %s -o - | tco | FileCheck %s
+! RUN: %flang -emit-llvm -S -mmlir -disable-external-name-interop %s -o - | FileCheck %s
 
   COMPLEX c
   c%RE = 3.14
index 3ba2bdd5efca3e0e09004a3d93bdb3f527c72171..92f215b23a8896650c12d4e0b1664d1a1cfc0a25 100644 (file)
@@ -1,4 +1,5 @@
 ! RUN: bbc %s -o - | tco | FileCheck %s
+! RUN: %flang -emit-llvm -S -mmlir -disable-external-name-interop %s -o - | FileCheck %s
 ! Test from Fortran source through to LLVM IR.
 ! UNSUPPORTED: system-windows
 
@@ -23,7 +24,7 @@ end program test
 ! CHECK: %[[elesize:.*]] = getelementptr { {{.*}}, [1 x [3 x i64]] }, ptr %[[arg]], i32 0, i32 1
 ! CHECK: %[[esval:.*]] = load i64, ptr %[[elesize]]
 ! CHECK: %[[mul:.*]] = mul i64 1, %[[esval]]
-! CHECK: %[[mul2:.*]] = mul i64 %[[mul]], %[[extval]], !dbg !17
+! CHECK: %[[mul2:.*]] = mul i64 %[[mul]], %[[extval]]
 ! CHECK: %[[buff:.*]] = call ptr @malloc(i64 %[[mul2]])
 ! CHECK: %[[to:.*]] = getelementptr i8, ptr %[[buff]], i64 %
 ! CHECK: call void @llvm.memmove.p0.p0.i64(ptr %[[to]], ptr %{{.*}}, i64 %{{.*}}, i1 false)