| //===- TestIntegerDivisibilityAnalysis.cpp - Test int divisibility --------===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "mlir/Analysis/DataFlow/ConstantPropagationAnalysis.h" | |
| #include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h" | |
| #include "mlir/Analysis/DataFlow/IntegerDivisibilityAnalysis.h" | |
| #include "mlir/Analysis/DataFlowFramework.h" | |
| #include "mlir/Dialect/Affine/IR/AffineDialect.h" | |
| #include "mlir/Dialect/Arith/IR/Arith.h" | |
| #include "mlir/IR/BuiltinAttributes.h" | |
| #include "mlir/IR/DialectRegistry.h" | |
| #include "mlir/IR/Operation.h" | |
| #include "mlir/Pass/Pass.h" | |
| #include "mlir/Pass/PassRegistry.h" | |
| #include "llvm/ADT/SmallVector.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| using namespace mlir; | |
| using namespace mlir::dataflow; | |
| namespace { | |
| struct TestIntegerDivisibilityAnalysisPass | |
| : public PassWrapper<TestIntegerDivisibilityAnalysisPass, OperationPass<>> { | |
| MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID( | |
| TestIntegerDivisibilityAnalysisPass) | |
| StringRef getArgument() const override { | |
| return "test-int-divisibility-analysis"; | |
| } | |
| StringRef getDescription() const override { | |
| return "Test integer divisibility analysis by annotating " | |
| "'test.int_divisibility' ops with the divisibility of their " | |
| "operand."; | |
| } | |
| void getDependentDialects(DialectRegistry ®istry) const override { | |
| registry.insert<arith::ArithDialect, affine::AffineDialect>(); | |
| } | |
| void runOnOperation() override { | |
| Operation *rootOp = getOperation(); | |
| MLIRContext *context = &getContext(); | |
| // The pass is rooted on `test.int_divisibility` ops, which are expected | |
| // to have a single operand for which to annotate divisibility information. | |
| SmallVector<std::pair<Operation *, Value>> queryOps; | |
| rootOp->walk([&](Operation *op) { | |
| if (op->getName().getStringRef() == "test.int_divisibility" && | |
| op->getNumOperands() == 1) | |
| queryOps.emplace_back(op, op->getOperand(0)); | |
| }); | |
| DataFlowSolver solver; | |
| // DeadCodeAnalysis is the base analysis that allows the solver to traverse | |
| // control flow. It is required by IntegerDivisibilityAnalysis. | |
| solver.load<DeadCodeAnalysis>(); | |
| // SparseConstantPropagation allows the solver to call | |
| // visitNonControlFlowArguments and analyze arguments like loop induction | |
| // variables. | |
| solver.load<SparseConstantPropagation>(); | |
| solver.load<IntegerDivisibilityAnalysis>(); | |
| if (failed(solver.initializeAndRun(rootOp))) | |
| return signalPassFailure(); | |
| for (auto &[op, value] : queryOps) { | |
| const auto *lattice = | |
| solver.lookupState<IntegerDivisibilityLattice>(value); | |
| if (!lattice || lattice->getValue().isUninitialized()) { | |
| op->setDiscardableAttr("divisibility", | |
| StringAttr::get(context, "uninitialized")); | |
| continue; | |
| } | |
| // Format for the divisibility information is "udiv = X, sdiv = Y". | |
| const auto &div = lattice->getValue().getValue(); | |
| std::string result; | |
| llvm::raw_string_ostream os(result); | |
| os << "udiv = " << div.udiv() << ", sdiv = " << div.sdiv(); | |
| op->setDiscardableAttr("divisibility", StringAttr::get(context, result)); | |
| } | |
| } | |
| }; | |
| } // end anonymous namespace | |
| namespace mlir::test { | |
| void registerTestIntegerDivisibilityAnalysisPass() { | |
| PassRegistration<TestIntegerDivisibilityAnalysisPass>(); | |
| } | |
| } // end namespace mlir::test |