[clang] [flang] [flang][driver] Separate the actions of the `-emit-fir` and `-emit-mlir` options (PR #139857)
via cfe-commits
cfe-commits at lists.llvm.org
Wed May 14 01:02:48 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: MingYan (NexMing)
<details>
<summary>Changes</summary>
This patch split `-emit-fir` and `-emit-mlir` option in Flang's frontend driver.
A new parent class for code-gen frontend actions is introduced:`CodeGenAction`.
For the `-emit-mlir` option, we aim to generate a file using the core MLIR dialects. Currently, FIR Dialect is directly lowered to LLVM Dialect, but in the future, we hope to gradually separate the pipeline into FIR → MLIR (core dialects) → LLVM. For now, this option temporarily generate a file using the LLVM dialect.
---
Full diff: https://github.com/llvm/llvm-project/pull/139857.diff
10 Files Affected:
- (modified) clang/include/clang/Driver/Options.td (+2-1)
- (modified) flang/include/flang/Frontend/FrontendActions.h (+11)
- (modified) flang/include/flang/Frontend/FrontendOptions.h (+3)
- (modified) flang/lib/Frontend/CompilerInvocation.cpp (+3)
- (modified) flang/lib/Frontend/FrontendActions.cpp (+49-1)
- (modified) flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp (+2)
- (added) flang/test/Driver/emit-fir.f90 (+30)
- (modified) flang/test/Driver/emit-mlir.f90 (+17-19)
- (modified) flang/test/Fir/non-trivial-procedure-binding-description.f90 (+2-2)
- (modified) flang/test/Lower/unsigned-ops.f90 (+1-1)
``````````diff
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index bd8df8f6a749a..00cc05a2bd1a6 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -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">;
diff --git a/flang/include/flang/Frontend/FrontendActions.h b/flang/include/flang/Frontend/FrontendActions.h
index f9a45bd6c0a56..b651a234b5849 100644
--- a/flang/include/flang/Frontend/FrontendActions.h
+++ b/flang/include/flang/Frontend/FrontendActions.h
@@ -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
};
@@ -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();
@@ -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) {}
diff --git a/flang/include/flang/Frontend/FrontendOptions.h b/flang/include/flang/Frontend/FrontendOptions.h
index 0bd2e621813ca..69bc5691430a8 100644
--- a/flang/include/flang/Frontend/FrontendOptions.h
+++ b/flang/include/flang/Frontend/FrontendOptions.h
@@ -37,6 +37,9 @@ enum ActionKind {
/// Emit FIR mlir file
EmitFIR,
+ /// Emit core MLIR mlir file
+ EmitMLIR,
+
/// Emit HLFIR mlir file
EmitHLFIR,
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 238079a09ef3a..2a4b6e9d884af 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -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;
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index e5a15c555fa5e..9ba98873042f8 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -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();
+ 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();
@@ -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");
@@ -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;
}
diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 09ac129d3e689..0c4195ec2ac2e 100644
--- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -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:
diff --git a/flang/test/Driver/emit-fir.f90 b/flang/test/Driver/emit-fir.f90
new file mode 100644
index 0000000000000..4230c4b7ab434
--- /dev/null
+++ b/flang/test/Driver/emit-fir.f90
@@ -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
diff --git a/flang/test/Driver/emit-mlir.f90 b/flang/test/Driver/emit-mlir.f90
index de5a62d6bc7f3..cced4b0e37017 100644
--- a/flang/test/Driver/emit-mlir.f90
+++ b/flang/test/Driver/emit-mlir.f90
@@ -1,7 +1,6 @@
! 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.
@@ -9,23 +8,22 @@
! 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
diff --git a/flang/test/Fir/non-trivial-procedure-binding-description.f90 b/flang/test/Fir/non-trivial-procedure-binding-description.f90
index 668928600157b..79bb4dbb3521e 100644
--- a/flang/test/Fir/non-trivial-procedure-binding-description.f90
+++ b/flang/test/Fir/non-trivial-procedure-binding-description.f90
@@ -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
diff --git a/flang/test/Lower/unsigned-ops.f90 b/flang/test/Lower/unsigned-ops.f90
index f61f10656159a..fa1eb47b26b00 100644
--- a/flang/test/Lower/unsigned-ops.f90
+++ b/flang/test/Lower/unsigned-ops.f90
@@ -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
``````````
</details>
https://github.com/llvm/llvm-project/pull/139857
More information about the cfe-commits
mailing list