1c3e0fb406fb6fe83566dc6d8b05362e0a2c1e191Eli Friedman//===- SparsePropagation.h - Sparse Conditional Property Propagation ------===// 2e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar// 393ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin// The LLVM Compiler Infrastructure 4e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar// 5c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump// This file is distributed under the University of Illinois Open Source 6e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar// License. See LICENSE.TXT for details. 7e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar// 893ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin//===----------------------------------------------------------------------===// 9e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar// 10c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump// This file implements an abstract sparse conditional propagation algorithm, 11e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar// modeled after SCCP, but with a customizable lattice function. 12e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar// 1393ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin//===----------------------------------------------------------------------===// 14e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar 15c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump#ifndef LLVM_ANALYSIS_SPARSEPROPAGATION_H 16e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar#define LLVM_ANALYSIS_SPARSEPROPAGATION_H 17e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar 1893ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin#include "llvm/ADT/DenseMap.h" 19e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar#include "llvm/ADT/SmallPtrSet.h" 20c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump#include <set> 21e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar#include <vector> 22e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar 2393ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Linnamespace llvm { 24e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar class Value; 25c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump class Constant; 26e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar class Argument; 27e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar class Instruction; 2893ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin class PHINode; 29e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar class TerminatorInst; 30c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump class BasicBlock; 31e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar class Function; 32e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar class SparseSolver; 3393ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin class raw_ostream; 34c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump 35e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar template<typename T> class SmallVectorImpl; 3693ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin 37d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar/// AbstractLatticeFunction - This class is implemented by the dataflow instance 38d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar/// to specify what the lattice values are and how they handle merges etc. 39e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar/// This gives the client the power to compute lattice values from instructions, 4093ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin/// constants, etc. The requirement is that lattice values must all fit into 4193ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin/// a void*. If a void* is not sufficient, the implementation should use this 42e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar/// pointer to be a pointer into a uniquing set or something. 43e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar/// 44e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbarclass AbstractLatticeFunction { 45e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbarpublic: 46c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump typedef void *LatticeVal; 47c36541e7bfa69cc63e2668a986bc99117559c545Mike Stumpprivate: 48e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar LatticeVal UndefVal, OverdefinedVal, UntrackedVal; 49e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbarpublic: 50e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar AbstractLatticeFunction(LatticeVal undefVal, LatticeVal overdefinedVal, 5193ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin LatticeVal untrackedVal) { 52cf6bde343ff5653744ca782e04d5a9c54b260042Daniel Dunbar UndefVal = undefVal; 53eedd292ea0cf2216ff16d3490147323489102e3aDaniel Dunbar OverdefinedVal = overdefinedVal; 54eedd292ea0cf2216ff16d3490147323489102e3aDaniel Dunbar UntrackedVal = untrackedVal; 5593ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin } 56e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar virtual ~AbstractLatticeFunction(); 57e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar 58e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar LatticeVal getUndefVal() const { return UndefVal; } 59e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar LatticeVal getOverdefinedVal() const { return OverdefinedVal; } 60c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump LatticeVal getUntrackedVal() const { return UntrackedVal; } 61c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump 62e06a75f4c8ea30b6a99d5aa1dce5feda64da09c6Daniel Dunbar /// IsUntrackedValue - If the specified Value is something that is obviously 63dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar /// uninteresting to the analysis (and would always return UntrackedVal), 645bde6f41506535ddaf6e9ff60bd1488db8ded952Daniel Dunbar /// this function can return true to avoid pointless work. 65d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar virtual bool IsUntrackedValue(Value *V) { 665bde6f41506535ddaf6e9ff60bd1488db8ded952Daniel Dunbar return false; 675bde6f41506535ddaf6e9ff60bd1488db8ded952Daniel Dunbar } 685bde6f41506535ddaf6e9ff60bd1488db8ded952Daniel Dunbar 69c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump /// ComputeConstant - Given a constant value, compute and return a lattice 705bde6f41506535ddaf6e9ff60bd1488db8ded952Daniel Dunbar /// value corresponding to the specified constant. 71dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar virtual LatticeVal ComputeConstant(Constant *C) { 72360431660b2245a109f5c6870729126dbcdea254Daniel Dunbar return getOverdefinedVal(); // always safe 73d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar } 745e31474b9c8348e8d0404264ae6a8775e34df6acBill Wendling 75d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar /// IsSpecialCasedPHI - Given a PHI node, determine whether this PHI node is 76d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar /// one that the we want to handle through ComputeInstructionState. 77d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar virtual bool IsSpecialCasedPHI(PHINode *PN) { 78d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar return false; 79360431660b2245a109f5c6870729126dbcdea254Daniel Dunbar } 80c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump 81360431660b2245a109f5c6870729126dbcdea254Daniel Dunbar /// GetConstant - If the specified lattice value is representable as an LLVM 82c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump /// constant value, return it. Otherwise return null. The returned value 83360431660b2245a109f5c6870729126dbcdea254Daniel Dunbar /// must be in the same LLVM type as Val. 84c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump virtual Constant *GetConstant(LatticeVal LV, Value *Val, SparseSolver &SS) { 85360431660b2245a109f5c6870729126dbcdea254Daniel Dunbar return nullptr; 86c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump } 87dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar 88c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump /// ComputeArgument - Given a formal argument value, compute and return a 89dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar /// lattice value corresponding to the specified argument. 90c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump virtual LatticeVal ComputeArgument(Argument *I) { 91dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar return getOverdefinedVal(); // always safe 92dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar } 93dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar 94dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar /// MergeValues - Compute and return the merge of the two specified lattice 95d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar /// values. Merging should only move one direction down the lattice to 965e31474b9c8348e8d0404264ae6a8775e34df6acBill Wendling /// guarantee convergence (toward overdefined). 975e31474b9c8348e8d0404264ae6a8775e34df6acBill Wendling virtual LatticeVal MergeValues(LatticeVal X, LatticeVal Y) { 985e31474b9c8348e8d0404264ae6a8775e34df6acBill Wendling return getOverdefinedVal(); // always safe, never useful. 995e31474b9c8348e8d0404264ae6a8775e34df6acBill Wendling } 1005e31474b9c8348e8d0404264ae6a8775e34df6acBill Wendling 101c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump /// ComputeInstructionState - Given an instruction and a vector of its operand 102c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump /// values, compute the result value of the instruction. 103c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump virtual LatticeVal ComputeInstructionState(Instruction &I, SparseSolver &SS) { 104c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump return getOverdefinedVal(); // always safe, never useful. 105c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump } 106c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump 107dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar /// PrintValue - Render the specified lattice value to the specified stream. 108dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar virtual void PrintValue(LatticeVal V, raw_ostream &OS); 109dfc6b80ee13a9102cd67e0b2398fa999eebcbf8eDaniel Dunbar}; 110d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar 111d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar 112d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar/// SparseSolver - This class is a general purpose solver for Sparse Conditional 113c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump/// Propagation with a programmable lattice function. 114c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump/// 115c36541e7bfa69cc63e2668a986bc99117559c545Mike Stumpclass SparseSolver { 1165bde6f41506535ddaf6e9ff60bd1488db8ded952Daniel Dunbar typedef AbstractLatticeFunction::LatticeVal LatticeVal; 117cf6bde343ff5653744ca782e04d5a9c54b260042Daniel Dunbar 118d0ef54cb306ef3090ffd551733c491e1cae2a28dDaniel Dunbar /// LatticeFunc - This is the object that knows the lattice and how to do 1195e31474b9c8348e8d0404264ae6a8775e34df6acBill Wendling /// compute transfer functions. 120c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump AbstractLatticeFunction *LatticeFunc; 121c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump 122cf6bde343ff5653744ca782e04d5a9c54b260042Daniel Dunbar DenseMap<Value*, LatticeVal> ValueState; // The state each value is in. 1235e31474b9c8348e8d0404264ae6a8775e34df6acBill Wendling SmallPtrSet<BasicBlock*, 16> BBExecutable; // The bbs that are executable. 124c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump 125f7fff322debe0b7256fe4dbc1103a3c2b43c379aDaniel Dunbar std::vector<Instruction*> InstWorkList; // Worklist of insts to process. 12693ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin 127c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump std::vector<BasicBlock*> BBWorkList; // The BasicBlock work list 1288e03444e924665d4d90f5cfc0624c815256e0309Daniel Dunbar 12993ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin /// KnownFeasibleEdges - Entries in this set are edges which have already had 130c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump /// PHI nodes retriggered. 131eedd292ea0cf2216ff16d3490147323489102e3aDaniel Dunbar typedef std::pair<BasicBlock*,BasicBlock*> Edge; 13293ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin std::set<Edge> KnownFeasibleEdges; 133c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump 134fcab2ca966d5176839f8698535e0d807bd968629Daniel Dunbar SparseSolver(const SparseSolver&) LLVM_DELETED_FUNCTION; 13593ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin void operator=(const SparseSolver&) LLVM_DELETED_FUNCTION; 136c36541e7bfa69cc63e2668a986bc99117559c545Mike Stumppublic: 1372e0011650fe149bf55916c6f25558bf9bfebf537Daniel Dunbar explicit SparseSolver(AbstractLatticeFunction *Lattice) 13893ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin : LatticeFunc(Lattice) {} 139c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump ~SparseSolver() { 1402e0011650fe149bf55916c6f25558bf9bfebf537Daniel Dunbar delete LatticeFunc; 14193ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin } 142c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump 143573b907e8ba3b74fc69cddaf63496c7bb5994196Daniel Dunbar /// Solve - Solve for constants and executable blocks. 14493ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin /// 145c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump void Solve(Function &F); 146573b907e8ba3b74fc69cddaf63496c7bb5994196Daniel Dunbar 14793ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin void Print(Function &F, raw_ostream &OS) const; 148c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump 149cc401dc651a91f53f9f9a39956732be8f537e7faDaniel Dunbar /// getLatticeState - Return the LatticeVal object that corresponds to the 15093ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin /// value. If an value is not in the map, it is returned as untracked, 151c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump /// unlike the getOrInitValueState method. 152cc401dc651a91f53f9f9a39956732be8f537e7faDaniel Dunbar LatticeVal getLatticeState(Value *V) const { 15393ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin DenseMap<Value*, LatticeVal>::const_iterator I = ValueState.find(V); 154c36541e7bfa69cc63e2668a986bc99117559c545Mike Stump return I != ValueState.end() ? I->second : LatticeFunc->getUntrackedVal(); 155836a0641ba4109b2c1254eec247ba4d2731bc2b7Daniel Dunbar } 15693ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin 157a1e6de9171d10c3a3dde7fc2e8cf72cc98bf6362Eli Friedman /// getOrInitValueState - Return the LatticeVal object that corresponds to the 158a1e6de9171d10c3a3dde7fc2e8cf72cc98bf6362Eli Friedman /// value, initializing the value's state if it hasn't been entered into the 159a1e6de9171d10c3a3dde7fc2e8cf72cc98bf6362Eli Friedman /// map yet. This function is necessary because not all values should start 160a1e6de9171d10c3a3dde7fc2e8cf72cc98bf6362Eli Friedman /// out in the underdefined state... Arguments should be overdefined, and 16155e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// constants should be marked as constants. 16293ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin /// 16355e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar LatticeVal getOrInitValueState(Value *V); 16455e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar 16555e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// isEdgeFeasible - Return true if the control flow edge from the 'From' 16693ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin /// basic block to the 'To' basic block is currently feasible. If 16755e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// AggressiveUndef is true, then this treats values with unknown lattice 16855e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// values as undefined. This is generally only useful when solving the 16955e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// lattice, not when querying it. 17093ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin bool isEdgeFeasible(BasicBlock *From, BasicBlock *To, 17155e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar bool AggressiveUndef = false); 17255e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar 17393ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin /// isBlockExecutable - Return true if there are any known feasible 17455e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// edges into the basic block. This is generally only useful when 17555e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// querying the lattice. 17693ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin bool isBlockExecutable(BasicBlock *BB) const { 17755e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar return BBExecutable.count(BB); 17855e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar } 17993ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin 18055e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbarprivate: 18155e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// UpdateState - When the state for some instruction is potentially updated, 18293ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin /// this function notices and adds I to the worklist if needed. 18355e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar void UpdateState(Instruction &Inst, LatticeVal V); 18455e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar 18593ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin /// MarkBlockExecutable - This method can be used by clients to mark all of 18655e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// the blocks that are known to be intrinsically live in the processed unit. 18755e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar void MarkBlockExecutable(BasicBlock *BB); 18893ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin 18955e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// markEdgeExecutable - Mark a basic block as executable, adding it to the BB 19055e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// work list if it is not already executable. 19155e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar void markEdgeExecutable(BasicBlock *Source, BasicBlock *Dest); 19293ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin 19355e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// getFeasibleSuccessors - Return a vector of booleans to indicate which 19455e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar /// successors are reachable from a given terminator instruction. 19555e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar void getFeasibleSuccessors(TerminatorInst &TI, SmallVectorImpl<bool> &Succs, 19693ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin bool AggressiveUndef); 19755e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar 19855e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar void visitInst(Instruction &I); 19955e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar void visitPHINode(PHINode &I); 20093ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin void visitTerminatorInst(TerminatorInst &TI); 20155e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar 20255e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar}; 20355e59e139d9ebcaae16d710472e28edbcafac98aDaniel Dunbar 20493ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin} // end namespace llvm 20546c54fb8ec45765a475b7b709b9aee7f94c490c2Daniel Dunbar 20646c54fb8ec45765a475b7b709b9aee7f94c490c2Daniel Dunbar#endif // LLVM_ANALYSIS_SPARSEPROPAGATION_H 20746c54fb8ec45765a475b7b709b9aee7f94c490c2Daniel Dunbar