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