1 //===- DeadCodeAnalysis.h - Dead code analysis ----------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements dead code analysis using the data-flow analysis 10 // framework. This analysis uses the results of constant propagation to 11 // determine live blocks, control-flow edges, and control-flow predecessors. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef MLIR_ANALYSIS_DATAFLOW_DEADCODEANALYSIS_H 16 #define MLIR_ANALYSIS_DATAFLOW_DEADCODEANALYSIS_H 17 18 #include "mlir/Analysis/DataFlowFramework.h" 19 #include "mlir/IR/SymbolTable.h" 20 #include "llvm/ADT/SmallPtrSet.h" 21 22 namespace mlir { 23 24 class CallOpInterface; 25 class CallableOpInterface; 26 class BranchOpInterface; 27 class RegionBranchOpInterface; 28 29 namespace dataflow { 30 31 //===----------------------------------------------------------------------===// 32 // Executable 33 //===----------------------------------------------------------------------===// 34 35 /// This is a simple analysis state that represents whether the associated 36 /// program point (either a block or a control-flow edge) is live. 37 class Executable : public AnalysisState { 38 public: 39 using AnalysisState::AnalysisState; 40 41 /// The state is initialized by default. isUninitialized()42 bool isUninitialized() const override { return false; } 43 44 /// The state is always initialized. defaultInitialize()45 ChangeResult defaultInitialize() override { return ChangeResult::NoChange; } 46 47 /// Set the state of the program point to live. 48 ChangeResult setToLive(); 49 50 /// Get whether the program point is live. isLive()51 bool isLive() const { return live; } 52 53 /// Print the liveness. 54 void print(raw_ostream &os) const override; 55 56 /// When the state of the program point is changed to live, re-invoke 57 /// subscribed analyses on the operations in the block and on the block 58 /// itself. 59 void onUpdate(DataFlowSolver *solver) const override; 60 61 /// Subscribe an analysis to changes to the liveness. blockContentSubscribe(DataFlowAnalysis * analysis)62 void blockContentSubscribe(DataFlowAnalysis *analysis) { 63 subscribers.insert(analysis); 64 } 65 66 private: 67 /// Whether the program point is live. Optimistically assume that the program 68 /// point is dead. 69 bool live = false; 70 71 /// A set of analyses that should be updated when this state changes. 72 SetVector<DataFlowAnalysis *, SmallVector<DataFlowAnalysis *, 4>, 73 SmallPtrSet<DataFlowAnalysis *, 4>> 74 subscribers; 75 }; 76 77 //===----------------------------------------------------------------------===// 78 // PredecessorState 79 //===----------------------------------------------------------------------===// 80 81 /// This analysis state represents a set of live control-flow "predecessors" of 82 /// a program point (either an operation or a block), which are the last 83 /// operations along all execution paths that pass through this point. 84 /// 85 /// For example, in dead-code analysis, an operation with region control-flow 86 /// can be the predecessor of a region's entry block or itself, the exiting 87 /// terminator of a region can be the predecessor of the parent operation or 88 /// another region's entry block, the callsite of a callable operation can be 89 /// the predecessor to its entry block, and the exiting terminator or a callable 90 /// operation can be the predecessor of the call operation. 91 /// 92 /// The state can optionally contain information about which values are 93 /// propagated from each predecessor to the successor point. 94 /// 95 /// The state can indicate that it is underdefined, meaning that not all live 96 /// control-flow predecessors can be known. 97 class PredecessorState : public AnalysisState { 98 public: 99 using AnalysisState::AnalysisState; 100 101 /// The state is initialized by default. isUninitialized()102 bool isUninitialized() const override { return false; } 103 104 /// The state is always initialized. defaultInitialize()105 ChangeResult defaultInitialize() override { return ChangeResult::NoChange; } 106 107 /// Print the known predecessors. 108 void print(raw_ostream &os) const override; 109 110 /// Returns true if all predecessors are known. allPredecessorsKnown()111 bool allPredecessorsKnown() const { return allKnown; } 112 113 /// Indicate that there are potentially unknown predecessors. setHasUnknownPredecessors()114 ChangeResult setHasUnknownPredecessors() { 115 return std::exchange(allKnown, false) ? ChangeResult::Change 116 : ChangeResult::NoChange; 117 } 118 119 /// Get the known predecessors. getKnownPredecessors()120 ArrayRef<Operation *> getKnownPredecessors() const { 121 return knownPredecessors.getArrayRef(); 122 } 123 124 /// Get the successor inputs from a predecessor. getSuccessorInputs(Operation * predecessor)125 ValueRange getSuccessorInputs(Operation *predecessor) const { 126 return successorInputs.lookup(predecessor); 127 } 128 129 /// Add a known predecessor. 130 ChangeResult join(Operation *predecessor); 131 132 /// Add a known predecessor with successor inputs. 133 ChangeResult join(Operation *predecessor, ValueRange inputs); 134 135 private: 136 /// Whether all predecessors are known. Optimistically assume that we know 137 /// all predecessors. 138 bool allKnown = true; 139 140 /// The known control-flow predecessors of this program point. 141 SetVector<Operation *, SmallVector<Operation *, 4>, 142 SmallPtrSet<Operation *, 4>> 143 knownPredecessors; 144 145 /// The successor inputs when branching from a given predecessor. 146 DenseMap<Operation *, ValueRange> successorInputs; 147 }; 148 149 //===----------------------------------------------------------------------===// 150 // CFGEdge 151 //===----------------------------------------------------------------------===// 152 153 /// This program point represents a control-flow edge between a block and one 154 /// of its successors. 155 class CFGEdge 156 : public GenericProgramPointBase<CFGEdge, std::pair<Block *, Block *>> { 157 public: 158 using Base::Base; 159 160 /// Get the block from which the edge originates. getFrom()161 Block *getFrom() const { return getValue().first; } 162 /// Get the target block. getTo()163 Block *getTo() const { return getValue().second; } 164 165 /// Print the blocks between the control-flow edge. 166 void print(raw_ostream &os) const override; 167 /// Get a fused location of both blocks. 168 Location getLoc() const override; 169 }; 170 171 //===----------------------------------------------------------------------===// 172 // DeadCodeAnalysis 173 //===----------------------------------------------------------------------===// 174 175 /// Dead code analysis analyzes control-flow, as understood by 176 /// `RegionBranchOpInterface` and `BranchOpInterface`, and the callgraph, as 177 /// understood by `CallableOpInterface` and `CallOpInterface`. 178 /// 179 /// This analysis uses known constant values of operands to determine the 180 /// liveness of each block and each edge between a block and its predecessors. 181 /// For region control-flow, this analysis determines the predecessor operations 182 /// for region entry blocks and region control-flow operations. For the 183 /// callgraph, this analysis determines the callsites and live returns of every 184 /// function. 185 class DeadCodeAnalysis : public DataFlowAnalysis { 186 public: 187 explicit DeadCodeAnalysis(DataFlowSolver &solver); 188 189 /// Initialize the analysis by visiting every operation with potential 190 /// control-flow semantics. 191 LogicalResult initialize(Operation *top) override; 192 193 /// Visit an operation with control-flow semantics and deduce which of its 194 /// successors are live. 195 LogicalResult visit(ProgramPoint point) override; 196 197 private: 198 /// Find and mark symbol callables with potentially unknown callsites as 199 /// having overdefined predecessors. `top` is the top-level operation that the 200 /// analysis is operating on. 201 void initializeSymbolCallables(Operation *top); 202 203 /// Recursively Initialize the analysis on nested regions. 204 LogicalResult initializeRecursively(Operation *op); 205 206 /// Visit the given call operation and compute any necessary lattice state. 207 void visitCallOperation(CallOpInterface call); 208 209 /// Visit the given branch operation with successors and try to determine 210 /// which are live from the current block. 211 void visitBranchOperation(BranchOpInterface branch); 212 213 /// Visit the given region branch operation, which defines regions, and 214 /// compute any necessary lattice state. This also resolves the lattice state 215 /// of both the operation results and any nested regions. 216 void visitRegionBranchOperation(RegionBranchOpInterface branch); 217 218 /// Visit the given terminator operation that exits a region under an 219 /// operation with control-flow semantics. These are terminators with no CFG 220 /// successors. 221 void visitRegionTerminator(Operation *op, RegionBranchOpInterface branch); 222 223 /// Visit the given terminator operation that exits a callable region. These 224 /// are terminators with no CFG successors. 225 void visitCallableTerminator(Operation *op, CallableOpInterface callable); 226 227 /// Mark the edge between `from` and `to` as executable. 228 void markEdgeLive(Block *from, Block *to); 229 230 /// Mark the entry blocks of the operation as executable. 231 void markEntryBlocksLive(Operation *op); 232 233 /// Get the constant values of the operands of the operation. Returns none if 234 /// any of the operand lattices are uninitialized. 235 Optional<SmallVector<Attribute>> getOperandValues(Operation *op); 236 237 /// A symbol table used for O(1) symbol lookups during simplification. 238 SymbolTableCollection symbolTable; 239 }; 240 241 } // end namespace dataflow 242 } // end namespace mlir 243 244 #endif // MLIR_ANALYSIS_DATAFLOW_DEADCODEANALYSIS_H 245