[flang][driver] Make `flang-new -fc1` accept MLIR files

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
This commit is contained in:
Andrzej Warzynski 2022-06-01 16:00:31 +00:00
parent d50d9946d1
commit cc3c6b6109
22 changed files with 96 additions and 8 deletions

View 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

View 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())

View 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();

View 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;
}

View File

@ -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
}

View File

@ -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
}

View 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> {}

View File

@ -1,4 +1,5 @@
// RUN: tco %s | FileCheck %s
// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
// UNSUPPORTED: system-windows

View 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>>) {

View 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.

View 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)

View 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 {

View 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}>

View 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 {

View 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

View File

@ -1,4 +1,5 @@
// RUN: tco %s | FileCheck %s
// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
// Test peephole optimizations

View 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)

View 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 {

View 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> {

View 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

View 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

View 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)