| // Copyright 2021 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 "iree/compiler/Dialect/Util/Transforms/Passes.h" |
| #include "mlir/IR/BuiltinTypes.h" |
| #include "mlir/Pass/Pass.h" |
| #include "mlir/Pass/PassManager.h" |
| |
| namespace mlir::iree_compiler::IREE::Util { |
| |
| #define GEN_PASS_DEF_FIXEDPOINTITERATORPASS |
| #include "iree/compiler/Dialect/Util/Transforms/Passes.h.inc" |
| |
| namespace { |
| |
| // Dynamic pass which runs a sub-pipeline to a fixed point or a maximum |
| // iteration count. |
| // |
| // There is no direct coupling between this iterator and the contained passes. |
| // Indirectly, at the start of each iteration, this pass will set the |
| // "iree.fixedpoint.converged" unit attribute on the root operation. If it is |
| // still there when the sub-pipeline is complete, it will be removed and |
| // iteration terminates. If a sub-pass removes it, then iteration will |
| // continue. |
| class FixedPointIteratorPass |
| : public impl::FixedPointIteratorPassBase<FixedPointIteratorPass> { |
| public: |
| using Base::Base; |
| FixedPointIteratorPass() = default; |
| FixedPointIteratorPass(const FixedPointIteratorPass &other) |
| : impl::FixedPointIteratorPassBase<FixedPointIteratorPass>(other) {} |
| FixedPointIteratorPass(OpPassManager pipeline); |
| |
| private: |
| LogicalResult initializeOptions( |
| StringRef options, |
| function_ref<LogicalResult(const Twine &)> errorHandler) override; |
| void getDependentDialects(DialectRegistry ®istry) const override; |
| void runOnOperation() override; |
| |
| std::optional<OpPassManager> pipeline; |
| |
| // Serialized form of the body pipeline. |
| Option<std::string> pipelineStr{ |
| *this, "pipeline", llvm::cl::desc("Pipeline to run to a fixed point")}; |
| Option<int> maxIterations{*this, "max-iterations", |
| llvm::cl::desc("Maximum number of iterations"), |
| llvm::cl::init(10)}; |
| }; |
| |
| FixedPointIteratorPass::FixedPointIteratorPass(OpPassManager pipeline) |
| : pipeline(std::move(pipeline)) { |
| llvm::raw_string_ostream ss(pipelineStr); |
| this->pipeline->printAsTextualPipeline(ss); |
| ss.flush(); |
| } |
| |
| LogicalResult FixedPointIteratorPass::initializeOptions( |
| StringRef options, |
| function_ref<LogicalResult(const Twine &)> errorHandler) { |
| if (failed(Pass::initializeOptions(options, errorHandler))) |
| return failure(); |
| if (pipeline) |
| return success(); |
| |
| // Pipelines are expected to be of the form `<op-name>(<pipeline>)`. |
| // TODO: This was lifted from the Inliner pass. We should provide a parse |
| // entry point that is the direct inverse of printAsTextualPipeline() and |
| // at least keep this internal to the upstream implementation. |
| // See: https://github.com/llvm/llvm-project/issues/52813 |
| StringRef pipelineSr = pipelineStr; |
| size_t pipelineStart = pipelineSr.find_first_of('('); |
| if (pipelineStart == StringRef::npos || !pipelineSr.consume_back(")")) |
| return failure(); |
| StringRef opName = pipelineSr.take_front(pipelineStart); |
| OpPassManager pm(opName); |
| if (failed(parsePassPipeline(pipelineSr.drop_front(1 + pipelineStart), pm))) |
| return failure(); |
| pipeline = std::move(pm); |
| return success(); |
| } |
| |
| void FixedPointIteratorPass::getDependentDialects( |
| DialectRegistry ®istry) const { |
| pipeline->getDependentDialects(registry); |
| } |
| |
| void FixedPointIteratorPass::runOnOperation() { |
| MLIRContext *context = &getContext(); |
| StringAttr markerName = StringAttr::get(context, "iree.fixedpoint.iteration"); |
| StringAttr modifiedName = |
| StringAttr::get(context, "iree.fixedpoint.modified"); |
| |
| if (getOperation()->hasAttr(markerName)) { |
| emitError(getOperation()->getLoc()) |
| << "nested fixed point pipelines not supported"; |
| return signalPassFailure(); |
| } |
| |
| for (int i = 0; i < maxIterations; ++i) { |
| getOperation()->setAttr(markerName, |
| IntegerAttr::get(IndexType::get(context), i)); |
| getOperation()->removeAttr(modifiedName); |
| if (failed(runPipeline(*pipeline, getOperation()))) { |
| return signalPassFailure(); |
| } |
| |
| if (!getOperation()->hasAttr(modifiedName)) { |
| // Normal exit. |
| getOperation()->removeAttr(markerName); |
| return; |
| } |
| } |
| |
| // Abnormal exit - iteration count exceeded. |
| emitError(getOperation()->getLoc()) |
| << "maximum iteration count exceeded in fixed point pipeline"; |
| return signalPassFailure(); |
| } |
| |
| } // namespace |
| |
| std::unique_ptr<OperationPass<void>> |
| createFixedPointIteratorPass(OpPassManager pipeline) { |
| return std::make_unique<FixedPointIteratorPass>(std::move(pipeline)); |
| } |
| |
| } // namespace mlir::iree_compiler::IREE::Util |