Skip to content

[flang][driver] Separate the actions of the -emit-fir and -emit-mlir options #139857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -7193,7 +7193,8 @@ defm analyzed_objects_for_unparse : OptOutFC1FFlag<"analyzed-objects-for-unparse

def emit_fir : Flag<["-"], "emit-fir">, Group<Action_Group>,
HelpText<"Build the parse tree, then lower it to FIR">;
def emit_mlir : Flag<["-"], "emit-mlir">, Alias<emit_fir>;
def emit_mlir : Flag<["-"], "emit-mlir">, Group<Action_Group>,
HelpText<"Build the parse tree, then lower it to core MLIR">;

def emit_hlfir : Flag<["-"], "emit-hlfir">, Group<Action_Group>,
HelpText<"Build the parse tree, then lower it to HLFIR">;
Expand Down
11 changes: 11 additions & 0 deletions flang/include/flang/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ enum class BackendActionTy {
Backend_EmitBC, ///< Emit LLVM bitcode files
Backend_EmitLL, ///< Emit human-readable LLVM assembly
Backend_EmitFIR, ///< Emit FIR files, possibly lowering via HLFIR
Backend_EmitMLIR, ///< Emit MLIR files, possibly lowering via FIR
Backend_EmitHLFIR, ///< Emit HLFIR files before any passes run
};

Expand Down Expand Up @@ -216,6 +217,11 @@ class CodeGenAction : public FrontendAction {
/// Runs pass pipeline to lower HLFIR into FIR
void lowerHLFIRToFIR();

/// Runs pass pipeline to lower FIR into core MLIR
/// TODO: Some operations currently do not have corresponding representations
/// in the core MLIR dialects, so we lower them directly to the LLVM dialect.
void lowerFIRToMLIR();

/// Generates an LLVM IR module from CodeGenAction::mlirModule and saves it
/// in CodeGenAction::llvmModule.
void generateLLVMIR();
Expand All @@ -232,6 +238,11 @@ class EmitFIRAction : public CodeGenAction {
EmitFIRAction() : CodeGenAction(BackendActionTy::Backend_EmitFIR) {}
};

class EmitMLIRAction : public CodeGenAction {
public:
EmitMLIRAction() : CodeGenAction(BackendActionTy::Backend_EmitMLIR) {}
};

class EmitHLFIRAction : public CodeGenAction {
public:
EmitHLFIRAction() : CodeGenAction(BackendActionTy::Backend_EmitHLFIR) {}
Expand Down
3 changes: 3 additions & 0 deletions flang/include/flang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ enum ActionKind {
/// Emit FIR mlir file
EmitFIR,

/// Emit core MLIR mlir file
EmitMLIR,

/// Emit HLFIR mlir file
EmitHLFIR,

Expand Down
3 changes: 3 additions & 0 deletions flang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,9 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
case clang::driver::options::OPT_emit_fir:
opts.programAction = EmitFIR;
break;
case clang::driver::options::OPT_emit_mlir:
opts.programAction = EmitMLIR;
break;
case clang::driver::options::OPT_emit_hlfir:
opts.programAction = EmitHLFIR;
break;
Expand Down
50 changes: 49 additions & 1 deletion flang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,49 @@ void CodeGenAction::lowerHLFIRToFIR() {
}
}

void CodeGenAction::lowerFIRToMLIR() {
assert(mlirModule && "The MLIR module has not been generated yet.");

CompilerInstance &ci = this->getInstance();
CompilerInvocation &invoc = ci.getInvocation();
const CodeGenOptions &opts = invoc.getCodeGenOpts();
const auto &mathOpts = invoc.getLoweringOpts().getMathOptions();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use a more concrete type instead of auto here?

llvm::OptimizationLevel level = mapToLevel(opts);
mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();

fir::support::loadDialects(*mlirCtx);
mlir::DialectRegistry registry;
fir::support::registerNonCodegenDialects(registry);
fir::support::addFIRExtensions(registry);
mlirCtx->appendDialectRegistry(registry);
fir::support::registerLLVMTranslation(*mlirCtx);

// Set-up the MLIR pass manager
mlir::PassManager pm((*mlirModule)->getName(),
mlir::OpPassManager::Nesting::Implicit);

pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
pm.enableVerifier(/*verifyPasses=*/true);

MLIRToLLVMPassPipelineConfig config(level, opts, mathOpts);
fir::registerDefaultInlinerPass(config);

// Create the pass pipeline
fir::createDefaultFIROptimizerPassPipeline(pm, config);
fir::createDefaultFIRCodeGenPassPipeline(pm, config);
(void)mlir::applyPassManagerCLOptions(pm);

mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest(
mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr));
pm.enableTiming(timingScopeMLIRPasses);
if (!mlir::succeeded(pm.run(*mlirModule))) {
unsigned diagID = ci.getDiagnostics().getCustomDiagID(
clang::DiagnosticsEngine::Error, "Lowering to FIR failed");
ci.getDiagnostics().Report(diagID);
}
}

static std::optional<std::pair<unsigned, unsigned>>
getAArch64VScaleRange(CompilerInstance &ci) {
const auto &langOpts = ci.getInvocation().getLangOpts();
Expand Down Expand Up @@ -836,6 +879,7 @@ getOutputStream(CompilerInstance &ci, llvm::StringRef inFile,
return ci.createDefaultOutputFile(
/*Binary=*/false, inFile, /*extension=*/"ll");
case BackendActionTy::Backend_EmitFIR:
case BackendActionTy::Backend_EmitMLIR:
case BackendActionTy::Backend_EmitHLFIR:
return ci.createDefaultOutputFile(
/*Binary=*/false, inFile, /*extension=*/"mlir");
Expand Down Expand Up @@ -1242,10 +1286,14 @@ void CodeGenAction::executeAction() {
}
}

if (action == BackendActionTy::Backend_EmitFIR) {
if (action == BackendActionTy::Backend_EmitFIR ||
action == BackendActionTy::Backend_EmitMLIR) {
if (loweringOpts.getLowerToHighLevelFIR()) {
lowerHLFIRToFIR();
}
if (action == BackendActionTy::Backend_EmitMLIR) {
lowerFIRToMLIR();
}
mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
return;
}
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ createFrontendAction(CompilerInstance &ci) {
return std::make_unique<ParseSyntaxOnlyAction>();
case EmitFIR:
return std::make_unique<EmitFIRAction>();
case EmitMLIR:
return std::make_unique<EmitMLIRAction>();
case EmitHLFIR:
return std::make_unique<EmitHLFIRAction>();
case EmitLLVM:
Expand Down
30 changes: 30 additions & 0 deletions flang/test/Driver/emit-fir.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
! Test the `-emit-fir` option

! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s

! Verify that an `.mlir` file is created when `-emit-fir` is used. Do it in a temporary directory, which will be cleaned up by the
! LIT runner.
! RUN: rm -rf %t-dir && mkdir -p %t-dir && cd %t-dir
! RUN: cp %s .
! RUN: %flang_fc1 -emit-fir emit-fir.f90 && ls emit-fir.mlir

! CHECK: module attributes {
! CHECK-SAME: dlti.dl_spec =
! CHECK-SAME: llvm.data_layout =
! CHECK-LABEL: func @_QQmain() {
! CHECK-NEXT: fir.dummy_scope
! CHECK-NEXT: return
! CHECK-NEXT: }
! CHECK-NEXT: func.func private @_FortranAProgramStart(i32, !llvm.ptr, !llvm.ptr, !llvm.ptr)
! CHECK-NEXT: func.func private @_FortranAProgramEndStatement()
! CHECK-NEXT: func.func @main(%arg0: i32, %arg1: !llvm.ptr, %arg2: !llvm.ptr) -> i32 {
! CHECK-NEXT: %c0_i32 = arith.constant 0 : i32
! CHECK-NEXT: %0 = fir.zero_bits !fir.ref<tuple<i32, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
! CHECK-NEXT: fir.call @_FortranAProgramStart(%arg0, %arg1, %arg2, %0) {{.*}} : (i32, !llvm.ptr, !llvm.ptr, !fir.ref<tuple<i32, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>)
! CHECK-NEXT: fir.call @_QQmain() fastmath<contract> : () -> ()
! CHECK-NEXT: fir.call @_FortranAProgramEndStatement() {{.*}} : () -> ()
! CHECK-NEXT: return %c0_i32 : i32
! CHECK-NEXT: }
! CHECK-NEXT: }

end program
36 changes: 17 additions & 19 deletions flang/test/Driver/emit-mlir.f90
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
! Test the `-emit-mlir` option

! RUN: %flang_fc1 -emit-mlir %s -o - | FileCheck %s
! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s

! Verify that an `.mlir` file is created when `-emit-mlir` is used. Do it in a temporary directory, which will be cleaned up by the
! LIT runner.
! RUN: rm -rf %t-dir && mkdir -p %t-dir && cd %t-dir
! RUN: cp %s .
! RUN: %flang_fc1 -emit-mlir emit-mlir.f90 && ls emit-mlir.mlir

! CHECK: module attributes {
! CHECK-SAME: dlti.dl_spec =
! CHECK-SAME: llvm.data_layout =
! CHECK-LABEL: func @_QQmain() {
! CHECK-NEXT: fir.dummy_scope
! CHECK-NEXT: return
! CHECK-NEXT: }
! CHECK-NEXT: func.func private @_FortranAProgramStart(i32, !llvm.ptr, !llvm.ptr, !llvm.ptr)
! CHECK-NEXT: func.func private @_FortranAProgramEndStatement()
! CHECK-NEXT: func.func @main(%arg0: i32, %arg1: !llvm.ptr, %arg2: !llvm.ptr) -> i32 {
! CHECK-NEXT: %c0_i32 = arith.constant 0 : i32
! CHECK-NEXT: %0 = fir.zero_bits !fir.ref<tuple<i32, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
! CHECK-NEXT: fir.call @_FortranAProgramStart(%arg0, %arg1, %arg2, %0) {{.*}} : (i32, !llvm.ptr, !llvm.ptr, !fir.ref<tuple<i32, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>)
! CHECK-NEXT: fir.call @_QQmain() fastmath<contract> : () -> ()
! CHECK-NEXT: fir.call @_FortranAProgramEndStatement() {{.*}} : () -> ()
! CHECK-NEXT: return %c0_i32 : i32
! CHECK-NEXT: }
! CHECK-NEXT: }
! CHECK-LABEL: llvm.func @_QQmain() {
! CHECK: llvm.return
! CHECK: }
! CHECK: llvm.func @_FortranAProgramStart(i32, !llvm.ptr, !llvm.ptr, !llvm.ptr) attributes {sym_visibility = "private"}
! CHECK: llvm.func @_FortranAProgramEndStatement() attributes {sym_visibility = "private"}

! CHECK-LABEL: llvm.func @main(
! CHECK-SAME: %[[ARG0:.*]]: i32,
! CHECK-SAME: %[[ARG1:.*]]: !llvm.ptr,
! CHECK-SAME: %[[ARG2:.*]]: !llvm.ptr) -> i32 {
! CHECK: %[[VAL_0:.*]] = llvm.mlir.constant(0 : i32) : i32
! CHECK: %[[VAL_1:.*]] = llvm.mlir.zero : !llvm.ptr
! CHECK: llvm.call @_FortranAProgramStart(%[[ARG0]], %[[ARG1]], %[[ARG2]], %[[VAL_1]]) {fastmathFlags = #llvm.fastmath<contract>} : (i32, !llvm.ptr, !llvm.ptr, !llvm.ptr) -> ()
! CHECK: llvm.call @_QQmain() {fastmathFlags = #llvm.fastmath<contract>} : () -> ()
! CHECK: llvm.call @_FortranAProgramEndStatement() {fastmathFlags = #llvm.fastmath<contract>} : () -> ()
! CHECK: llvm.return %[[VAL_0]] : i32
! CHECK: }

end program
4 changes: 2 additions & 2 deletions flang/test/Fir/non-trivial-procedure-binding-description.f90
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
! RUN: %flang_fc1 -emit-mlir %s -o - | FileCheck %s --check-prefix=BEFORE
! RUN: %flang_fc1 -emit-mlir %s -o - | fir-opt --abstract-result | FileCheck %s --check-prefix=AFTER
! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s --check-prefix=BEFORE
! RUN: %flang_fc1 -emit-fir %s -o - | fir-opt --abstract-result | FileCheck %s --check-prefix=AFTER
module a
type f
contains
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Lower/unsigned-ops.f90
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
! RUN: %flang_fc1 -funsigned -emit-mlir %s -o - | FileCheck %s
! RUN: %flang_fc1 -funsigned -emit-fir %s -o - | FileCheck %s

unsigned function f01(u, v)
unsigned, intent(in) :: u, v
Expand Down