createMemoryAllocationPass(bool dynOnHeap, std::size_t maxStackSize);
std::unique_ptr<mlir::Pass> createAnnotateConstantOperandsPass();
std::unique_ptr<mlir::Pass> createSimplifyRegionLitePass();
+std::unique_ptr<mlir::Pass> createAlgebraicSimplificationPass();
// declarative passes
#define GEN_PASS_REGISTRATION
let constructor = "::fir::createSimplifyRegionLitePass()";
}
+def AlgebraicSimplification : Pass<"flang-algebraic-simplification"> {
+ let summary = "";
+ let description = [{
+ Run algebraic simplifications for Math/Complex/etc. dialect operations.
+ This is a flang specific pass, because we may want to "tune"
+ the rewrite patterns specifically for Fortran (e.g. increase
+ the limit for constant exponent value that defines the cases
+ when pow(x, constant) is transformed into a set of multiplications, etc.).
+ }];
+ let dependentDialects = [ "mlir::math::MathDialect" ];
+ let constructor = "::fir::createAlgebraicSimplificationPass()";
+}
+
#endif // FLANG_OPTIMIZER_TRANSFORMS_PASSES
#include "mlir/Transforms/Passes.h"
#include "flang/Optimizer/CodeGen/CodeGen.h"
#include "flang/Optimizer/Transforms/Passes.h"
+#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Support/CommandLine.h"
#define DisableOption(DOName, DOOption, DODescription) \
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};
+
/// Optimizer Passes
DisableOption(CfgConversion, "cfg-conversion", "disable FIR to CFG pass");
DisableOption(FirAvc, "avc", "array value copy analysis and transformation");
/// incremental conversion of FIR.
///
/// \param pm - MLIR pass manager that will hold the pipeline definition
-inline void createDefaultFIROptimizerPassPipeline(mlir::PassManager &pm) {
+inline void createDefaultFIROptimizerPassPipeline(
+ mlir::PassManager &pm, llvm::OptimizationLevel optLevel = defaultOptLevel) {
// simplify the IR
mlir::GreedyRewriteConfig config;
config.enableRegionSimplification = false;
pm.addNestedPass<mlir::func::FuncOp>(fir::createCharacterConversionPass());
pm.addPass(mlir::createCanonicalizerPass(config));
pm.addPass(fir::createSimplifyRegionLitePass());
+ // Algebraic simplifications may increase code size.
+ if (optLevel.isOptimizingForSpeed())
+ pm.addPass(fir::createAlgebraicSimplificationPass());
pm.addPass(mlir::createCSEPass());
fir::addMemoryAllocationOpt(pm);
/// Create a pass pipeline for lowering from MLIR to LLVM IR
///
/// \param pm - MLIR pass manager that will hold the pipeline definition
-inline void createMLIRToLLVMPassPipeline(mlir::PassManager &pm) {
+/// \param optLevel - optimization level used for creating FIR optimization
+/// passes pipeline
+inline void createMLIRToLLVMPassPipeline(
+ mlir::PassManager &pm, llvm::OptimizationLevel optLevel = defaultOptLevel) {
// Add default optimizer pass pipeline.
- fir::createDefaultFIROptimizerPassPipeline(pm);
+ fir::createDefaultFIROptimizerPassPipeline(pm, optLevel);
// Add codegen pass pipeline.
fir::createDefaultFIRCodeGenPassPipeline(pm);
#include "flang/Tools/CLOptions.inc"
+static llvm::OptimizationLevel
+mapToLevel(const Fortran::frontend::CodeGenOptions &opts) {
+ switch (opts.OptimizationLevel) {
+ default:
+ llvm_unreachable("Invalid optimization level!");
+ case 0:
+ return llvm::OptimizationLevel::O0;
+ case 1:
+ return llvm::OptimizationLevel::O1;
+ case 2:
+ return llvm::OptimizationLevel::O2;
+ case 3:
+ return llvm::OptimizationLevel::O3;
+ }
+}
+
// Lower the previously generated MLIR module into an LLVM IR module
void CodeGenAction::generateLLVMIR() {
assert(mlirModule && "The MLIR module has not been generated yet.");
CompilerInstance &ci = this->getInstance();
+ auto opts = ci.getInvocation().getCodeGenOpts();
+ llvm::OptimizationLevel level = mapToLevel(opts);
fir::support::loadDialects(*mlirCtx);
fir::support::registerLLVMTranslation(*mlirCtx);
pm.enableVerifier(/*verifyPasses=*/true);
// Create the pass pipeline
- fir::createMLIRToLLVMPassPipeline(pm);
+ fir::createMLIRToLLVMPassPipeline(pm, level);
mlir::applyPassManagerCLOptions(pm);
// run the pass manager
codeGenPasses.run(llvmModule);
}
-static llvm::OptimizationLevel
-mapToLevel(const Fortran::frontend::CodeGenOptions &opts) {
- switch (opts.OptimizationLevel) {
- default:
- llvm_unreachable("Invalid optimization level!");
- case 0:
- return llvm::OptimizationLevel::O0;
- case 1:
- return llvm::OptimizationLevel::O1;
- case 2:
- return llvm::OptimizationLevel::O2;
- case 3:
- return llvm::OptimizationLevel::O3;
- }
-}
-
void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
auto opts = getInstance().getInvocation().getCodeGenOpts();
llvm::OptimizationLevel level = mapToLevel(opts);
--- /dev/null
+//===- AlgebraicSimplification.cpp - Simplify algebraic expressions -------===//
+//
+// 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 a pass that applies algebraic simplifications
+// to operations of Math/Complex/etc. dialects that are used by Flang.
+// It is done as a Flang specific pass, because we may want to tune
+// the parameters of the patterns for Fortran programs.
+//===----------------------------------------------------------------------===//
+
+#include "PassDetail.h"
+#include "flang/Optimizer/Transforms/Passes.h"
+#include "mlir/Dialect/Math/Transforms/Passes.h"
+#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
+
+using namespace mlir;
+
+namespace {
+struct AlgebraicSimplification
+ : public fir::AlgebraicSimplificationBase<AlgebraicSimplification> {
+
+ void runOnOperation() override;
+};
+} // namespace
+
+void AlgebraicSimplification::runOnOperation() {
+ RewritePatternSet patterns(&getContext());
+ populateMathAlgebraicSimplificationPatterns(patterns);
+ (void)applyPatternsAndFoldGreedily(getOperation(), std::move(patterns));
+}
+
+std::unique_ptr<mlir::Pass> fir::createAlgebraicSimplificationPass() {
+ return std::make_unique<AlgebraicSimplification>();
+}
MemRefDataFlowOpt.cpp
RewriteLoop.cpp
SimplifyRegionLite.cpp
+ AlgebraicSimplification.cpp
DEPENDS
FIRBuilder
MLIRAffineUtils
MLIRFuncDialect
MLIRLLVMDialect
+ MLIRMathTransforms
MLIROpenACCDialect
MLIROpenMPDialect
FIRSupport
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/Math/IR/Math.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "mlir/Pass/Pass.h"
--- /dev/null
+! Test the MLIR pass pipeline
+
+! RUN: bbc --mlir-pass-statistics --mlir-pass-statistics-display=pipeline %s 2>&1 | FileCheck %s
+end program
+
+! CHECK: Pass statistics report
+
+! CHECK: Fortran::lower::VerifierPass
+! CHECK-NEXT: CSE
+! Ideally, we need an output with only the pass names, but
+! there is currently no way to get that, so in order to
+! guarantee that the passes are in the expected order
+! (i.e. use -NEXT) we have to check the statistics output as well.
+! CHECK-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+! CHECK-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+
+! CHECK-NEXT: 'func.func' Pipeline
+! CHECK-NEXT: ArrayValueCopy
+! CHECK-NEXT: CharacterConversion
+
+! CHECK-NEXT: Canonicalizer
+! CHECK-NEXT: SimplifyRegionLite
+! CHECK-NEXT: AlgebraicSimplification
+! CHECK-NEXT: CSE
+! CHECK-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+! CHECK-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+
+! CHECK-NEXT: 'func.func' Pipeline
+! CHECK-NEXT: MemoryAllocationOpt
+
+! CHECK-NEXT: Inliner
+! CHECK-NEXT: CSE
+! CHECK-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+! CHECK-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+
+! CHECK-NEXT: 'func.func' Pipeline
+! CHECK-NEXT: CFGConversion
+
+! CHECK-NEXT: SCFToControlFlow
+! CHECK-NEXT: Canonicalizer
+! CHECK-NEXT: SimplifyRegionLite
+! CHECK-NEXT: CSE
+! CHECK-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+! CHECK-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+! CHECK-NOT: LLVMIRLoweringPass
! Test the MLIR pass pipeline
-! RUN: %flang_fc1 -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -o - 2>&1 | FileCheck %s
+! RUN: %flang_fc1 -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline -o /dev/null %s 2>&1 | FileCheck --check-prefixes=ALL %s
+! -O0 is the default:
+! RUN: %flang_fc1 -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -O0 -o /dev/null 2>&1 | FileCheck --check-prefixes=ALL %s
+! RUN: %flang_fc1 -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -O2 -o /dev/null 2>&1 | FileCheck --check-prefixes=ALL,O2 %s
end program
-! CHECK: Pass statistics report
-
-! CHECK: CSE
-! CHECK-LABEL: 'func.func' Pipeline
-! CHECK: ArrayValueCopy
-! CHECK: CharacterConversion
-! CHECK: Canonicalizer
-! CHECK: SimplifyRegionLite
-! CHECK: CSE
-
-! CHECK-LABEL: 'func.func' Pipeline
-! CHECK: MemoryAllocationOpt
-! CHECK: Inliner
-! CHECK: CSE
-
-! CHECK-LABEL: 'func.func' Pipeline
-! CHECK: CFGConversion
-! CHECK: SCFToControlFlow
-! CHECK: Canonicalizer
-! CHECK: SimplifyRegionLite
-! CHECK: CSE
-! CHECK: BoxedProcedurePass
-
-! CHECK-LABEL: 'func.func' Pipeline
-! CHECK: AbstractResultOpt
-! CHECK: CodeGenRewrite
-! CHECK: TargetRewrite
-! CHECK: ExternalNameConversion
-! CHECK: FIRToLLVMLowering
-! CHECK-NOT: LLVMIRLoweringPass
+! ALL: Pass statistics report
+
+! ALL: Fortran::lower::VerifierPass
+! ALL-NEXT: CSE
+! Ideally, we need an output with only the pass names, but
+! there is currently no way to get that, so in order to
+! guarantee that the passes are in the expected order
+! (i.e. use -NEXT) we have to check the statistics output as well.
+! ALL-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+! ALL-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+
+! ALL-NEXT: 'func.func' Pipeline
+! ALL-NEXT: ArrayValueCopy
+! ALL-NEXT: CharacterConversion
+
+! ALL-NEXT: Canonicalizer
+! ALL-NEXT: SimplifyRegionLite
+! O2-NEXT: AlgebraicSimplification
+! ALL-NEXT: CSE
+! ALL-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+! ALL-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+
+! ALL-NEXT: 'func.func' Pipeline
+! ALL-NEXT: MemoryAllocationOpt
+
+! ALL-NEXT: Inliner
+! ALL-NEXT: CSE
+! ALL-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+! ALL-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+
+! ALL-NEXT: 'func.func' Pipeline
+! ALL-NEXT: CFGConversion
+
+! ALL-NEXT: SCFToControlFlow
+! ALL-NEXT: Canonicalizer
+! ALL-NEXT: SimplifyRegionLite
+! ALL-NEXT: CSE
+! ALL-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+! ALL-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+! ALL-NEXT: BoxedProcedurePass
+
+! ALL-NEXT: 'func.func' Pipeline
+! ALL-NEXT: AbstractResultOpt
+
+! ALL-NEXT: CodeGenRewrite
+! ALL-NEXT: (S) 0 num-dce'd - Number of operations eliminated
+! ALL-NEXT: TargetRewrite
+! ALL-NEXT: ExternalNameConversion
+! ALL-NEXT: FIRToLLVMLowering
+! ALL-NOT: LLVMIRLoweringPass
// PASSES: Pass statistics report
-// PASSES: CSE
-// PASSES-LABEL: 'func.func' Pipeline
-// PASSES: ArrayValueCopy
-// PASSES: CharacterConversion
-// PASSES: Canonicalizer
-// PASSES: SimplifyRegionLite
-// PASSES: CSE
-
-// PASSES-LABEL: 'func.func' Pipeline
-// PASSES: MemoryAllocationOpt
-// PASSES: Inliner
-// PASSES: CSE
-
-// PASSES-LABEL: 'func.func' Pipeline
-// PASSES: CFGConversion
-// PASSES: SCFToControlFlow
-// PASSES: Canonicalizer
-// PASSES: SimplifyRegionLite
-// PASSES: CSE
-// PASSES: BoxedProcedurePass
-
-// PASSES-LABEL: 'func.func' Pipeline
-// PASSES: AbstractResultOpt
-// PASSES: CodeGenRewrite
-// PASSES: TargetRewrite
-// PASSES: FIRToLLVMLowering
-// PASSES: LLVMIRLoweringPass
+// PASSES: CSE
+// PASSES-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+// PASSES-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+
+// PASSES-NEXT: 'func.func' Pipeline
+// PASSES-NEXT: ArrayValueCopy
+// PASSES-NEXT: CharacterConversion
+
+// PASSES-NEXT: Canonicalizer
+// PASSES-NEXT: SimplifyRegionLite
+// PASSES-NEXT: AlgebraicSimplification
+// PASSES-NEXT: CSE
+// PASSES-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+// PASSES-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+
+// PASSES-NEXT: 'func.func' Pipeline
+// PASSES-NEXT: MemoryAllocationOpt
+
+// PASSES-NEXT: Inliner
+// PASSES-NEXT: CSE
+// PASSES-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+// PASSES-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+
+// PASSES-NEXT: 'func.func' Pipeline
+// PASSES-NEXT: CFGConversion
+
+// PASSES-NEXT: SCFToControlFlow
+// PASSES-NEXT: Canonicalizer
+// PASSES-NEXT: SimplifyRegionLite
+// PASSES-NEXT: CSE
+// PASSES-NEXT: (S) 0 num-cse'd - Number of operations CSE'd
+// PASSES-NEXT: (S) 0 num-dce'd - Number of operations DCE'd
+// PASSES-NEXT: BoxedProcedurePass
+
+// PASSES-NEXT: 'func.func' Pipeline
+// PASSES-NEXT: AbstractResultOpt
+
+// PASSES-NEXT: CodeGenRewrite
+// PASSES-NEXT: (S) 0 num-dce'd - Number of operations eliminated
+// PASSES-NEXT: TargetRewrite
+// PASSES-NEXT: FIRToLLVMLowering
+// PASSES-NEXT: LLVMIRLoweringPass
#include "mlir/Pass/PassRegistry.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
#include "mlir/Transforms/Passes.h"
+#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
// run the default canned pipeline
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
- // Add default optimizer pass pipeline.
- fir::createDefaultFIROptimizerPassPipeline(pm);
+ // Add O2 optimizer pass pipeline.
+ fir::createDefaultFIROptimizerPassPipeline(pm, llvm::OptimizationLevel::O2);
}
if (mlir::succeeded(pm.run(mlirModule))) {
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Transforms/Passes.h"
+#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
if (mlir::failed(passPipeline.addToPipeline(pm, errorHandler)))
return mlir::failure();
} else {
- fir::createMLIRToLLVMPassPipeline(pm);
+ // Run tco with O2 by default.
+ fir::createMLIRToLLVMPassPipeline(pm, llvm::OptimizationLevel::O2);
fir::addLLVMDialectToLLVMPass(pm, out.os());
}