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/Optimizer/Passes/CommandLineOpts.h b/flang/include/flang/Optimizer/Passes/CommandLineOpts.h new file mode 100644 index 00000000000000..1cfaf285e75e64 --- /dev/null +++ b/flang/include/flang/Optimizer/Passes/CommandLineOpts.h @@ -0,0 +1,60 @@ +//===-- CommandLineOpts.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_OPTIMIZER_PASSES_COMMANDLINEOPTS_H +#define FORTRAN_OPTIMIZER_PASSES_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 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 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 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 disableCfgConversion; +extern llvm::cl::opt disableFirAvc; +extern llvm::cl::opt disableFirMao; + +extern llvm::cl::opt disableFirAliasTags; +extern llvm::cl::opt useOldAliasTags; + +/// CodeGen Passes +extern llvm::cl::opt disableCodeGenRewrite; +extern llvm::cl::opt disableTargetRewrite; +extern llvm::cl::opt disableDebugInfo; +extern llvm::cl::opt disableFirToLlvmIr; +extern llvm::cl::opt disableLlvmIrToLlvm; +extern llvm::cl::opt disableBoxedProcedureRewrite; + +extern llvm::cl::opt disableExternalNameConversion; +extern llvm::cl::opt enableConstantArgumentGlobalisation; +extern llvm::cl::opt disableCompilerGeneratedNamesConversion; + +#endif // FORTRAN_OPTIMIZER_PASSES_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..3b54ac38838587 --- /dev/null +++ b/flang/include/flang/Optimizer/Passes/Pipelines.h @@ -0,0 +1,162 @@ +//===-- 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/Optimizer/CodeGen/CodeGen.h" +#include "flang/Optimizer/HLFIR/Passes.h" +#include "flang/Optimizer/OpenMP/Passes.h" +#include "flang/Optimizer/Passes/CommandLineOpts.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 fir { + +using PassConstructor = std::unique_ptr(); + +template +void addNestedPassToOps(mlir::PassManager &pm, PassConstructor ctor) { + pm.addNestedPass(ctor()); +} + +template > +void addNestedPassToOps(mlir::PassManager &pm, PassConstructor ctor) { + addNestedPassToOps(pm, ctor); + addNestedPassToOps(pm, ctor); +} + +/// Generic for adding a pass to the pass manager if it is not disabled. +template +void addPassConditionally(mlir::PassManager &pm, llvm::cl::opt &disabled, + F ctor) { + if (!disabled) + pm.addPass(ctor()); +} + +template +void addNestedPassConditionally(mlir::PassManager &pm, + llvm::cl::opt &disabled, F ctor) { + if (!disabled) + pm.addNestedPass(ctor()); +} + +void addNestedPassToAllTopLevelOperations(mlir::PassManager &pm, + PassConstructor ctor); + +void addNestedPassToAllTopLevelOperationsConditionally( + mlir::PassManager &pm, llvm::cl::opt &disabled, PassConstructor ctor); + +/// 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. +void addCanonicalizerPassWithoutRegionSimplification(mlir::OpPassManager &pm); + +void addCfgConversionPass(mlir::PassManager &pm, + const MLIRToLLVMPassPipelineConfig &config); + +void addAVC(mlir::PassManager &pm, const llvm::OptimizationLevel &optLevel); + +void addMemoryAllocationOpt(mlir::PassManager &pm); + +void addCodeGenRewritePass(mlir::PassManager &pm, bool preserveDeclare); + +void addTargetRewritePass(mlir::PassManager &pm); + +mlir::LLVM::DIEmissionKind +getEmissionKind(llvm::codegenoptions::DebugInfoKind kind); + +void addBoxedProcedurePass(mlir::PassManager &pm); + +void addExternalNameConversionPass(mlir::PassManager &pm, + bool appendUnderscore = true); + +void addCompilerGeneratedNamesConversionPass(mlir::PassManager &pm); + +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 - -#define DisableOption(DOName, DOOption, DODescription) \ - static llvm::cl::opt 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 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 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 arrayStackAllocationThreshold( - "fstack-array-size", - llvm::cl::desc( - "place all array allocations more than elements on the heap"), - llvm::cl::init(~static_cast(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 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 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(); - -template -void addNestedPassToOps(mlir::PassManager &pm, PassConstructor ctor) { - pm.addNestedPass(ctor()); -} - -template > -void addNestedPassToOps(mlir::PassManager &pm, PassConstructor ctor) { - addNestedPassToOps(pm, ctor); - addNestedPassToOps(pm, ctor); -} - -void addNestedPassToAllTopLevelOperations( - mlir::PassManager &pm, PassConstructor ctor) { - addNestedPassToOps(pm, ctor); -} - -void addNestedPassToAllTopLevelOperationsConditionally(mlir::PassManager &pm, - llvm::cl::opt &disabled, PassConstructor ctor) { - if (!disabled) - addNestedPassToAllTopLevelOperations(pm, ctor); -} - -/// Generic for adding a pass to the pass manager if it is not disabled. -template -void addPassConditionally( - mlir::PassManager &pm, llvm::cl::opt &disabled, F ctor) { - if (!disabled) - pm.addPass(ctor()); -} - -template -void addNestedPassConditionally( - mlir::PassManager &pm, llvm::cl::opt &disabled, F ctor) { - if (!disabled) - pm.addNestedPass(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( - pm, disableFirAvc, [&]() { return createArrayValueCopyPass(options); }); -} - -inline void addMemoryAllocationOpt(mlir::PassManager &pm) { - addNestedPassConditionally(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 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..6579e9cdf82491 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,7 +34,6 @@ if(FLANG_VENDOR) PROPERTIES COMPILE_DEFINITIONS "FLANG_VENDOR=\"${FLANG_VENDOR} \"") endif() - add_flang_library(FortranCommon Fortran.cpp Fortran-features.cpp diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt index ecdcc73d61ec1f..ebfdb14b534bb4 100644 --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -38,6 +38,7 @@ add_flang_library(flangFrontend FIRTransforms HLFIRDialect HLFIRTransforms + flangPasses FlangOpenMPTransforms MLIRTransforms MLIRBuiltinToLLVMIRTranslation 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 #include -#include "flang/Tools/CLOptions.inc" - namespace llvm { extern cl::opt 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..3df988940e005f --- /dev/null +++ b/flang/lib/Optimizer/Passes/CMakeLists.txt @@ -0,0 +1,22 @@ +add_flang_library(flangPasses + CommandLineOpts.cpp + 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/CommandLineOpts.cpp b/flang/lib/Optimizer/Passes/CommandLineOpts.cpp new file mode 100644 index 00000000000000..f95a280883cbaf --- /dev/null +++ b/flang/lib/Optimizer/Passes/CommandLineOpts.cpp @@ -0,0 +1,73 @@ +//===-- 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/Optimizer/Passes/CommandLineOpts.h" + +using namespace llvm; + +#define DisableOption(DOName, DOOption, DODescription) \ + cl::opt disable##DOName("disable-" DOOption, \ + cl::desc("disable " DODescription " pass"), \ + cl::init(false), cl::Hidden) +#define EnableOption(EOName, EOOption, EODescription) \ + cl::opt enable##EOName("enable-" EOOption, \ + cl::desc("enable " EODescription " pass"), \ + cl::init(false), cl::Hidden) + +cl::opt dynamicArrayStackToHeapAllocation( + "fdynamic-heap-array", + cl::desc("place all array allocations of dynamic size on the heap"), + cl::init(false), cl::Hidden); + +cl::opt arrayStackAllocationThreshold( + "fstack-array-size", + cl::desc( + "place all array allocations more than elements on the heap"), + cl::init(~static_cast(0)), cl::Hidden); + +cl::opt 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 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/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp new file mode 100644 index 00000000000000..3fa5c54403bd8c --- /dev/null +++ b/flang/lib/Optimizer/Passes/Pipelines.cpp @@ -0,0 +1,314 @@ +//===-- 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 fir { + +void addNestedPassToAllTopLevelOperations(mlir::PassManager &pm, + PassConstructor ctor) { + addNestedPassToOps(pm, ctor); +} + +void addNestedPassToAllTopLevelOperationsConditionally( + mlir::PassManager &pm, llvm::cl::opt &disabled, + PassConstructor ctor) { + if (!disabled) + addNestedPassToAllTopLevelOperations(pm, ctor); +} + +void addCanonicalizerPassWithoutRegionSimplification(mlir::OpPassManager &pm) { + mlir::GreedyRewriteConfig config; + config.enableRegionSimplification = mlir::GreedySimplifyRegionLevel::Disabled; + pm.addPass(mlir::createCanonicalizerPass(config)); +} + +void addCfgConversionPass(mlir::PassManager &pm, + const MLIRToLLVMPassPipelineConfig &config) { + if (config.NSWOnLoopVarInc) + addNestedPassToAllTopLevelOperationsConditionally( + pm, disableCfgConversion, fir::createCFGConversionPassWithNSW); + else + addNestedPassToAllTopLevelOperationsConditionally(pm, disableCfgConversion, + fir::createCFGConversion); +} + +void addAVC(mlir::PassManager &pm, const llvm::OptimizationLevel &optLevel) { + ArrayValueCopyOptions options; + options.optimizeConflicts = optLevel.isOptimizingForSpeed(); + addNestedPassConditionally( + pm, disableFirAvc, [&]() { return createArrayValueCopyPass(options); }); +} + +void addMemoryAllocationOpt(mlir::PassManager &pm) { + addNestedPassConditionally(pm, disableFirMao, [&]() { + return fir::createMemoryAllocationOpt( + {dynamicArrayStackToHeapAllocation, arrayStackAllocationThreshold}); + }); +} + +void addCodeGenRewritePass(mlir::PassManager &pm, bool preserveDeclare) { + fir::CodeGenRewriteOptions options; + options.preserveDeclare = preserveDeclare; + addPassConditionally(pm, disableCodeGenRewrite, + [&]() { return fir::createCodeGenRewrite(options); }); +} + +void addTargetRewritePass(mlir::PassManager &pm) { + addPassConditionally(pm, disableTargetRewrite, + []() { return fir::createTargetRewritePass(); }); +} + +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); + }); +} + +void addBoxedProcedurePass(mlir::PassManager &pm) { + addPassConditionally(pm, disableBoxedProcedureRewrite, + [&]() { return fir::createBoxedProcedurePass(); }); +} + +void addExternalNameConversionPass(mlir::PassManager &pm, + bool appendUnderscore) { + addPassConditionally(pm, disableExternalNameConversion, [&]() { + return fir::createExternalNameConversion({appendUnderscore}); + }); +} + +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 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..18fa7ac1d6cdc9 100644 --- a/flang/tools/bbc/CMakeLists.txt +++ b/flang/tools/bbc/CMakeLists.txt @@ -1,14 +1,14 @@ set(LLVM_LINK_COMPONENTS -Passes -AllTargetsCodeGens -AllTargetsDescs -AllTargetsInfos -TargetParser + Passes + AllTargetsCodeGens + AllTargetsDescs + AllTargetsInfos + TargetParser ) add_flang_tool(bbc bbc.cpp -DEPENDS -FIROptCodeGenPassIncGen + DEPENDS + FIROptCodeGenPassIncGen ) llvm_update_compile_flags(bbc) @@ -16,23 +16,24 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) get_property(extension_libs GLOBAL PROPERTY MLIR_EXTENSION_LIBS) target_link_libraries(bbc PRIVATE -CUFAttrs -CUFDialect -FIRDialect -FIRDialectSupport -FIRSupport -FIRTransforms -FIRBuilder -HLFIRDialect -HLFIRTransforms -FlangOpenMPTransforms -${dialect_libs} -${extension_libs} -MLIRAffineToStandard -MLIRSCFToControlFlow -FortranCommon -FortranParser -FortranEvaluate -FortranSemantics -FortranLower + CUFAttrs + CUFDialect + FIRDialect + FIRDialectSupport + FIRSupport + FIRTransforms + FIRBuilder + HLFIRDialect + HLFIRTransforms + flangPasses + FlangOpenMPTransforms + ${dialect_libs} + ${extension_libs} + MLIRAffineToStandard + MLIRSCFToControlFlow + FortranCommon + FortranParser + FortranEvaluate + FortranSemantics + FortranLower ) diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp index dcff4503f16571..ac3de35319106f 100644 --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -233,7 +233,8 @@ static llvm::cl::opt llvm::cl::init(false)); #define FLANG_EXCLUDE_CODEGEN -#include "flang/Tools/CLOptions.inc" +#include "flang/Optimizer/Passes/CommandLineOpts.h" +#include "flang/Optimizer/Passes/Pipelines.h" //===----------------------------------------------------------------------===// diff --git a/flang/tools/tco/CMakeLists.txt b/flang/tools/tco/CMakeLists.txt index 698a398547c773..aac80437ee11d9 100644 --- a/flang/tools/tco/CMakeLists.txt +++ b/flang/tools/tco/CMakeLists.txt @@ -17,7 +17,9 @@ target_link_libraries(tco PRIVATE FIRBuilder HLFIRDialect HLFIRTransforms + flangPasses FlangOpenMPTransforms + FortranCommon ${dialect_libs} ${extension_libs} MLIRIR diff --git a/flang/tools/tco/tco.cpp b/flang/tools/tco/tco.cpp index a8c64333109aeb..5c373c4e85258c 100644 --- a/flang/tools/tco/tco.cpp +++ b/flang/tools/tco/tco.cpp @@ -70,7 +70,8 @@ static cl::opt codeGenLLVM( cl::desc("Run only CodeGen passes and translate FIR to LLVM IR"), cl::init(false)); -#include "flang/Tools/CLOptions.inc" +#include "flang/Optimizer/Passes/CommandLineOpts.h" +#include "flang/Optimizer/Passes/Pipelines.h" static void printModule(mlir::ModuleOp mod, raw_ostream &output) { output << mod << '\n';