[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 c8f74e3..3be87b6 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 cc376f3..8f2167b 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 57b6203..a842420 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 574e007..8353858 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 059a437..bc80a6b 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 dd4efae..d3dddf7 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm  %s -o - | FileCheck %s
 
 // UNSUPPORTED: system-windows
 
index 248fc94..a9630c8 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 ee20424..06d6620 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 68e59f7..aec11dd 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 a29c1da..598fcb3 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 50e11bc..14b210f 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 67e3723..48f10c1 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 19653aa..644a7ef 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 a19519a..28fe33c 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: tco %s | FileCheck %s
+// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
 
 // Test peephole optimizations
 
index b018ec4..5cdf2cd 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 5b15e20..47cc5e4 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 251b77d..c0f8d09 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 8ea9daf..d569adb 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 2805148..896f17d 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 3ba2bdd..92f215b 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)