forked from OSchip/llvm-project
[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:
parent
d50d9946d1
commit
cc3c6b6109
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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> {}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// RUN: tco %s | FileCheck %s
|
||||
// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
// UNSUPPORTED: system-windows
|
||||
|
||||
|
|
|
@ -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>>) {
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}>
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// RUN: tco %s | FileCheck %s
|
||||
// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
// Test peephole optimizations
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue