1*c095afcbSMogball //===- TestDeadCodeAnalysis.cpp - Test dead code analysis -----------------===// 2*c095afcbSMogball // 3*c095afcbSMogball // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*c095afcbSMogball // See https://llvm.org/LICENSE.txt for license information. 5*c095afcbSMogball // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*c095afcbSMogball // 7*c095afcbSMogball //===----------------------------------------------------------------------===// 8*c095afcbSMogball 9*c095afcbSMogball #include "mlir/Analysis/DataFlow/ConstantPropagationAnalysis.h" 10*c095afcbSMogball #include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h" 11*c095afcbSMogball #include "mlir/IR/Matchers.h" 12*c095afcbSMogball #include "mlir/Pass/Pass.h" 13*c095afcbSMogball 14*c095afcbSMogball using namespace mlir; 15*c095afcbSMogball using namespace mlir::dataflow; 16*c095afcbSMogball 17*c095afcbSMogball /// Print the liveness of every block, control-flow edge, and the predecessors 18*c095afcbSMogball /// of all regions, callables, and calls. 19*c095afcbSMogball static void printAnalysisResults(DataFlowSolver &solver, Operation *op, 20*c095afcbSMogball raw_ostream &os) { 21*c095afcbSMogball op->walk([&](Operation *op) { 22*c095afcbSMogball auto tag = op->getAttrOfType<StringAttr>("tag"); 23*c095afcbSMogball if (!tag) 24*c095afcbSMogball return; 25*c095afcbSMogball os << tag.getValue() << ":\n"; 26*c095afcbSMogball for (Region ®ion : op->getRegions()) { 27*c095afcbSMogball os << " region #" << region.getRegionNumber() << "\n"; 28*c095afcbSMogball for (Block &block : region) { 29*c095afcbSMogball os << " "; 30*c095afcbSMogball block.printAsOperand(os); 31*c095afcbSMogball os << " = "; 32*c095afcbSMogball auto *live = solver.lookupState<Executable>(&block); 33*c095afcbSMogball if (live) 34*c095afcbSMogball os << *live; 35*c095afcbSMogball else 36*c095afcbSMogball os << "dead"; 37*c095afcbSMogball os << "\n"; 38*c095afcbSMogball for (Block *pred : block.getPredecessors()) { 39*c095afcbSMogball os << " from "; 40*c095afcbSMogball pred->printAsOperand(os); 41*c095afcbSMogball os << " = "; 42*c095afcbSMogball auto *live = solver.lookupState<Executable>( 43*c095afcbSMogball solver.getProgramPoint<CFGEdge>(pred, &block)); 44*c095afcbSMogball if (live) 45*c095afcbSMogball os << *live; 46*c095afcbSMogball else 47*c095afcbSMogball os << "dead"; 48*c095afcbSMogball os << "\n"; 49*c095afcbSMogball } 50*c095afcbSMogball } 51*c095afcbSMogball if (!region.empty()) { 52*c095afcbSMogball auto *preds = solver.lookupState<PredecessorState>(®ion.front()); 53*c095afcbSMogball if (preds) 54*c095afcbSMogball os << "region_preds: " << *preds << "\n"; 55*c095afcbSMogball } 56*c095afcbSMogball } 57*c095afcbSMogball auto *preds = solver.lookupState<PredecessorState>(op); 58*c095afcbSMogball if (preds) 59*c095afcbSMogball os << "op_preds: " << *preds << "\n"; 60*c095afcbSMogball }); 61*c095afcbSMogball } 62*c095afcbSMogball 63*c095afcbSMogball namespace { 64*c095afcbSMogball /// This is a simple analysis that implements a transfer function for constant 65*c095afcbSMogball /// operations. 66*c095afcbSMogball struct ConstantAnalysis : public DataFlowAnalysis { 67*c095afcbSMogball using DataFlowAnalysis::DataFlowAnalysis; 68*c095afcbSMogball 69*c095afcbSMogball LogicalResult initialize(Operation *top) override { 70*c095afcbSMogball WalkResult result = top->walk([&](Operation *op) { 71*c095afcbSMogball if (op->hasTrait<OpTrait::ConstantLike>()) 72*c095afcbSMogball if (failed(visit(op))) 73*c095afcbSMogball return WalkResult::interrupt(); 74*c095afcbSMogball return WalkResult::advance(); 75*c095afcbSMogball }); 76*c095afcbSMogball return success(!result.wasInterrupted()); 77*c095afcbSMogball } 78*c095afcbSMogball 79*c095afcbSMogball LogicalResult visit(ProgramPoint point) override { 80*c095afcbSMogball Operation *op = point.get<Operation *>(); 81*c095afcbSMogball Attribute value; 82*c095afcbSMogball if (matchPattern(op, m_Constant(&value))) { 83*c095afcbSMogball auto *constant = getOrCreate<Lattice<ConstantValue>>(op->getResult(0)); 84*c095afcbSMogball propagateIfChanged( 85*c095afcbSMogball constant, constant->join(ConstantValue(value, op->getDialect()))); 86*c095afcbSMogball } 87*c095afcbSMogball return success(); 88*c095afcbSMogball } 89*c095afcbSMogball }; 90*c095afcbSMogball 91*c095afcbSMogball /// This is a simple pass that runs dead code analysis with no constant value 92*c095afcbSMogball /// provider. It marks everything as live. 93*c095afcbSMogball struct TestDeadCodeAnalysisPass 94*c095afcbSMogball : public PassWrapper<TestDeadCodeAnalysisPass, OperationPass<>> { 95*c095afcbSMogball MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDeadCodeAnalysisPass) 96*c095afcbSMogball 97*c095afcbSMogball StringRef getArgument() const override { return "test-dead-code-analysis"; } 98*c095afcbSMogball 99*c095afcbSMogball void runOnOperation() override { 100*c095afcbSMogball Operation *op = getOperation(); 101*c095afcbSMogball 102*c095afcbSMogball DataFlowSolver solver; 103*c095afcbSMogball solver.load<DeadCodeAnalysis>(); 104*c095afcbSMogball solver.load<ConstantAnalysis>(); 105*c095afcbSMogball if (failed(solver.initializeAndRun(op))) 106*c095afcbSMogball return signalPassFailure(); 107*c095afcbSMogball printAnalysisResults(solver, op, llvm::errs()); 108*c095afcbSMogball } 109*c095afcbSMogball }; 110*c095afcbSMogball } // end anonymous namespace 111*c095afcbSMogball 112*c095afcbSMogball namespace mlir { 113*c095afcbSMogball namespace test { 114*c095afcbSMogball void registerTestDeadCodeAnalysisPass() { 115*c095afcbSMogball PassRegistration<TestDeadCodeAnalysisPass>(); 116*c095afcbSMogball } 117*c095afcbSMogball } // end namespace test 118*c095afcbSMogball } // end namespace mlir 119