[llvm] r314734 - Template the sparse propagation solver instead of using void pointers

Daniel Berlin via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 2 15:49:49 PDT 2017


Author: dannyb
Date: Mon Oct  2 15:49:49 2017
New Revision: 314734

URL: http://llvm.org/viewvc/llvm-project?rev=314734&view=rev
Log:
Template the sparse propagation solver instead of using void pointers

Summary:
This avoids using void * as the type of the lattice value and ugly casts needed to make that happen.
(If folks want to use references, etc, they can use a reference_wrapper).

Reviewers: davide, mssimpso

Subscribers: sanjoy, llvm-commits

Differential Revision: https://reviews.llvm.org/D38476

Modified:
    llvm/trunk/include/llvm/Analysis/SparsePropagation.h
    llvm/trunk/lib/Analysis/SparsePropagation.cpp

Modified: llvm/trunk/include/llvm/Analysis/SparsePropagation.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/SparsePropagation.h?rev=314734&r1=314733&r2=314734&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/SparsePropagation.h (original)
+++ llvm/trunk/include/llvm/Analysis/SparsePropagation.h Mon Oct  2 15:49:49 2017
@@ -30,22 +30,19 @@ class Function;
 class Instruction;
 class PHINode;
 class raw_ostream;
-class SparseSolver;
+template <class LatticeVal> class SparseSolver;
 class TerminatorInst;
 class Value;
 template <typename T> class SmallVectorImpl;
 
 /// AbstractLatticeFunction - This class is implemented by the dataflow instance
-/// to specify what the lattice values are and how they handle merges etc.
-/// 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:
-  using LatticeVal = void *;
+/// to specify what the lattice values are and how they handle merges etc.  This
+/// gives the client the power to compute lattice values from instructions,
+/// constants, etc.  The current requirement is that lattice values must be
+/// copyable.  At the moment, nothing tries to avoid copying.
+
 
+template <class LatticeVal> class AbstractLatticeFunction {
 private:
   LatticeVal UndefVal, OverdefinedVal, UntrackedVal;
 
@@ -81,7 +78,8 @@ public:
   /// 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) {
+  virtual Constant *GetConstant(LatticeVal LV, Value *Val,
+                                SparseSolver<LatticeVal> &SS) {
     return nullptr;
   }
 
@@ -100,7 +98,8 @@ public:
 
   /// 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) {
+  virtual LatticeVal ComputeInstructionState(Instruction &I,
+                                             SparseSolver<LatticeVal> &SS) {
     return getOverdefinedVal(); // always safe, never useful.
   }
 
@@ -110,12 +109,11 @@ public:
 
 /// SparseSolver - This class is a general purpose solver for Sparse Conditional
 /// Propagation with a programmable lattice function.
-class SparseSolver {
-  using LatticeVal = AbstractLatticeFunction::LatticeVal;
+template <class LatticeVal> class SparseSolver {
 
   /// LatticeFunc - This is the object that knows the lattice and how to do
   /// compute transfer functions.
-  AbstractLatticeFunction *LatticeFunc;
+  AbstractLatticeFunction<LatticeVal> *LatticeFunc;
 
   DenseMap<Value *, LatticeVal> ValueState;   // The state each value is in.
   SmallPtrSet<BasicBlock *, 16> BBExecutable; // The bbs that are executable.
@@ -130,7 +128,7 @@ class SparseSolver {
   std::set<Edge> KnownFeasibleEdges;
 
 public:
-  explicit SparseSolver(AbstractLatticeFunction *Lattice)
+  explicit SparseSolver(AbstractLatticeFunction<LatticeVal> *Lattice)
       : LatticeFunc(Lattice) {}
   SparseSolver(const SparseSolver &) = delete;
   SparseSolver &operator=(const SparseSolver &) = delete;
@@ -145,7 +143,7 @@ public:
   /// value.  If an value is not in the map, it is returned as untracked,
   /// unlike the getOrInitValueState method.
   LatticeVal getLatticeState(Value *V) const {
-    DenseMap<Value*, LatticeVal>::const_iterator I = ValueState.find(V);
+    auto I = ValueState.find(V);
     return I != ValueState.end() ? I->second : LatticeFunc->getUntrackedVal();
   }
 

Modified: llvm/trunk/lib/Analysis/SparsePropagation.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/SparsePropagation.cpp?rev=314734&r1=314733&r2=314734&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/SparsePropagation.cpp (original)
+++ llvm/trunk/lib/Analysis/SparsePropagation.cpp Mon Oct  2 15:49:49 2017
@@ -36,10 +36,13 @@ using namespace llvm;
 //                  AbstractLatticeFunction Implementation
 //===----------------------------------------------------------------------===//
 
-AbstractLatticeFunction::~AbstractLatticeFunction() = default;
+template <class LatticeVal>
+AbstractLatticeFunction<LatticeVal>::~AbstractLatticeFunction() = default;
 
 /// PrintValue - Render the specified lattice value to the specified stream.
-void AbstractLatticeFunction::PrintValue(LatticeVal V, raw_ostream &OS) {
+template <class LatticeVal>
+void AbstractLatticeFunction<LatticeVal>::PrintValue(LatticeVal V,
+                                                     raw_ostream &OS) {
   if (V == UndefVal)
     OS << "undefined";
   else if (V == OverdefinedVal)
@@ -59,8 +62,9 @@ void AbstractLatticeFunction::PrintValue
 /// 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.
-SparseSolver::LatticeVal SparseSolver::getOrInitValueState(Value *V) {
-  DenseMap<Value*, LatticeVal>::iterator I = ValueState.find(V);
+template <class LatticeVal>
+LatticeVal SparseSolver<LatticeVal>::getOrInitValueState(Value *V) {
+  auto I = ValueState.find(V);
   if (I != ValueState.end()) return I->second;  // Common case, in the map
   
   LatticeVal LV;
@@ -85,8 +89,9 @@ SparseSolver::LatticeVal SparseSolver::g
 
 /// UpdateState - When the state for some instruction is potentially updated,
 /// this function notices and adds I to the worklist if needed.
-void SparseSolver::UpdateState(Instruction &Inst, LatticeVal V) {
-  DenseMap<Value*, LatticeVal>::iterator I = ValueState.find(&Inst);
+template <class LatticeVal>
+void SparseSolver<LatticeVal>::UpdateState(Instruction &Inst, LatticeVal V) {
+  auto I = ValueState.find(&Inst);
   if (I != ValueState.end() && I->second == V)
     return;  // No change.
   
@@ -97,7 +102,8 @@ void SparseSolver::UpdateState(Instructi
 
 /// 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 SparseSolver::MarkBlockExecutable(BasicBlock *BB) {
+template <class LatticeVal>
+void SparseSolver<LatticeVal>::MarkBlockExecutable(BasicBlock *BB) {
   DEBUG(dbgs() << "Marking Block Executable: " << BB->getName() << "\n");
   BBExecutable.insert(BB);   // Basic block is executable!
   BBWorkList.push_back(BB);  // Add the block to the work list!
@@ -105,7 +111,9 @@ void SparseSolver::MarkBlockExecutable(B
 
 /// markEdgeExecutable - Mark a basic block as executable, adding it to the BB
 /// work list if it is not already executable...
-void SparseSolver::markEdgeExecutable(BasicBlock *Source, BasicBlock *Dest) {
+template <class LatticeVal>
+void SparseSolver<LatticeVal>::markEdgeExecutable(BasicBlock *Source,
+                                                  BasicBlock *Dest) {
   if (!KnownFeasibleEdges.insert(Edge(Source, Dest)).second)
     return;  // This edge is already known to be executable!
   
@@ -125,9 +133,9 @@ void SparseSolver::markEdgeExecutable(Ba
 
 /// getFeasibleSuccessors - Return a vector of booleans to indicate which
 /// successors are reachable from a given terminator instruction.
-void SparseSolver::getFeasibleSuccessors(TerminatorInst &TI,
-                                         SmallVectorImpl<bool> &Succs,
-                                         bool AggressiveUndef) {
+template <class LatticeVal>
+void SparseSolver<LatticeVal>::getFeasibleSuccessors(
+    TerminatorInst &TI, SmallVectorImpl<bool> &Succs, bool AggressiveUndef) {
   Succs.resize(TI.getNumSuccessors());
   if (TI.getNumSuccessors() == 0) return;
   
@@ -208,8 +216,9 @@ void SparseSolver::getFeasibleSuccessors
 
 /// isEdgeFeasible - Return true if the control flow edge from the 'From'
 /// basic block to the 'To' basic block is currently feasible...
-bool SparseSolver::isEdgeFeasible(BasicBlock *From, BasicBlock *To,
-                                  bool AggressiveUndef) {
+template <class LatticeVal>
+bool SparseSolver<LatticeVal>::isEdgeFeasible(BasicBlock *From, BasicBlock *To,
+                                              bool AggressiveUndef) {
   SmallVector<bool, 16> SuccFeasible;
   TerminatorInst *TI = From->getTerminator();
   getFeasibleSuccessors(*TI, SuccFeasible, AggressiveUndef);
@@ -221,7 +230,8 @@ bool SparseSolver::isEdgeFeasible(BasicB
   return false;
 }
 
-void SparseSolver::visitTerminatorInst(TerminatorInst &TI) {
+template <class LatticeVal>
+void SparseSolver<LatticeVal>::visitTerminatorInst(TerminatorInst &TI) {
   SmallVector<bool, 16> SuccFeasible;
   getFeasibleSuccessors(TI, SuccFeasible, true);
   
@@ -233,7 +243,8 @@ void SparseSolver::visitTerminatorInst(T
       markEdgeExecutable(BB, TI.getSuccessor(i));
 }
 
-void SparseSolver::visitPHINode(PHINode &PN) {
+template <class LatticeVal>
+void SparseSolver<LatticeVal>::visitPHINode(PHINode &PN) {
   // The lattice function may store more information on a PHINode than could be
   // computed from its incoming values.  For example, SSI form stores its sigma
   // functions as PHINodes with a single incoming value.
@@ -279,7 +290,8 @@ void SparseSolver::visitPHINode(PHINode
   UpdateState(PN, PNIV);
 }
 
-void SparseSolver::visitInst(Instruction &I) {
+template <class LatticeVal>
+void SparseSolver<LatticeVal>::visitInst(Instruction &I) {
   // PHIs are handled by the propagation logic, they are never passed into the
   // transfer functions.
   if (PHINode *PN = dyn_cast<PHINode>(&I))
@@ -295,7 +307,7 @@ void SparseSolver::visitInst(Instruction
     visitTerminatorInst(*TI);
 }
 
-void SparseSolver::Solve(Function &F) {
+template <class LatticeVal> void SparseSolver<LatticeVal>::Solve(Function &F) {
   MarkBlockExecutable(&F.getEntryBlock());
   
   // Process the work lists until they are empty!
@@ -331,7 +343,8 @@ void SparseSolver::Solve(Function &F) {
   }
 }
 
-void SparseSolver::Print(Function &F, raw_ostream &OS) const {
+template <class LatticeVal>
+void SparseSolver<LatticeVal>::Print(Function &F, raw_ostream &OS) const {
   OS << "\nFUNCTION: " << F.getName() << "\n";
   for (auto &BB : F) {
     if (!BBExecutable.count(&BB))




More information about the llvm-commits mailing list