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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits