//===- 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/AffineOps.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> { 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(); } 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> 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(); // SparseConstantPropagation allows the solver to call // visitNonControlFlowArguments and analyze arguments like loop induction // variables. solver.load(); solver.load(); if (failed(solver.initializeAndRun(rootOp))) return signalPassFailure(); for (auto &[op, value] : queryOps) { const auto *lattice = solver.lookupState(value); if (!lattice || lattice->getValue().isUninitialized()) { op->setAttr("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->setAttr("divisibility", StringAttr::get(context, result)); } } }; } // end anonymous namespace namespace mlir::test { void registerTestIntegerDivisibilityAnalysisPass() { PassRegistration(); } } // end namespace mlir::test