| // Copyright 2019 The IREE Authors |
| // |
| // Licensed 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 |
| |
| #include "compiler/plugins/input/StableHLO/Conversion/Passes.h" |
| |
| #include "compiler/plugins/input/StableHLO/Conversion/Preprocessing/Passes.h" |
| #include "iree/compiler/Dialect/Util/Transforms/Passes.h" |
| #include "iree/compiler/InputConversion/Common/Passes.h" |
| #include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h" |
| #include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h" |
| #include "mlir/Conversion/ShapeToStandard/ShapeToStandard.h" |
| #include "mlir/Dialect/Func/IR/FuncOps.h" |
| #include "mlir/Dialect/SCF/Transforms/Passes.h" |
| #include "mlir/Dialect/Shape/Transforms/Passes.h" |
| #include "mlir/Pass/PassManager.h" |
| #include "mlir/Pass/PassOptions.h" |
| #include "mlir/Pass/PassRegistry.h" |
| #include "mlir/Transforms/Passes.h" |
| #include "stablehlo/transforms/Passes.h" |
| |
| namespace mlir::iree_compiler::stablehlo { |
| namespace { |
| #define GEN_PASS_REGISTRATION |
| #include "compiler/plugins/input/StableHLO/Conversion/Passes.h.inc" // IWYU pragma: export |
| } // namespace |
| |
| namespace { |
| |
| void registerStableHLOConversionPassPipeline() { |
| PassPipelineRegistration<StableHloOptions> stablehlo( |
| "iree-stablehlo-input-transformation-pipeline", |
| "Runs the StableHLO IREE flow dialect transformation pipeline", |
| [](OpPassManager &passManager, const StableHloOptions &options) { |
| buildStableHLOInputConversionPassPipeline(passManager, options); |
| }); |
| } |
| |
| // Prepare HLO for use as an input to the Flow dialect. |
| void buildStableHLOInputConversionPassPipelineImpl( |
| OpPassManager &passManager, const StableHloOptions &options, bool detuple) { |
| // Having both StableHLO and VHLO in the same module is not supported. |
| // If the input is VHLO, then it is automatically converted to StableHLO. |
| // If the input is StableHLO, this pass is considered a NOP. |
| passManager.addPass(stablehlo::createCheckVHLOStableHloMixUsage()); |
| ::mlir::stablehlo::createStablehloDeserializePipeline(passManager); |
| passManager.addNestedPass<func::FuncOp>(mlir::createCanonicalizerPass()); |
| passManager.addNestedPass<func::FuncOp>(createStableHLOCanonicalize()); |
| passManager.addNestedPass<func::FuncOp>(mlir::createCSEPass()); |
| passManager.addNestedPass<func::FuncOp>(createLegalizeStableHLOCustomCalls()); |
| passManager.addNestedPass<func::FuncOp>( |
| stablehlo::createLegalizeControlFlow()); |
| |
| passManager.addPass(createFlattenTuplesInSCF()); |
| if (detuple) { |
| passManager.addPass(createFlattenTuplesInCFG()); |
| } |
| |
| passManager.addPass(createStableHLOToStableHLOPreprocessing()); |
| passManager.addNestedPass<func::FuncOp>(createStableHLOCanonicalize()); |
| |
| // Various shape functions may have been materialized in the `shape.shape_of` |
| // style of treating shapes as tensors. We prefer to legalize these to |
| // scalar ops as early as possible to avoid having them persist as tensor |
| // computations. |
| passManager.addNestedPass<func::FuncOp>(createShapeToShapeLowering()); |
| passManager.addPass(createConvertShapeToStandardPass()); |
| passManager.addNestedPass<func::FuncOp>(mlir::createCanonicalizerPass()); |
| passManager.addNestedPass<func::FuncOp>(createStableHLOCanonicalize()); |
| |
| // We also don't handle calls well on the old codepath; until we remove the |
| // use of the CFG we can continue inlining. |
| passManager.addPass(mlir::createInlinerPass()); |
| |
| // Perform initial cleanup. createLegalizeInputTypes could rewrite types. In |
| // this context, some operations could be folded away. |
| passManager.addNestedPass<func::FuncOp>(mlir::createCanonicalizerPass()); |
| passManager.addNestedPass<func::FuncOp>(createStableHLOCanonicalize()); |
| passManager.addNestedPass<func::FuncOp>(mlir::createCSEPass()); |
| |
| // Convert to Linalg. After this point, StableHLO will be eliminated. |
| passManager.addNestedPass<func::FuncOp>( |
| stablehlo::createLegalizeShapeComputations()); |
| passManager.addNestedPass<func::FuncOp>( |
| stablehlo::createConvertStableHloToLinalgExt()); |
| passManager.addNestedPass<func::FuncOp>(stablehlo::createLegalizeChlo()); |
| passManager.addPass(createConvertStableHloToIreeInputDialects()); |
| // Ensure conversion completed. |
| passManager.addPass(createReconcileUnrealizedCastsPass()); |
| |
| // Note that some StableHLO ops are left by the above and must resolve via |
| // canonicalization. See comments in the above pass and find a better way. |
| passManager.addNestedPass<func::FuncOp>(mlir::createCanonicalizerPass()); |
| passManager.addNestedPass<func::FuncOp>(createStableHLOCanonicalize()); |
| |
| passManager.addPass(stablehlo::createVerifyCompilerStableHloInputLegality()); |
| } |
| } // namespace |
| |
| void buildStableHLOInputConversionPassPipeline( |
| OpPassManager &passManager, const StableHloOptions &options) { |
| buildStableHLOInputConversionPassPipelineImpl(passManager, options, |
| /*detuple=*/false); |
| } |
| |
| void buildStableHLOXLAInputConversionPassPipeline( |
| OpPassManager &passManager, const StableHloOptions &options) { |
| buildStableHLOInputConversionPassPipelineImpl(passManager, options, |
| /*detuple=*/true); |
| } |
| |
| void registerStableHLOConversionPasses() { |
| // Generated. |
| registerPasses(); |
| |
| registerStableHLOPreprocessingPasses(); |
| registerStableHLOConversionPassPipeline(); |
| } |
| |
| } // namespace mlir::iree_compiler::stablehlo |