2008-05-12 01:12:24 +00:00
|
|
|
//===- SparsePropagation.h - Sparse Conditional Property Propagation ------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements an abstract sparse conditional propagation algorithm,
|
|
|
|
// modeled after SCCP, but with a customizable lattice function.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_ANALYSIS_SPARSE_PROPAGATION_H
|
|
|
|
#define LLVM_ANALYSIS_SPARSE_PROPAGATION_H
|
|
|
|
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include <vector>
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
class Value;
|
|
|
|
class Constant;
|
2008-08-09 17:23:35 +00:00
|
|
|
class Argument;
|
2008-05-12 01:12:24 +00:00
|
|
|
class Instruction;
|
|
|
|
class PHINode;
|
|
|
|
class TerminatorInst;
|
|
|
|
class BasicBlock;
|
|
|
|
class Function;
|
|
|
|
class SparseSolver;
|
2009-08-23 04:37:46 +00:00
|
|
|
class raw_ostream;
|
2009-01-05 17:59:02 +00:00
|
|
|
|
|
|
|
template<typename T> class SmallVectorImpl;
|
2008-05-12 01:12:24 +00:00
|
|
|
|
|
|
|
/// AbstractLatticeFunction - This class is implemented by the dataflow instance
|
2008-05-27 20:41:18 +00:00
|
|
|
/// to specify what the lattice values are and how they handle merges etc.
|
2008-05-12 01:12:24 +00:00
|
|
|
/// This gives the client the power to compute lattice values from instructions,
|
|
|
|
/// constants, etc. The requirement is that lattice values must all fit into
|
|
|
|
/// a void*. If a void* is not sufficient, the implementation should use this
|
|
|
|
/// pointer to be a pointer into a uniquing set or something.
|
|
|
|
///
|
|
|
|
class AbstractLatticeFunction {
|
|
|
|
public:
|
|
|
|
typedef void *LatticeVal;
|
|
|
|
private:
|
|
|
|
LatticeVal UndefVal, OverdefinedVal, UntrackedVal;
|
|
|
|
public:
|
|
|
|
AbstractLatticeFunction(LatticeVal undefVal, LatticeVal overdefinedVal,
|
|
|
|
LatticeVal untrackedVal) {
|
|
|
|
UndefVal = undefVal;
|
|
|
|
OverdefinedVal = overdefinedVal;
|
|
|
|
UntrackedVal = untrackedVal;
|
|
|
|
}
|
|
|
|
virtual ~AbstractLatticeFunction();
|
|
|
|
|
|
|
|
LatticeVal getUndefVal() const { return UndefVal; }
|
|
|
|
LatticeVal getOverdefinedVal() const { return OverdefinedVal; }
|
|
|
|
LatticeVal getUntrackedVal() const { return UntrackedVal; }
|
|
|
|
|
|
|
|
/// IsUntrackedValue - If the specified Value is something that is obviously
|
|
|
|
/// uninteresting to the analysis (and would always return UntrackedVal),
|
|
|
|
/// this function can return true to avoid pointless work.
|
|
|
|
virtual bool IsUntrackedValue(Value *V) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ComputeConstant - Given a constant value, compute and return a lattice
|
|
|
|
/// value corresponding to the specified constant.
|
|
|
|
virtual LatticeVal ComputeConstant(Constant *C) {
|
|
|
|
return getOverdefinedVal(); // always safe
|
|
|
|
}
|
2009-09-19 18:33:36 +00:00
|
|
|
|
|
|
|
/// IsSpecialCasedPHI - Given a PHI node, determine whether this PHI node is
|
|
|
|
/// one that the we want to handle through ComputeInstructionState.
|
|
|
|
virtual bool IsSpecialCasedPHI(PHINode *PN) {
|
|
|
|
return false;
|
|
|
|
}
|
2008-05-12 01:12:24 +00:00
|
|
|
|
|
|
|
/// GetConstant - If the specified lattice value is representable as an LLVM
|
|
|
|
/// constant value, return it. Otherwise return null. The returned value
|
|
|
|
/// must be in the same LLVM type as Val.
|
|
|
|
virtual Constant *GetConstant(LatticeVal LV, Value *Val, SparseSolver &SS) {
|
|
|
|
return 0;
|
|
|
|
}
|
2008-08-09 17:23:35 +00:00
|
|
|
|
|
|
|
/// ComputeArgument - Given a formal argument value, compute and return a
|
|
|
|
/// lattice value corresponding to the specified argument.
|
|
|
|
virtual LatticeVal ComputeArgument(Argument *I) {
|
|
|
|
return getOverdefinedVal(); // always safe
|
|
|
|
}
|
2008-05-12 01:12:24 +00:00
|
|
|
|
|
|
|
/// MergeValues - Compute and return the merge of the two specified lattice
|
|
|
|
/// values. Merging should only move one direction down the lattice to
|
|
|
|
/// guarantee convergence (toward overdefined).
|
|
|
|
virtual LatticeVal MergeValues(LatticeVal X, LatticeVal Y) {
|
|
|
|
return getOverdefinedVal(); // always safe, never useful.
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ComputeInstructionState - Given an instruction and a vector of its operand
|
|
|
|
/// values, compute the result value of the instruction.
|
|
|
|
virtual LatticeVal ComputeInstructionState(Instruction &I, SparseSolver &SS) {
|
|
|
|
return getOverdefinedVal(); // always safe, never useful.
|
|
|
|
}
|
|
|
|
|
|
|
|
/// PrintValue - Render the specified lattice value to the specified stream.
|
2009-08-23 04:37:46 +00:00
|
|
|
virtual void PrintValue(LatticeVal V, raw_ostream &OS);
|
2008-05-12 01:12:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// SparseSolver - This class is a general purpose solver for Sparse Conditional
|
|
|
|
/// Propagation with a programmable lattice function.
|
|
|
|
///
|
|
|
|
class SparseSolver {
|
|
|
|
typedef AbstractLatticeFunction::LatticeVal LatticeVal;
|
|
|
|
|
|
|
|
/// LatticeFunc - This is the object that knows the lattice and how to do
|
|
|
|
/// compute transfer functions.
|
|
|
|
AbstractLatticeFunction *LatticeFunc;
|
|
|
|
|
|
|
|
DenseMap<Value*, LatticeVal> ValueState; // The state each value is in.
|
|
|
|
SmallPtrSet<BasicBlock*, 16> BBExecutable; // The bbs that are executable.
|
|
|
|
|
|
|
|
std::vector<Instruction*> InstWorkList; // Worklist of insts to process.
|
|
|
|
|
|
|
|
std::vector<BasicBlock*> BBWorkList; // The BasicBlock work list
|
|
|
|
|
|
|
|
/// KnownFeasibleEdges - Entries in this set are edges which have already had
|
|
|
|
/// PHI nodes retriggered.
|
|
|
|
typedef std::pair<BasicBlock*,BasicBlock*> Edge;
|
|
|
|
std::set<Edge> KnownFeasibleEdges;
|
|
|
|
|
|
|
|
SparseSolver(const SparseSolver&); // DO NOT IMPLEMENT
|
|
|
|
void operator=(const SparseSolver&); // DO NOT IMPLEMENT
|
|
|
|
public:
|
2009-12-18 23:42:08 +00:00
|
|
|
explicit SparseSolver(AbstractLatticeFunction *Lattice)
|
|
|
|
: LatticeFunc(Lattice) {}
|
2008-05-12 01:12:24 +00:00
|
|
|
~SparseSolver() {
|
|
|
|
delete LatticeFunc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Solve - Solve for constants and executable blocks.
|
|
|
|
///
|
|
|
|
void Solve(Function &F);
|
|
|
|
|
2009-08-23 04:37:46 +00:00
|
|
|
void Print(Function &F, raw_ostream &OS) const;
|
2008-05-12 01:12:24 +00:00
|
|
|
|
|
|
|
/// getLatticeState - Return the LatticeVal object that corresponds to the
|
|
|
|
/// value. If an value is not in the map, it is returned as untracked,
|
|
|
|
/// unlike the getOrInitValueState method.
|
|
|
|
LatticeVal getLatticeState(Value *V) const {
|
2009-11-10 01:02:17 +00:00
|
|
|
DenseMap<Value*, LatticeVal>::const_iterator I = ValueState.find(V);
|
2008-05-12 01:12:24 +00:00
|
|
|
return I != ValueState.end() ? I->second : LatticeFunc->getUntrackedVal();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getOrInitValueState - Return the LatticeVal object that corresponds to the
|
|
|
|
/// value, initializing the value's state if it hasn't been entered into the
|
|
|
|
/// map yet. This function is necessary because not all values should start
|
|
|
|
/// out in the underdefined state... Arguments should be overdefined, and
|
|
|
|
/// constants should be marked as constants.
|
|
|
|
///
|
|
|
|
LatticeVal getOrInitValueState(Value *V);
|
|
|
|
|
2008-05-13 22:51:04 +00:00
|
|
|
/// isEdgeFeasible - Return true if the control flow edge from the 'From'
|
2008-05-20 03:39:39 +00:00
|
|
|
/// basic block to the 'To' basic block is currently feasible. If
|
|
|
|
/// AggressiveUndef is true, then this treats values with unknown lattice
|
|
|
|
/// values as undefined. This is generally only useful when solving the
|
|
|
|
/// lattice, not when querying it.
|
|
|
|
bool isEdgeFeasible(BasicBlock *From, BasicBlock *To,
|
|
|
|
bool AggressiveUndef = false);
|
2009-04-09 05:56:58 +00:00
|
|
|
|
|
|
|
/// isBlockExecutable - Return true if there are any known feasible
|
|
|
|
/// edges into the basic block. This is generally only useful when
|
|
|
|
/// querying the lattice.
|
|
|
|
bool isBlockExecutable(BasicBlock *BB) const {
|
|
|
|
return BBExecutable.count(BB);
|
|
|
|
}
|
2008-05-13 22:51:04 +00:00
|
|
|
|
2008-05-12 01:12:24 +00:00
|
|
|
private:
|
|
|
|
/// UpdateState - When the state for some instruction is potentially updated,
|
|
|
|
/// this function notices and adds I to the worklist if needed.
|
|
|
|
void UpdateState(Instruction &Inst, LatticeVal V);
|
|
|
|
|
|
|
|
/// MarkBlockExecutable - This method can be used by clients to mark all of
|
|
|
|
/// the blocks that are known to be intrinsically live in the processed unit.
|
|
|
|
void MarkBlockExecutable(BasicBlock *BB);
|
|
|
|
|
|
|
|
/// markEdgeExecutable - Mark a basic block as executable, adding it to the BB
|
|
|
|
/// work list if it is not already executable.
|
|
|
|
void markEdgeExecutable(BasicBlock *Source, BasicBlock *Dest);
|
|
|
|
|
|
|
|
/// getFeasibleSuccessors - Return a vector of booleans to indicate which
|
|
|
|
/// successors are reachable from a given terminator instruction.
|
2008-05-20 03:39:39 +00:00
|
|
|
void getFeasibleSuccessors(TerminatorInst &TI, SmallVectorImpl<bool> &Succs,
|
|
|
|
bool AggressiveUndef);
|
2008-05-12 01:12:24 +00:00
|
|
|
|
|
|
|
void visitInst(Instruction &I);
|
|
|
|
void visitPHINode(PHINode &I);
|
|
|
|
void visitTerminatorInst(TerminatorInst &TI);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end namespace llvm
|
|
|
|
|
|
|
|
#endif // LLVM_ANALYSIS_SPARSE_PROPAGATION_H
|