[flang-commits] [flang] [flang] Refactor to remove .inc file containing shared code (PR #109874)

Tarun Prabhu via flang-commits flang-commits at lists.llvm.org
Tue Sep 24 15:30:57 PDT 2024


https://github.com/tarunprabhu created https://github.com/llvm/llvm-project/pull/109874

Remove flang/include/flang/Tools/CLOptions.inc - which was included as is in - several places. Move the code in it to header and source files which are used used in the "standard" way. Some minor cleanup such as removing trailing whitespace and excessive newlines and reordering entries alphabetically for files that were modified along the way. Update the documentation that referenced CLOptions.inc.

------------------------

Notes for reviewers:

This is in response to #102975 being reverted. The underlying issue was `flang/include/flang/Tools/CLOptions.inc` being included directly in several places. That file contains command-line options and function definitions which results in the duplicate definition errors if the file is included in more than one place in an executable/library.

IMO, including files containing code causes issues in the long run as it removes the ability to link against certain libraries. This PR moves the code in `CLOptions.inc` into `.h` and `.cpp` files which can then be included and linked in the "standard" way.

The contents of `CLOptions.inc` are split across two places since the contents include both command line options and functions to build FIR pass pipelines which don't seem like they should belong together anyway.

The command line options were moved to `Common/` since it seemed a "reasonable" place for them. 

The FIR pass pipeline code was moved to a new `Passes` directory in `flang/lib/Optimizer`. It was not possible to put the code in, for instance, `Common/`, `Support/` or `Optimizer/Transforms/` because that resulted in circular dependencies. The name `Passes` was chosen because the code there is functionally similar to some code in `llvm/Passes`.

>From 51a60d173f15bdbdaafd2a927f372789fde3bbce Mon Sep 17 00:00:00 2001
From: Tarun Prabhu <tarun.prabhu at gmail.com>
Date: Tue, 24 Sep 2024 16:03:24 -0600
Subject: [PATCH] [flang] Refactor to remove .inc file containing shared code

Remove flang/include/flang/Tools/CLOptions.inc - which was included as is in -
several places. Move the code in it to header and source files which are used
used in the "standard" way. Some minor cleanup such as removing trailing
whitespace and excessive newlines and reordering entries alphabetically for
files that were modified along the way. Update the documentation that
referenced CLOptions.inc.
---
 flang/docs/FlangDriver.md                     |   2 +-
 flang/include/flang/Common/CommandLineOpts.h  |  60 +++
 .../flang/Optimizer/Passes/Pipelines.h        | 128 +++++
 flang/include/flang/Tools/CLOptions.inc       | 438 ------------------
 flang/lib/Common/CMakeLists.txt               |   5 +-
 flang/lib/Common/CommandLineOpts.cpp          |  67 +++
 flang/lib/Frontend/CMakeLists.txt             |   1 +
 flang/lib/Frontend/FrontendActions.cpp        |   3 +-
 flang/lib/Optimizer/CMakeLists.txt            |   5 +-
 flang/lib/Optimizer/Passes/CMakeLists.txt     |  21 +
 flang/lib/Optimizer/Passes/Pipelines.cpp      | 330 +++++++++++++
 flang/tools/bbc/CMakeLists.txt                |   1 +
 flang/tools/bbc/bbc.cpp                       |   3 +-
 flang/tools/tco/CMakeLists.txt                |   2 +
 flang/tools/tco/tco.cpp                       |   3 +-
 15 files changed, 622 insertions(+), 447 deletions(-)
 create mode 100644 flang/include/flang/Common/CommandLineOpts.h
 create mode 100644 flang/include/flang/Optimizer/Passes/Pipelines.h
 delete mode 100644 flang/include/flang/Tools/CLOptions.inc
 create mode 100644 flang/lib/Common/CommandLineOpts.cpp
 create mode 100644 flang/lib/Optimizer/Passes/CMakeLists.txt
 create mode 100644 flang/lib/Optimizer/Passes/Pipelines.cpp

diff --git a/flang/docs/FlangDriver.md b/flang/docs/FlangDriver.md
index e1c11062125028..815c26a28dfdfa 100644
--- a/flang/docs/FlangDriver.md
+++ b/flang/docs/FlangDriver.md
@@ -521,7 +521,7 @@ e.g. during the semantic checks.
 ## FIR Optimizer Pass Pipeline Extension Points
 
 The default FIR optimizer pass pipeline `createDefaultFIROptimizerPassPipeline`
-in `flang/include/flang/Tools/CLOptions.inc` contains extension point callback
+in `flang/lib/Optimizer/Passes/Pipelines.cpp` contains extension point callback
 invocations `invokeFIROptEarlyEPCallbacks`, `invokeFIRInlinerCallback`, and
 `invokeFIROptLastEPCallbacks` for Flang drivers to be able to insert additonal
 passes at different points of the default pass pipeline. An example use of these
diff --git a/flang/include/flang/Common/CommandLineOpts.h b/flang/include/flang/Common/CommandLineOpts.h
new file mode 100644
index 00000000000000..72674b2b809c24
--- /dev/null
+++ b/flang/include/flang/Common/CommandLineOpts.h
@@ -0,0 +1,60 @@
+//===-- CommandLineOptions.h -- shared command line options -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+/// This file declares some shared command-line options that can be used when
+/// debugging the test tools.
+
+#ifndef FORTRAN_COMMON_COMMANDLINEOPTS_H
+#define FORTRAN_COMMON_COMMANDLINEOPTS_H
+
+#include "llvm/Frontend/Debug/Options.h"
+#include "llvm/Passes/OptimizationLevel.h"
+#include "llvm/Support/CommandLine.h"
+
+/// Shared option in tools to control whether dynamically sized array
+/// allocations should always be on the heap.
+extern llvm::cl::opt<bool> dynamicArrayStackToHeapAllocation;
+
+/// Shared option in tools to set a maximum value for the number of elements in
+/// a compile-time sized array that can be allocated on the stack.
+extern llvm::cl::opt<std::size_t> arrayStackAllocationThreshold;
+
+/// Shared option in tools to ignore missing runtime type descriptor objects
+/// when translating FIR to LLVM. The resulting program will crash if the
+/// runtime needs the derived type descriptors, this is only a debug option to
+/// allow compiling manually written FIR programs involving derived types
+/// without having to write the derived type descriptors which are normally
+/// generated by the frontend.
+extern llvm::cl::opt<bool> ignoreMissingTypeDescriptors;
+
+/// Default optimization level used to create Flang pass pipeline is O0.
+extern llvm::OptimizationLevel defaultOptLevel;
+
+extern llvm::codegenoptions::DebugInfoKind noDebugInfo;
+
+/// Optimizer Passes
+extern llvm::cl::opt<bool> disableCfgConversion;
+extern llvm::cl::opt<bool> disableFirAvc;
+extern llvm::cl::opt<bool> disableFirMao;
+
+extern llvm::cl::opt<bool> disableFirAliasTags;
+extern llvm::cl::opt<bool> useOldAliasTags;
+
+/// CodeGen Passes
+extern llvm::cl::opt<bool> disableCodeGenRewrite;
+extern llvm::cl::opt<bool> disableTargetRewrite;
+extern llvm::cl::opt<bool> disableDebugInfo;
+extern llvm::cl::opt<bool> disableFirToLlvmIr;
+extern llvm::cl::opt<bool> disableLlvmIrToLlvm;
+extern llvm::cl::opt<bool> disableBoxedProcedureRewrite;
+
+extern llvm::cl::opt<bool> disableExternalNameConversion;
+extern llvm::cl::opt<bool> enableConstantArgumentGlobalisation;
+extern llvm::cl::opt<bool> disableCompilerGeneratedNamesConversion;
+
+#endif // FORTRAN_COMMON_COMMANDLINE_OPTS_H
diff --git a/flang/include/flang/Optimizer/Passes/Pipelines.h b/flang/include/flang/Optimizer/Passes/Pipelines.h
new file mode 100644
index 00000000000000..8980bfbb90e9a0
--- /dev/null
+++ b/flang/include/flang/Optimizer/Passes/Pipelines.h
@@ -0,0 +1,128 @@
+//===-- Pipelines.h -- FIR pass pipelines -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+/// This file declares some utilties to setup FIR pass pipelines. These are
+/// common to flang and the test tools.
+
+#ifndef FORTRAN_OPTIMIZER_PASSES_PIPELINES_H
+#define FORTRAN_OPTIMIZER_PASSES_PIPELINES_H
+
+#include "flang/Common/CommandLineOpts.h"
+#include "flang/Optimizer/CodeGen/CodeGen.h"
+#include "flang/Optimizer/HLFIR/Passes.h"
+#include "flang/Optimizer/OpenMP/Passes.h"
+#include "flang/Optimizer/Transforms/Passes.h"
+#include "flang/Tools/CrossToolHelpers.h"
+#include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
+#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
+#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
+#include "mlir/Pass/PassManager.h"
+#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
+#include "mlir/Transforms/Passes.h"
+#include "llvm/Frontend/Debug/Options.h"
+#include "llvm/Passes/OptimizationLevel.h"
+#include "llvm/Support/CommandLine.h"
+
+namespace {
+
+using PassConstructor = std::unique_ptr<mlir::Pass>();
+
+template <typename OP>
+void addNestedPassToOps(mlir::PassManager &pm, PassConstructor ctor) {
+  pm.addNestedPass<OP>(ctor());
+}
+
+template <typename OP, typename... OPS,
+          typename = std::enable_if_t<sizeof...(OPS) != 0>>
+void addNestedPassToOps(mlir::PassManager &pm, PassConstructor ctor) {
+  addNestedPassToOps<OP>(pm, ctor);
+  addNestedPassToOps<OPS...>(pm, ctor);
+}
+
+/// Generic for adding a pass to the pass manager if it is not disabled.
+template <typename F>
+void addPassConditionally(mlir::PassManager &pm, llvm::cl::opt<bool> &disabled,
+                          F ctor) {
+  if (!disabled)
+    pm.addPass(ctor());
+}
+
+template <typename OP, typename F>
+void addNestedPassConditionally(mlir::PassManager &pm,
+                                llvm::cl::opt<bool> &disabled, F ctor) {
+  if (!disabled)
+    pm.addNestedPass<OP>(ctor());
+}
+
+} // namespace
+
+namespace fir {
+
+void addDebugInfoPass(mlir::PassManager &pm,
+                      llvm::codegenoptions::DebugInfoKind debugLevel,
+                      llvm::OptimizationLevel optLevel,
+                      llvm::StringRef inputFilename);
+
+void addFIRToLLVMPass(mlir::PassManager &pm,
+                      const MLIRToLLVMPassPipelineConfig &config);
+
+void addLLVMDialectToLLVMPass(mlir::PassManager &pm, llvm::raw_ostream &output);
+
+/// Use inliner extension point callback to register the default inliner pass.
+void registerDefaultInlinerPass(MLIRToLLVMPassPipelineConfig &config);
+
+/// Create a pass pipeline for running default optimization passes for
+/// incremental conversion of FIR.
+///
+/// \param pm - MLIR pass manager that will hold the pipeline definition
+void createDefaultFIROptimizerPassPipeline(mlir::PassManager &pm,
+                                           MLIRToLLVMPassPipelineConfig &pc);
+
+/// Create a pass pipeline for lowering from HLFIR to FIR
+///
+/// \param pm - MLIR pass manager that will hold the pipeline definition
+/// \param optLevel - optimization level used for creating FIR optimization
+///   passes pipeline
+void createHLFIRToFIRPassPipeline(
+    mlir::PassManager &pm, llvm::OptimizationLevel optLevel = defaultOptLevel);
+
+/// Create a pass pipeline for handling certain OpenMP transformations needed
+/// prior to FIR lowering.
+///
+/// WARNING: These passes must be run immediately after the lowering to ensure
+/// that the FIR is correct with respect to OpenMP operations/attributes.
+///
+/// \param pm - MLIR pass manager that will hold the pipeline definition.
+/// \param isTargetDevice - Whether code is being generated for a target device
+/// rather than the host device.
+void createOpenMPFIRPassPipeline(mlir::PassManager &pm, bool isTargetDevice);
+
+#if !defined(FLANG_EXCLUDE_CODEGEN)
+void createDebugPasses(mlir::PassManager &pm,
+                       llvm::codegenoptions::DebugInfoKind debugLevel,
+                       llvm::OptimizationLevel OptLevel,
+                       llvm::StringRef inputFilename);
+
+void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
+                                         MLIRToLLVMPassPipelineConfig config,
+                                         llvm::StringRef inputFilename = {});
+
+/// Create a pass pipeline for lowering from MLIR to LLVM IR
+///
+/// \param pm - MLIR pass manager that will hold the pipeline definition
+/// \param optLevel - optimization level used for creating FIR optimization
+///   passes pipeline
+void createMLIRToLLVMPassPipeline(mlir::PassManager &pm,
+                                  MLIRToLLVMPassPipelineConfig &config,
+                                  llvm::StringRef inputFilename = {});
+#undef FLANG_EXCLUDE_CODEGEN
+#endif
+
+} // namespace fir
+
+#endif // FORTRAN_OPTIMIZER_PASSES_PIPELINES_H
diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc
deleted file mode 100644
index 04b7f0ba370b86..00000000000000
--- a/flang/include/flang/Tools/CLOptions.inc
+++ /dev/null
@@ -1,438 +0,0 @@
-//===-- CLOptions.inc -- command line options -------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-/// This file defines some shared command-line options that can be used when
-/// debugging the test tools. This file must be included into the tool.
-
-#include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
-#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
-#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
-#include "mlir/Pass/PassManager.h"
-#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
-#include "mlir/Transforms/Passes.h"
-#include "flang/Optimizer/CodeGen/CodeGen.h"
-#include "flang/Optimizer/HLFIR/Passes.h"
-#include "flang/Optimizer/OpenMP/Passes.h"
-#include "flang/Optimizer/Transforms/Passes.h"
-#include "llvm/Passes/OptimizationLevel.h"
-#include "llvm/Support/CommandLine.h"
-#include <type_traits>
-
-#define DisableOption(DOName, DOOption, DODescription) \
-  static llvm::cl::opt<bool> disable##DOName("disable-" DOOption, \
-      llvm::cl::desc("disable " DODescription " pass"), llvm::cl::init(false), \
-      llvm::cl::Hidden)
-#define EnableOption(EOName, EOOption, EODescription) \
-  static llvm::cl::opt<bool> enable##EOName("enable-" EOOption, \
-      llvm::cl::desc("enable " EODescription " pass"), llvm::cl::init(false), \
-      llvm::cl::Hidden)
-
-/// Shared option in tools to control whether dynamically sized array
-/// allocations should always be on the heap.
-static llvm::cl::opt<bool> dynamicArrayStackToHeapAllocation(
-    "fdynamic-heap-array",
-    llvm::cl::desc("place all array allocations of dynamic size on the heap"),
-    llvm::cl::init(false), llvm::cl::Hidden);
-
-/// Shared option in tools to set a maximum value for the number of elements in
-/// a compile-time sized array that can be allocated on the stack.
-static llvm::cl::opt<std::size_t> arrayStackAllocationThreshold(
-    "fstack-array-size",
-    llvm::cl::desc(
-        "place all array allocations more than <size> elements on the heap"),
-    llvm::cl::init(~static_cast<std::size_t>(0)), llvm::cl::Hidden);
-
-/// Shared option in tools to ignore missing runtime type descriptor objects
-/// when translating FIR to LLVM. The resulting program will crash if the
-/// runtime needs the derived type descriptors, this is only a debug option to
-/// allow compiling manually written FIR programs involving derived types
-/// without having to write the derived type descriptors which are normally
-/// generated by the frontend.
-static llvm::cl::opt<bool> ignoreMissingTypeDescriptors(
-    "ignore-missing-type-desc",
-    llvm::cl::desc("ignore failures to find derived type descriptors when "
-                   "translating FIR to LLVM"),
-    llvm::cl::init(false), llvm::cl::Hidden);
-
-namespace {
-/// Default optimization level used to create Flang pass pipeline is O0.
-const static llvm::OptimizationLevel &defaultOptLevel{
-    llvm::OptimizationLevel::O0};
-
-const static llvm::codegenoptions::DebugInfoKind &NoDebugInfo{
-    llvm::codegenoptions::NoDebugInfo};
-
-/// Optimizer Passes
-DisableOption(CfgConversion, "cfg-conversion", "disable FIR to CFG pass");
-DisableOption(FirAvc, "avc", "array value copy analysis and transformation");
-DisableOption(
-    FirMao, "memory-allocation-opt", "memory allocation optimization");
-
-DisableOption(FirAliasTags, "fir-alias-tags", "fir alias analysis");
-static llvm::cl::opt<bool> useOldAliasTags("use-old-alias-tags",
-    llvm::cl::desc("Use a single TBAA tree for all functions and do not use "
-                   "the FIR alias tags pass"),
-    llvm::cl::init(false), llvm::cl::Hidden);
-
-/// CodeGen Passes
-#if !defined(FLANG_EXCLUDE_CODEGEN)
-DisableOption(CodeGenRewrite, "codegen-rewrite", "rewrite FIR for codegen");
-DisableOption(TargetRewrite, "target-rewrite", "rewrite FIR for target");
-DisableOption(DebugInfo, "debug-info", "Add debug info");
-DisableOption(FirToLlvmIr, "fir-to-llvmir", "FIR to LLVM-IR dialect");
-DisableOption(LlvmIrToLlvm, "llvm", "conversion to LLVM");
-DisableOption(BoxedProcedureRewrite, "boxed-procedure-rewrite",
-    "rewrite boxed procedures");
-#endif
-
-DisableOption(ExternalNameConversion, "external-name-interop",
-    "convert names with external convention");
-EnableOption(ConstantArgumentGlobalisation, "constant-argument-globalisation",
-    "the local constant argument to global constant conversion");
-DisableOption(CompilerGeneratedNamesConversion, "compiler-generated-names",
-    "replace special symbols in compiler generated names");
-
-using PassConstructor = std::unique_ptr<mlir::Pass>();
-
-template <typename OP>
-void addNestedPassToOps(mlir::PassManager &pm, PassConstructor ctor) {
-  pm.addNestedPass<OP>(ctor());
-}
-
-template <typename OP, typename... OPS,
-    typename = std::enable_if_t<sizeof...(OPS) != 0>>
-void addNestedPassToOps(mlir::PassManager &pm, PassConstructor ctor) {
-  addNestedPassToOps<OP>(pm, ctor);
-  addNestedPassToOps<OPS...>(pm, ctor);
-}
-
-void addNestedPassToAllTopLevelOperations(
-    mlir::PassManager &pm, PassConstructor ctor) {
-  addNestedPassToOps<mlir::func::FuncOp, mlir::omp::DeclareReductionOp,
-      mlir::omp::PrivateClauseOp, fir::GlobalOp>(pm, ctor);
-}
-
-void addNestedPassToAllTopLevelOperationsConditionally(mlir::PassManager &pm,
-    llvm::cl::opt<bool> &disabled, PassConstructor ctor) {
-  if (!disabled)
-    addNestedPassToAllTopLevelOperations(pm, ctor);
-}
-
-/// Generic for adding a pass to the pass manager if it is not disabled.
-template <typename F>
-void addPassConditionally(
-    mlir::PassManager &pm, llvm::cl::opt<bool> &disabled, F ctor) {
-  if (!disabled)
-    pm.addPass(ctor());
-}
-
-template <typename OP, typename F>
-void addNestedPassConditionally(
-    mlir::PassManager &pm, llvm::cl::opt<bool> &disabled, F ctor) {
-  if (!disabled)
-    pm.addNestedPass<OP>(ctor());
-}
-
-} // namespace
-
-namespace fir {
-
-/// Add MLIR Canonicalizer pass with region simplification disabled.
-/// FIR does not support the promotion of some SSA value to block arguments (or
-/// into arith.select operands) that may be done by mlir block merging in the
-/// region simplification (e.g., !fir.shape<> SSA values are not supported as
-/// block arguments).
-/// Aside from the fir.shape issue, moving some abstract SSA value into block
-/// arguments may have a heavy cost since it forces their code generation that
-/// may be expensive (array temporary). The MLIR pass does not take these
-/// extra costs into account when doing block merging.
-static void addCanonicalizerPassWithoutRegionSimplification(
-    mlir::OpPassManager &pm) {
-  mlir::GreedyRewriteConfig config;
-  config.enableRegionSimplification = mlir::GreedySimplifyRegionLevel::Disabled;
-  pm.addPass(mlir::createCanonicalizerPass(config));
-}
-
-inline void addCfgConversionPass(
-    mlir::PassManager &pm, const MLIRToLLVMPassPipelineConfig &config) {
-  if (config.NSWOnLoopVarInc)
-    addNestedPassToAllTopLevelOperationsConditionally(
-        pm, disableCfgConversion, fir::createCFGConversionPassWithNSW);
-  else
-    addNestedPassToAllTopLevelOperationsConditionally(
-        pm, disableCfgConversion, fir::createCFGConversion);
-}
-
-inline void addAVC(
-    mlir::PassManager &pm, const llvm::OptimizationLevel &optLevel) {
-  ArrayValueCopyOptions options;
-  options.optimizeConflicts = optLevel.isOptimizingForSpeed();
-  addNestedPassConditionally<mlir::func::FuncOp>(
-      pm, disableFirAvc, [&]() { return createArrayValueCopyPass(options); });
-}
-
-inline void addMemoryAllocationOpt(mlir::PassManager &pm) {
-  addNestedPassConditionally<mlir::func::FuncOp>(pm, disableFirMao, [&]() {
-    return fir::createMemoryAllocationOpt(
-        {dynamicArrayStackToHeapAllocation, arrayStackAllocationThreshold});
-  });
-}
-
-#if !defined(FLANG_EXCLUDE_CODEGEN)
-inline void addCodeGenRewritePass(mlir::PassManager &pm, bool preserveDeclare) {
-  fir::CodeGenRewriteOptions options;
-  options.preserveDeclare = preserveDeclare;
-  addPassConditionally(pm, disableCodeGenRewrite,
-      [&]() { return fir::createCodeGenRewrite(options); });
-}
-
-inline void addTargetRewritePass(mlir::PassManager &pm) {
-  addPassConditionally(pm, disableTargetRewrite,
-      []() { return fir::createTargetRewritePass(); });
-}
-
-inline mlir::LLVM::DIEmissionKind getEmissionKind(
-    llvm::codegenoptions::DebugInfoKind kind) {
-  switch (kind) {
-  case llvm::codegenoptions::DebugInfoKind::FullDebugInfo:
-    return mlir::LLVM::DIEmissionKind::Full;
-  case llvm::codegenoptions::DebugInfoKind::DebugLineTablesOnly:
-    return mlir::LLVM::DIEmissionKind::LineTablesOnly;
-  default:
-    return mlir::LLVM::DIEmissionKind::None;
-  }
-}
-
-inline void addDebugInfoPass(mlir::PassManager &pm,
-    llvm::codegenoptions::DebugInfoKind debugLevel,
-    llvm::OptimizationLevel optLevel, llvm::StringRef inputFilename) {
-  fir::AddDebugInfoOptions options;
-  options.debugLevel = getEmissionKind(debugLevel);
-  options.isOptimized = optLevel != llvm::OptimizationLevel::O0;
-  options.inputFilename = inputFilename;
-  addPassConditionally(pm, disableDebugInfo,
-      [&]() { return fir::createAddDebugInfoPass(options); });
-}
-
-inline void addFIRToLLVMPass(
-    mlir::PassManager &pm, const MLIRToLLVMPassPipelineConfig &config) {
-  fir::FIRToLLVMPassOptions options;
-  options.ignoreMissingTypeDescriptors = ignoreMissingTypeDescriptors;
-  options.applyTBAA = config.AliasAnalysis;
-  options.forceUnifiedTBAATree = useOldAliasTags;
-  options.typeDescriptorsRenamedForAssembly =
-      !disableCompilerGeneratedNamesConversion;
-  addPassConditionally(pm, disableFirToLlvmIr,
-      [&]() { return fir::createFIRToLLVMPass(options); });
-  // The dialect conversion framework may leave dead unrealized_conversion_cast
-  // ops behind, so run reconcile-unrealized-casts to clean them up.
-  addPassConditionally(pm, disableFirToLlvmIr,
-      [&]() { return mlir::createReconcileUnrealizedCastsPass(); });
-}
-
-inline void addLLVMDialectToLLVMPass(
-    mlir::PassManager &pm, llvm::raw_ostream &output) {
-  addPassConditionally(pm, disableLlvmIrToLlvm,
-      [&]() { return fir::createLLVMDialectToLLVMPass(output); });
-}
-
-inline void addBoxedProcedurePass(mlir::PassManager &pm) {
-  addPassConditionally(pm, disableBoxedProcedureRewrite,
-      [&]() { return fir::createBoxedProcedurePass(); });
-}
-#endif
-
-inline void addExternalNameConversionPass(
-    mlir::PassManager &pm, bool appendUnderscore = true) {
-  addPassConditionally(pm, disableExternalNameConversion,
-      [&]() { return fir::createExternalNameConversion({appendUnderscore}); });
-}
-
-inline void addCompilerGeneratedNamesConversionPass(mlir::PassManager &pm) {
-  addPassConditionally(pm, disableCompilerGeneratedNamesConversion,
-      [&]() { return fir::createCompilerGeneratedNamesConversion(); });
-}
-
-// Use inliner extension point callback to register the default inliner pass.
-inline void registerDefaultInlinerPass(MLIRToLLVMPassPipelineConfig &config) {
-  config.registerFIRInlinerCallback(
-      [](mlir::PassManager &pm, llvm::OptimizationLevel level) {
-        llvm::StringMap<mlir::OpPassManager> pipelines;
-        // The default inliner pass adds the canonicalizer pass with the default
-        // configuration.
-        pm.addPass(mlir::createInlinerPass(
-            pipelines, addCanonicalizerPassWithoutRegionSimplification));
-      });
-}
-
-/// Create a pass pipeline for running default optimization passes for
-/// incremental conversion of FIR.
-///
-/// \param pm - MLIR pass manager that will hold the pipeline definition
-inline void createDefaultFIROptimizerPassPipeline(
-    mlir::PassManager &pm, MLIRToLLVMPassPipelineConfig &pc) {
-  // Early Optimizer EP Callback
-  pc.invokeFIROptEarlyEPCallbacks(pm, pc.OptLevel);
-
-  // simplify the IR
-  mlir::GreedyRewriteConfig config;
-  config.enableRegionSimplification = mlir::GreedySimplifyRegionLevel::Disabled;
-  pm.addPass(mlir::createCSEPass());
-  fir::addAVC(pm, pc.OptLevel);
-  addNestedPassToAllTopLevelOperations(pm, fir::createCharacterConversion);
-  pm.addPass(mlir::createCanonicalizerPass(config));
-  pm.addPass(fir::createSimplifyRegionLite());
-  if (pc.OptLevel.isOptimizingForSpeed()) {
-    // These passes may increase code size.
-    pm.addPass(fir::createSimplifyIntrinsics());
-    pm.addPass(fir::createAlgebraicSimplificationPass(config));
-    if (enableConstantArgumentGlobalisation)
-      pm.addPass(fir::createConstantArgumentGlobalisationOpt());
-  }
-
-  if (pc.LoopVersioning)
-    pm.addPass(fir::createLoopVersioning());
-
-  pm.addPass(mlir::createCSEPass());
-
-  if (pc.StackArrays)
-    pm.addPass(fir::createStackArrays());
-  else
-    fir::addMemoryAllocationOpt(pm);
-
-  // FIR Inliner Callback
-  pc.invokeFIRInlinerCallback(pm, pc.OptLevel);
-
-  pm.addPass(fir::createSimplifyRegionLite());
-  pm.addPass(mlir::createCSEPass());
-
-  // Polymorphic types
-  pm.addPass(fir::createPolymorphicOpConversion());
-  pm.addPass(fir::createAssumedRankOpConversion());
-
-  if (pc.AliasAnalysis && !disableFirAliasTags && !useOldAliasTags)
-    pm.addPass(fir::createAddAliasTags());
-
-  addNestedPassToAllTopLevelOperations(pm, fir::createStackReclaim);
-  // convert control flow to CFG form
-  fir::addCfgConversionPass(pm, pc);
-  pm.addPass(mlir::createConvertSCFToCFPass());
-
-  pm.addPass(mlir::createCanonicalizerPass(config));
-  pm.addPass(fir::createSimplifyRegionLite());
-  pm.addPass(mlir::createCSEPass());
-
-  // Last Optimizer EP Callback
-  pc.invokeFIROptLastEPCallbacks(pm, pc.OptLevel);
-}
-
-/// Create a pass pipeline for lowering from HLFIR to FIR
-///
-/// \param pm - MLIR pass manager that will hold the pipeline definition
-/// \param optLevel - optimization level used for creating FIR optimization
-///   passes pipeline
-inline void createHLFIRToFIRPassPipeline(
-    mlir::PassManager &pm, llvm::OptimizationLevel optLevel = defaultOptLevel) {
-  if (optLevel.isOptimizingForSpeed()) {
-    addCanonicalizerPassWithoutRegionSimplification(pm);
-    addNestedPassToAllTopLevelOperations(
-        pm, hlfir::createSimplifyHLFIRIntrinsics);
-  }
-  addNestedPassToAllTopLevelOperations(pm, hlfir::createInlineElementals);
-  if (optLevel.isOptimizingForSpeed()) {
-    addCanonicalizerPassWithoutRegionSimplification(pm);
-    pm.addPass(mlir::createCSEPass());
-    addNestedPassToAllTopLevelOperations(
-        pm, hlfir::createOptimizedBufferization);
-  }
-  pm.addPass(hlfir::createLowerHLFIROrderedAssignments());
-  pm.addPass(hlfir::createLowerHLFIRIntrinsics());
-  pm.addPass(hlfir::createBufferizeHLFIR());
-  pm.addPass(hlfir::createConvertHLFIRtoFIR());
-}
-
-/// Create a pass pipeline for handling certain OpenMP transformations needed
-/// prior to FIR lowering.
-///
-/// WARNING: These passes must be run immediately after the lowering to ensure
-/// that the FIR is correct with respect to OpenMP operations/attributes.
-///
-/// \param pm - MLIR pass manager that will hold the pipeline definition.
-/// \param isTargetDevice - Whether code is being generated for a target device
-/// rather than the host device.
-inline void createOpenMPFIRPassPipeline(
-    mlir::PassManager &pm, bool isTargetDevice) {
-  pm.addPass(flangomp::createMapInfoFinalizationPass());
-  pm.addPass(flangomp::createMarkDeclareTargetPass());
-  if (isTargetDevice)
-    pm.addPass(flangomp::createFunctionFilteringPass());
-}
-
-#if !defined(FLANG_EXCLUDE_CODEGEN)
-inline void createDebugPasses(mlir::PassManager &pm,
-    llvm::codegenoptions::DebugInfoKind debugLevel,
-    llvm::OptimizationLevel OptLevel, llvm::StringRef inputFilename) {
-  if (debugLevel != llvm::codegenoptions::NoDebugInfo)
-    addDebugInfoPass(pm, debugLevel, OptLevel, inputFilename);
-}
-
-inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
-    MLIRToLLVMPassPipelineConfig config, llvm::StringRef inputFilename = {}) {
-  fir::addBoxedProcedurePass(pm);
-  addNestedPassToAllTopLevelOperations(pm, fir::createAbstractResultOpt);
-  fir::addCodeGenRewritePass(
-      pm, (config.DebugInfo != llvm::codegenoptions::NoDebugInfo));
-  fir::addTargetRewritePass(pm);
-  fir::addCompilerGeneratedNamesConversionPass(pm);
-  fir::addExternalNameConversionPass(pm, config.Underscoring);
-  fir::createDebugPasses(pm, config.DebugInfo, config.OptLevel, inputFilename);
-
-  if (config.VScaleMin != 0)
-    pm.addPass(fir::createVScaleAttr({{config.VScaleMin, config.VScaleMax}}));
-
-  // Add function attributes
-  mlir::LLVM::framePointerKind::FramePointerKind framePointerKind;
-
-  if (config.FramePointerKind != llvm::FramePointerKind::None ||
-      config.NoInfsFPMath || config.NoNaNsFPMath || config.ApproxFuncFPMath ||
-      config.NoSignedZerosFPMath || config.UnsafeFPMath) {
-    if (config.FramePointerKind == llvm::FramePointerKind::NonLeaf)
-      framePointerKind =
-          mlir::LLVM::framePointerKind::FramePointerKind::NonLeaf;
-    else if (config.FramePointerKind == llvm::FramePointerKind::All)
-      framePointerKind = mlir::LLVM::framePointerKind::FramePointerKind::All;
-    else
-      framePointerKind = mlir::LLVM::framePointerKind::FramePointerKind::None;
-
-    pm.addPass(fir::createFunctionAttr({framePointerKind, config.NoInfsFPMath,
-        config.NoNaNsFPMath, config.ApproxFuncFPMath,
-        config.NoSignedZerosFPMath, config.UnsafeFPMath}));
-  }
-
-  fir::addFIRToLLVMPass(pm, config);
-}
-
-/// Create a pass pipeline for lowering from MLIR to LLVM IR
-///
-/// \param pm - MLIR pass manager that will hold the pipeline definition
-/// \param optLevel - optimization level used for creating FIR optimization
-///   passes pipeline
-inline void createMLIRToLLVMPassPipeline(mlir::PassManager &pm,
-    MLIRToLLVMPassPipelineConfig &config, llvm::StringRef inputFilename = {}) {
-  fir::createHLFIRToFIRPassPipeline(pm, config.OptLevel);
-
-  // Add default optimizer pass pipeline.
-  fir::createDefaultFIROptimizerPassPipeline(pm, config);
-
-  // Add codegen pass pipeline.
-  fir::createDefaultFIRCodeGenPassPipeline(pm, config, inputFilename);
-}
-#undef FLANG_EXCLUDE_CODEGEN
-#endif
-
-} // namespace fir
diff --git a/flang/lib/Common/CMakeLists.txt b/flang/lib/Common/CMakeLists.txt
index c6f818ad27cd19..6e5bdfa2f6236b 100644
--- a/flang/lib/Common/CMakeLists.txt
+++ b/flang/lib/Common/CMakeLists.txt
@@ -12,7 +12,7 @@ endif()
 if(flang_vc AND LLVM_APPEND_VC_REV)
   set(flang_source_dir ${FLANG_SOURCE_DIR})
 endif()
- 
+
 # Create custom target to generate the VC revision include.
 add_custom_command(OUTPUT "${version_inc}"
   DEPENDS "${llvm_vc}" "${flang_vc}" "${generate_vcs_version_script}"
@@ -34,8 +34,8 @@ if(FLANG_VENDOR)
     PROPERTIES COMPILE_DEFINITIONS "FLANG_VENDOR=\"${FLANG_VENDOR} \"")
 endif()
 
-
 add_flang_library(FortranCommon
+  CommandLineOpts.cpp
   Fortran.cpp
   Fortran-features.cpp
   default-kinds.cpp
@@ -44,5 +44,6 @@ add_flang_library(FortranCommon
   ${version_inc}
 
   LINK_COMPONENTS
+  Passes
   Support
 )
diff --git a/flang/lib/Common/CommandLineOpts.cpp b/flang/lib/Common/CommandLineOpts.cpp
new file mode 100644
index 00000000000000..f77863bd77525d
--- /dev/null
+++ b/flang/lib/Common/CommandLineOpts.cpp
@@ -0,0 +1,67 @@
+//===-- CommandLineOpts.cpp -- shared command line options ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+/// This file defines some shared command-line options that can be used when
+/// debugging the test tools.
+
+#include "flang/Common/CommandLineOpts.h"
+
+using namespace llvm;
+
+#define DisableOption(DOName, DOOption, DODescription) \
+  cl::opt<bool> disable##DOName("disable-" DOOption, \
+      cl::desc("disable " DODescription " pass"), cl::init(false), cl::Hidden)
+#define EnableOption(EOName, EOOption, EODescription) \
+  cl::opt<bool> enable##EOName("enable-" EOOption, \
+      cl::desc("enable " EODescription " pass"), cl::init(false), cl::Hidden)
+
+cl::opt<bool> dynamicArrayStackToHeapAllocation("fdynamic-heap-array",
+    cl::desc("place all array allocations of dynamic size on the heap"),
+    cl::init(false), cl::Hidden);
+
+cl::opt<std::size_t> arrayStackAllocationThreshold("fstack-array-size",
+    cl::desc(
+        "place all array allocations more than <size> elements on the heap"),
+    cl::init(~static_cast<std::size_t>(0)), cl::Hidden);
+
+cl::opt<bool> ignoreMissingTypeDescriptors("ignore-missing-type-desc",
+    cl::desc("ignore failures to find derived type descriptors when "
+             "translating FIR to LLVM"),
+    cl::init(false), cl::Hidden);
+
+OptimizationLevel defaultOptLevel{OptimizationLevel::O0};
+
+codegenoptions::DebugInfoKind noDebugInfo{codegenoptions::NoDebugInfo};
+
+/// Optimizer Passes
+DisableOption(CfgConversion, "cfg-conversion", "disable FIR to CFG pass");
+DisableOption(FirAvc, "avc", "array value copy analysis and transformation");
+DisableOption(
+    FirMao, "memory-allocation-opt", "memory allocation optimization");
+
+DisableOption(FirAliasTags, "fir-alias-tags", "fir alias analysis");
+cl::opt<bool> useOldAliasTags("use-old-alias-tags",
+    cl::desc("Use a single TBAA tree for all functions and do not use "
+             "the FIR alias tags pass"),
+    cl::init(false), cl::Hidden);
+
+/// CodeGen Passes
+DisableOption(CodeGenRewrite, "codegen-rewrite", "rewrite FIR for codegen");
+DisableOption(TargetRewrite, "target-rewrite", "rewrite FIR for target");
+DisableOption(DebugInfo, "debug-info", "Add debug info");
+DisableOption(FirToLlvmIr, "fir-to-llvmir", "FIR to LLVM-IR dialect");
+DisableOption(LlvmIrToLlvm, "llvm", "conversion to LLVM");
+DisableOption(BoxedProcedureRewrite, "boxed-procedure-rewrite",
+    "rewrite boxed procedures");
+
+DisableOption(ExternalNameConversion, "external-name-interop",
+    "convert names with external convention");
+EnableOption(ConstantArgumentGlobalisation, "constant-argument-globalisation",
+    "the local constant argument to global constant conversion");
+DisableOption(CompilerGeneratedNamesConversion, "compiler-generated-names",
+    "replace special symbols in compiler generated names");
diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt
index ecdcc73d61ec1f..412435fec4ad1d 100644
--- a/flang/lib/Frontend/CMakeLists.txt
+++ b/flang/lib/Frontend/CMakeLists.txt
@@ -35,6 +35,7 @@ add_flang_library(flangFrontend
   FIRSupport
   FIRBuilder
   FIRCodeGen
+  FIRPasses
   FIRTransforms
   HLFIRDialect
   HLFIRTransforms
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 267c3ceb44f33e..4a52edc436e0ed 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -21,6 +21,7 @@
 #include "flang/Lower/Support/Verifier.h"
 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
+#include "flang/Optimizer/Passes/Pipelines.h"
 #include "flang/Optimizer/Support/DataLayout.h"
 #include "flang/Optimizer/Support/InitFIR.h"
 #include "flang/Optimizer/Support/Utils.h"
@@ -77,8 +78,6 @@
 #include <memory>
 #include <system_error>
 
-#include "flang/Tools/CLOptions.inc"
-
 namespace llvm {
 extern cl::opt<bool> PrintPipelinePasses;
 } // namespace llvm
diff --git a/flang/lib/Optimizer/CMakeLists.txt b/flang/lib/Optimizer/CMakeLists.txt
index dd153ac33c0fbb..5354d7181e6516 100644
--- a/flang/lib/Optimizer/CMakeLists.txt
+++ b/flang/lib/Optimizer/CMakeLists.txt
@@ -1,8 +1,9 @@
+add_subdirectory(Analysis)
 add_subdirectory(Builder)
 add_subdirectory(CodeGen)
 add_subdirectory(Dialect)
 add_subdirectory(HLFIR)
+add_subdirectory(OpenMP)
+add_subdirectory(Passes)
 add_subdirectory(Support)
 add_subdirectory(Transforms)
-add_subdirectory(Analysis)
-add_subdirectory(OpenMP)
diff --git a/flang/lib/Optimizer/Passes/CMakeLists.txt b/flang/lib/Optimizer/Passes/CMakeLists.txt
new file mode 100644
index 00000000000000..b40885572b4c81
--- /dev/null
+++ b/flang/lib/Optimizer/Passes/CMakeLists.txt
@@ -0,0 +1,21 @@
+add_flang_library(FIRPasses
+  Pipelines.cpp
+
+  DEPENDS
+  FortranCommon
+
+  LINK_LIBS
+  FIRCodeGen
+  FIRTransforms
+  FlangOpenMPTransforms
+  FortranCommon
+  HLFIRTransforms
+  MLIRPass
+  MLIRReconcileUnrealizedCasts
+  MLIRSCFToControlFlow
+  MLIRSupport
+  MLIRTransforms
+
+  LINK_COMPONENTS
+  Passes
+)
diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp
new file mode 100644
index 00000000000000..722c0db357281c
--- /dev/null
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -0,0 +1,330 @@
+//===-- Pipelines.cpp -- FIR pass pipelines ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+/// This file defines some utilties to setup FIR pass pipelines. These are
+/// common to flang and the test tools.
+
+#include "flang/Optimizer/Passes/Pipelines.h"
+
+namespace {
+
+static void addNestedPassToAllTopLevelOperations(mlir::PassManager &pm,
+                                                 PassConstructor ctor) {
+  addNestedPassToOps<mlir::func::FuncOp, mlir::omp::DeclareReductionOp,
+                     mlir::omp::PrivateClauseOp, fir::GlobalOp>(pm, ctor);
+}
+
+static void
+addNestedPassToAllTopLevelOperationsConditionally(mlir::PassManager &pm,
+                                                  llvm::cl::opt<bool> &disabled,
+                                                  PassConstructor ctor) {
+  if (!disabled)
+    addNestedPassToAllTopLevelOperations(pm, ctor);
+}
+
+} // namespace
+
+namespace fir {
+
+// Add MLIR Canonicalizer pass with region simplification disabled.
+// FIR does not support the promotion of some SSA value to block arguments (or
+// into arith.select operands) that may be done by mlir block merging in the
+// region simplification (e.g., !fir.shape<> SSA values are not supported as
+// block arguments).
+// Aside from the fir.shape issue, moving some abstract SSA value into block
+// arguments may have a heavy cost since it forces their code generation that
+// may be expensive (array temporary). The MLIR pass does not take these
+// extra costs into account when doing block merging.
+static void
+addCanonicalizerPassWithoutRegionSimplification(mlir::OpPassManager &pm) {
+  mlir::GreedyRewriteConfig config;
+  config.enableRegionSimplification = mlir::GreedySimplifyRegionLevel::Disabled;
+  pm.addPass(mlir::createCanonicalizerPass(config));
+}
+
+static void addCfgConversionPass(mlir::PassManager &pm,
+                                 const MLIRToLLVMPassPipelineConfig &config) {
+  if (config.NSWOnLoopVarInc)
+    addNestedPassToAllTopLevelOperationsConditionally(
+        pm, disableCfgConversion, fir::createCFGConversionPassWithNSW);
+  else
+    addNestedPassToAllTopLevelOperationsConditionally(pm, disableCfgConversion,
+                                                      fir::createCFGConversion);
+}
+
+static void addAVC(mlir::PassManager &pm,
+                   const llvm::OptimizationLevel &optLevel) {
+  ArrayValueCopyOptions options;
+  options.optimizeConflicts = optLevel.isOptimizingForSpeed();
+  addNestedPassConditionally<mlir::func::FuncOp>(
+      pm, disableFirAvc, [&]() { return createArrayValueCopyPass(options); });
+}
+
+static void addMemoryAllocationOpt(mlir::PassManager &pm) {
+  addNestedPassConditionally<mlir::func::FuncOp>(pm, disableFirMao, [&]() {
+    return fir::createMemoryAllocationOpt(
+        {dynamicArrayStackToHeapAllocation, arrayStackAllocationThreshold});
+  });
+}
+
+static void addCodeGenRewritePass(mlir::PassManager &pm, bool preserveDeclare) {
+  fir::CodeGenRewriteOptions options;
+  options.preserveDeclare = preserveDeclare;
+  addPassConditionally(pm, disableCodeGenRewrite,
+                       [&]() { return fir::createCodeGenRewrite(options); });
+}
+
+static void addTargetRewritePass(mlir::PassManager &pm) {
+  addPassConditionally(pm, disableTargetRewrite,
+                       []() { return fir::createTargetRewritePass(); });
+}
+
+static mlir::LLVM::DIEmissionKind
+getEmissionKind(llvm::codegenoptions::DebugInfoKind kind) {
+  switch (kind) {
+  case llvm::codegenoptions::DebugInfoKind::FullDebugInfo:
+    return mlir::LLVM::DIEmissionKind::Full;
+  case llvm::codegenoptions::DebugInfoKind::DebugLineTablesOnly:
+    return mlir::LLVM::DIEmissionKind::LineTablesOnly;
+  default:
+    return mlir::LLVM::DIEmissionKind::None;
+  }
+}
+
+void addDebugInfoPass(mlir::PassManager &pm,
+                      llvm::codegenoptions::DebugInfoKind debugLevel,
+                      llvm::OptimizationLevel optLevel,
+                      llvm::StringRef inputFilename) {
+  fir::AddDebugInfoOptions options;
+  options.debugLevel = getEmissionKind(debugLevel);
+  options.isOptimized = optLevel != llvm::OptimizationLevel::O0;
+  options.inputFilename = inputFilename;
+  addPassConditionally(pm, disableDebugInfo,
+                       [&]() { return fir::createAddDebugInfoPass(options); });
+}
+
+void addFIRToLLVMPass(mlir::PassManager &pm,
+                      const MLIRToLLVMPassPipelineConfig &config) {
+  fir::FIRToLLVMPassOptions options;
+  options.ignoreMissingTypeDescriptors = ignoreMissingTypeDescriptors;
+  options.applyTBAA = config.AliasAnalysis;
+  options.forceUnifiedTBAATree = useOldAliasTags;
+  options.typeDescriptorsRenamedForAssembly =
+      !disableCompilerGeneratedNamesConversion;
+  addPassConditionally(pm, disableFirToLlvmIr,
+                       [&]() { return fir::createFIRToLLVMPass(options); });
+  // The dialect conversion framework may leave dead unrealized_conversion_cast
+  // ops behind, so run reconcile-unrealized-casts to clean them up.
+  addPassConditionally(pm, disableFirToLlvmIr, [&]() {
+    return mlir::createReconcileUnrealizedCastsPass();
+  });
+}
+
+void addLLVMDialectToLLVMPass(mlir::PassManager &pm,
+                              llvm::raw_ostream &output) {
+  addPassConditionally(pm, disableLlvmIrToLlvm, [&]() {
+    return fir::createLLVMDialectToLLVMPass(output);
+  });
+}
+
+static void addBoxedProcedurePass(mlir::PassManager &pm) {
+  addPassConditionally(pm, disableBoxedProcedureRewrite,
+                       [&]() { return fir::createBoxedProcedurePass(); });
+}
+
+static void addExternalNameConversionPass(mlir::PassManager &pm,
+                                          bool appendUnderscore = true) {
+  addPassConditionally(pm, disableExternalNameConversion, [&]() {
+    return fir::createExternalNameConversion({appendUnderscore});
+  });
+}
+
+static void addCompilerGeneratedNamesConversionPass(mlir::PassManager &pm) {
+  addPassConditionally(pm, disableCompilerGeneratedNamesConversion, [&]() {
+    return fir::createCompilerGeneratedNamesConversion();
+  });
+}
+
+// Use inliner extension point callback to register the default inliner pass.
+void registerDefaultInlinerPass(MLIRToLLVMPassPipelineConfig &config) {
+  config.registerFIRInlinerCallback(
+      [](mlir::PassManager &pm, llvm::OptimizationLevel level) {
+        llvm::StringMap<mlir::OpPassManager> pipelines;
+        // The default inliner pass adds the canonicalizer pass with the default
+        // configuration.
+        pm.addPass(mlir::createInlinerPass(
+            pipelines, addCanonicalizerPassWithoutRegionSimplification));
+      });
+}
+
+/// Create a pass pipeline for running default optimization passes for
+/// incremental conversion of FIR.
+///
+/// \param pm - MLIR pass manager that will hold the pipeline definition
+void createDefaultFIROptimizerPassPipeline(mlir::PassManager &pm,
+                                           MLIRToLLVMPassPipelineConfig &pc) {
+  // Early Optimizer EP Callback
+  pc.invokeFIROptEarlyEPCallbacks(pm, pc.OptLevel);
+
+  // simplify the IR
+  mlir::GreedyRewriteConfig config;
+  config.enableRegionSimplification = mlir::GreedySimplifyRegionLevel::Disabled;
+  pm.addPass(mlir::createCSEPass());
+  fir::addAVC(pm, pc.OptLevel);
+  addNestedPassToAllTopLevelOperations(pm, fir::createCharacterConversion);
+  pm.addPass(mlir::createCanonicalizerPass(config));
+  pm.addPass(fir::createSimplifyRegionLite());
+  if (pc.OptLevel.isOptimizingForSpeed()) {
+    // These passes may increase code size.
+    pm.addPass(fir::createSimplifyIntrinsics());
+    pm.addPass(fir::createAlgebraicSimplificationPass(config));
+    if (enableConstantArgumentGlobalisation)
+      pm.addPass(fir::createConstantArgumentGlobalisationOpt());
+  }
+
+  if (pc.LoopVersioning)
+    pm.addPass(fir::createLoopVersioning());
+
+  pm.addPass(mlir::createCSEPass());
+
+  if (pc.StackArrays)
+    pm.addPass(fir::createStackArrays());
+  else
+    fir::addMemoryAllocationOpt(pm);
+
+  // FIR Inliner Callback
+  pc.invokeFIRInlinerCallback(pm, pc.OptLevel);
+
+  pm.addPass(fir::createSimplifyRegionLite());
+  pm.addPass(mlir::createCSEPass());
+
+  // Polymorphic types
+  pm.addPass(fir::createPolymorphicOpConversion());
+  pm.addPass(fir::createAssumedRankOpConversion());
+
+  if (pc.AliasAnalysis && !disableFirAliasTags && !useOldAliasTags)
+    pm.addPass(fir::createAddAliasTags());
+
+  addNestedPassToAllTopLevelOperations(pm, fir::createStackReclaim);
+  // convert control flow to CFG form
+  fir::addCfgConversionPass(pm, pc);
+  pm.addPass(mlir::createConvertSCFToCFPass());
+
+  pm.addPass(mlir::createCanonicalizerPass(config));
+  pm.addPass(fir::createSimplifyRegionLite());
+  pm.addPass(mlir::createCSEPass());
+
+  // Last Optimizer EP Callback
+  pc.invokeFIROptLastEPCallbacks(pm, pc.OptLevel);
+}
+
+/// Create a pass pipeline for lowering from HLFIR to FIR
+///
+/// \param pm - MLIR pass manager that will hold the pipeline definition
+/// \param optLevel - optimization level used for creating FIR optimization
+///   passes pipeline
+void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
+                                  llvm::OptimizationLevel optLevel) {
+  if (optLevel.isOptimizingForSpeed()) {
+    addCanonicalizerPassWithoutRegionSimplification(pm);
+    addNestedPassToAllTopLevelOperations(pm,
+                                         hlfir::createSimplifyHLFIRIntrinsics);
+  }
+  addNestedPassToAllTopLevelOperations(pm, hlfir::createInlineElementals);
+  if (optLevel.isOptimizingForSpeed()) {
+    addCanonicalizerPassWithoutRegionSimplification(pm);
+    pm.addPass(mlir::createCSEPass());
+    addNestedPassToAllTopLevelOperations(pm,
+                                         hlfir::createOptimizedBufferization);
+  }
+  pm.addPass(hlfir::createLowerHLFIROrderedAssignments());
+  pm.addPass(hlfir::createLowerHLFIRIntrinsics());
+  pm.addPass(hlfir::createBufferizeHLFIR());
+  pm.addPass(hlfir::createConvertHLFIRtoFIR());
+}
+
+/// Create a pass pipeline for handling certain OpenMP transformations needed
+/// prior to FIR lowering.
+///
+/// WARNING: These passes must be run immediately after the lowering to ensure
+/// that the FIR is correct with respect to OpenMP operations/attributes.
+///
+/// \param pm - MLIR pass manager that will hold the pipeline definition.
+/// \param isTargetDevice - Whether code is being generated for a target device
+/// rather than the host device.
+void createOpenMPFIRPassPipeline(mlir::PassManager &pm, bool isTargetDevice) {
+  pm.addPass(flangomp::createMapInfoFinalizationPass());
+  pm.addPass(flangomp::createMarkDeclareTargetPass());
+  if (isTargetDevice)
+    pm.addPass(flangomp::createFunctionFilteringPass());
+}
+
+void createDebugPasses(mlir::PassManager &pm,
+                       llvm::codegenoptions::DebugInfoKind debugLevel,
+                       llvm::OptimizationLevel OptLevel,
+                       llvm::StringRef inputFilename) {
+  if (debugLevel != llvm::codegenoptions::NoDebugInfo)
+    addDebugInfoPass(pm, debugLevel, OptLevel, inputFilename);
+}
+
+void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
+                                         MLIRToLLVMPassPipelineConfig config,
+                                         llvm::StringRef inputFilename) {
+  fir::addBoxedProcedurePass(pm);
+  addNestedPassToAllTopLevelOperations(pm, fir::createAbstractResultOpt);
+  fir::addCodeGenRewritePass(
+      pm, (config.DebugInfo != llvm::codegenoptions::NoDebugInfo));
+  fir::addTargetRewritePass(pm);
+  fir::addCompilerGeneratedNamesConversionPass(pm);
+  fir::addExternalNameConversionPass(pm, config.Underscoring);
+  fir::createDebugPasses(pm, config.DebugInfo, config.OptLevel, inputFilename);
+
+  if (config.VScaleMin != 0)
+    pm.addPass(fir::createVScaleAttr({{config.VScaleMin, config.VScaleMax}}));
+
+  // Add function attributes
+  mlir::LLVM::framePointerKind::FramePointerKind framePointerKind;
+
+  if (config.FramePointerKind != llvm::FramePointerKind::None ||
+      config.NoInfsFPMath || config.NoNaNsFPMath || config.ApproxFuncFPMath ||
+      config.NoSignedZerosFPMath || config.UnsafeFPMath) {
+    if (config.FramePointerKind == llvm::FramePointerKind::NonLeaf)
+      framePointerKind =
+          mlir::LLVM::framePointerKind::FramePointerKind::NonLeaf;
+    else if (config.FramePointerKind == llvm::FramePointerKind::All)
+      framePointerKind = mlir::LLVM::framePointerKind::FramePointerKind::All;
+    else
+      framePointerKind = mlir::LLVM::framePointerKind::FramePointerKind::None;
+
+    pm.addPass(fir::createFunctionAttr(
+        {framePointerKind, config.NoInfsFPMath, config.NoNaNsFPMath,
+         config.ApproxFuncFPMath, config.NoSignedZerosFPMath,
+         config.UnsafeFPMath}));
+  }
+
+  fir::addFIRToLLVMPass(pm, config);
+}
+
+/// Create a pass pipeline for lowering from MLIR to LLVM IR
+///
+/// \param pm - MLIR pass manager that will hold the pipeline definition
+/// \param optLevel - optimization level used for creating FIR optimization
+///   passes pipeline
+void createMLIRToLLVMPassPipeline(mlir::PassManager &pm,
+                                  MLIRToLLVMPassPipelineConfig &config,
+                                  llvm::StringRef inputFilename) {
+  fir::createHLFIRToFIRPassPipeline(pm, config.OptLevel);
+
+  // Add default optimizer pass pipeline.
+  fir::createDefaultFIROptimizerPassPipeline(pm, config);
+
+  // Add codegen pass pipeline.
+  fir::createDefaultFIRCodeGenPassPipeline(pm, config, inputFilename);
+}
+
+} // namespace fir
diff --git a/flang/tools/bbc/CMakeLists.txt b/flang/tools/bbc/CMakeLists.txt
index 69316d4dc61de3..178745bbb24617 100644
--- a/flang/tools/bbc/CMakeLists.txt
+++ b/flang/tools/bbc/CMakeLists.txt
@@ -20,6 +20,7 @@ CUFAttrs
 CUFDialect
 FIRDialect
 FIRDialectSupport
+FIRPasses
 FIRSupport
 FIRTransforms
 FIRBuilder
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index dcff4503f16571..19d18001c5e1ec 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -233,7 +233,8 @@ static llvm::cl::opt<bool>
            llvm::cl::init(false));
 
 #define FLANG_EXCLUDE_CODEGEN
-#include "flang/Tools/CLOptions.inc"
+#include "flang/Common/CommandLineOpts.h"
+#include "flang/Optimizer/Passes/Pipelines.h"
 
 //===----------------------------------------------------------------------===//
 
diff --git a/flang/tools/tco/CMakeLists.txt b/flang/tools/tco/CMakeLists.txt
index 698a398547c773..8abd3740f3e5bd 100644
--- a/flang/tools/tco/CMakeLists.txt
+++ b/flang/tools/tco/CMakeLists.txt
@@ -12,12 +12,14 @@ target_link_libraries(tco PRIVATE
   FIRCodeGen
   FIRDialect
   FIRDialectSupport
+  FIRPasses
   FIRSupport
   FIRTransforms
   FIRBuilder
   HLFIRDialect
   HLFIRTransforms
   FlangOpenMPTransforms
+  FortranCommon
   ${dialect_libs}
   ${extension_libs}
   MLIRIR
diff --git a/flang/tools/tco/tco.cpp b/flang/tools/tco/tco.cpp
index a8c64333109aeb..2b6e240e483b25 100644
--- a/flang/tools/tco/tco.cpp
+++ b/flang/tools/tco/tco.cpp
@@ -70,7 +70,8 @@ static cl::opt<bool> codeGenLLVM(
     cl::desc("Run only CodeGen passes and translate FIR to LLVM IR"),
     cl::init(false));
 
-#include "flang/Tools/CLOptions.inc"
+#include "flang/Common/CommandLineOpts.h"
+#include "flang/Optimizer/Passes/Pipelines.h"
 
 static void printModule(mlir::ModuleOp mod, raw_ostream &output) {
   output << mod << '\n';



More information about the flang-commits mailing list