Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:17

0001 //===- SparsePropagation.h - Sparse Conditional Property Propagation ------===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file implements an abstract sparse conditional propagation algorithm,
0010 // modeled after SCCP, but with a customizable lattice function.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_ANALYSIS_SPARSEPROPAGATION_H
0015 #define LLVM_ANALYSIS_SPARSEPROPAGATION_H
0016 
0017 #include "llvm/ADT/SmallPtrSet.h"
0018 #include "llvm/IR/Constants.h"
0019 #include "llvm/IR/Instructions.h"
0020 #include "llvm/Support/Debug.h"
0021 #include <set>
0022 
0023 #define DEBUG_TYPE "sparseprop"
0024 
0025 namespace llvm {
0026 
0027 /// A template for translating between LLVM Values and LatticeKeys. Clients must
0028 /// provide a specialization of LatticeKeyInfo for their LatticeKey type.
0029 template <class LatticeKey> struct LatticeKeyInfo {
0030   // static inline Value *getValueFromLatticeKey(LatticeKey Key);
0031   // static inline LatticeKey getLatticeKeyFromValue(Value *V);
0032 };
0033 
0034 template <class LatticeKey, class LatticeVal,
0035           class KeyInfo = LatticeKeyInfo<LatticeKey>>
0036 class SparseSolver;
0037 
0038 /// AbstractLatticeFunction - This class is implemented by the dataflow instance
0039 /// to specify what the lattice values are and how they handle merges etc.  This
0040 /// gives the client the power to compute lattice values from instructions,
0041 /// constants, etc.  The current requirement is that lattice values must be
0042 /// copyable.  At the moment, nothing tries to avoid copying.  Additionally,
0043 /// lattice keys must be able to be used as keys of a mapping data structure.
0044 /// Internally, the generic solver currently uses a DenseMap to map lattice keys
0045 /// to lattice values.  If the lattice key is a non-standard type, a
0046 /// specialization of DenseMapInfo must be provided.
0047 template <class LatticeKey, class LatticeVal> class AbstractLatticeFunction {
0048 private:
0049   LatticeVal UndefVal, OverdefinedVal, UntrackedVal;
0050 
0051 public:
0052   AbstractLatticeFunction(LatticeVal undefVal, LatticeVal overdefinedVal,
0053                           LatticeVal untrackedVal) {
0054     UndefVal = undefVal;
0055     OverdefinedVal = overdefinedVal;
0056     UntrackedVal = untrackedVal;
0057   }
0058 
0059   virtual ~AbstractLatticeFunction() = default;
0060 
0061   LatticeVal getUndefVal()       const { return UndefVal; }
0062   LatticeVal getOverdefinedVal() const { return OverdefinedVal; }
0063   LatticeVal getUntrackedVal()   const { return UntrackedVal; }
0064 
0065   /// IsUntrackedValue - If the specified LatticeKey is obviously uninteresting
0066   /// to the analysis (i.e., it would always return UntrackedVal), this
0067   /// function can return true to avoid pointless work.
0068   virtual bool IsUntrackedValue(LatticeKey Key) { return false; }
0069 
0070   /// ComputeLatticeVal - Compute and return a LatticeVal corresponding to the
0071   /// given LatticeKey.
0072   virtual LatticeVal ComputeLatticeVal(LatticeKey Key) {
0073     return getOverdefinedVal();
0074   }
0075 
0076   /// IsSpecialCasedPHI - Given a PHI node, determine whether this PHI node is
0077   /// one that the we want to handle through ComputeInstructionState.
0078   virtual bool IsSpecialCasedPHI(PHINode *PN) { return false; }
0079 
0080   /// MergeValues - Compute and return the merge of the two specified lattice
0081   /// values.  Merging should only move one direction down the lattice to
0082   /// guarantee convergence (toward overdefined).
0083   virtual LatticeVal MergeValues(LatticeVal X, LatticeVal Y) {
0084     return getOverdefinedVal(); // always safe, never useful.
0085   }
0086 
0087   /// ComputeInstructionState - Compute the LatticeKeys that change as a result
0088   /// of executing instruction \p I. Their associated LatticeVals are store in
0089   /// \p ChangedValues.
0090   virtual void ComputeInstructionState(
0091       Instruction &I, SmallDenseMap<LatticeKey, LatticeVal, 16> &ChangedValues,
0092       SparseSolver<LatticeKey, LatticeVal> &SS) = 0;
0093 
0094   /// PrintLatticeVal - Render the given LatticeVal to the specified stream.
0095   virtual void PrintLatticeVal(LatticeVal LV, raw_ostream &OS);
0096 
0097   /// PrintLatticeKey - Render the given LatticeKey to the specified stream.
0098   virtual void PrintLatticeKey(LatticeKey Key, raw_ostream &OS);
0099 
0100   /// GetValueFromLatticeVal - If the given LatticeVal is representable as an
0101   /// LLVM value, return it; otherwise, return nullptr. If a type is given, the
0102   /// returned value must have the same type. This function is used by the
0103   /// generic solver in attempting to resolve branch and switch conditions.
0104   virtual Value *GetValueFromLatticeVal(LatticeVal LV, Type *Ty = nullptr) {
0105     return nullptr;
0106   }
0107 };
0108 
0109 /// SparseSolver - This class is a general purpose solver for Sparse Conditional
0110 /// Propagation with a programmable lattice function.
0111 template <class LatticeKey, class LatticeVal, class KeyInfo>
0112 class SparseSolver {
0113 
0114   /// LatticeFunc - This is the object that knows the lattice and how to
0115   /// compute transfer functions.
0116   AbstractLatticeFunction<LatticeKey, LatticeVal> *LatticeFunc;
0117 
0118   /// ValueState - Holds the LatticeVals associated with LatticeKeys.
0119   DenseMap<LatticeKey, LatticeVal> ValueState;
0120 
0121   /// BBExecutable - Holds the basic blocks that are executable.
0122   SmallPtrSet<BasicBlock *, 16> BBExecutable;
0123 
0124   /// ValueWorkList - Holds values that should be processed.
0125   SmallVector<Value *, 64> ValueWorkList;
0126 
0127   /// BBWorkList - Holds basic blocks that should be processed.
0128   SmallVector<BasicBlock *, 64> BBWorkList;
0129 
0130   using Edge = std::pair<BasicBlock *, BasicBlock *>;
0131 
0132   /// KnownFeasibleEdges - Entries in this set are edges which have already had
0133   /// PHI nodes retriggered.
0134   std::set<Edge> KnownFeasibleEdges;
0135 
0136 public:
0137   explicit SparseSolver(
0138       AbstractLatticeFunction<LatticeKey, LatticeVal> *Lattice)
0139       : LatticeFunc(Lattice) {}
0140   SparseSolver(const SparseSolver &) = delete;
0141   SparseSolver &operator=(const SparseSolver &) = delete;
0142 
0143   /// Solve - Solve for constants and executable blocks.
0144   void Solve();
0145 
0146   void Print(raw_ostream &OS) const;
0147 
0148   /// getExistingValueState - Return the LatticeVal object corresponding to the
0149   /// given value from the ValueState map. If the value is not in the map,
0150   /// UntrackedVal is returned, unlike the getValueState method.
0151   LatticeVal getExistingValueState(LatticeKey Key) const {
0152     auto I = ValueState.find(Key);
0153     return I != ValueState.end() ? I->second : LatticeFunc->getUntrackedVal();
0154   }
0155 
0156   /// getValueState - Return the LatticeVal object corresponding to the given
0157   /// value from the ValueState map. If the value is not in the map, its state
0158   /// is initialized.
0159   LatticeVal getValueState(LatticeKey Key);
0160 
0161   /// isEdgeFeasible - Return true if the control flow edge from the 'From'
0162   /// basic block to the 'To' basic block is currently feasible.  If
0163   /// AggressiveUndef is true, then this treats values with unknown lattice
0164   /// values as undefined.  This is generally only useful when solving the
0165   /// lattice, not when querying it.
0166   bool isEdgeFeasible(BasicBlock *From, BasicBlock *To,
0167                       bool AggressiveUndef = false);
0168 
0169   /// isBlockExecutable - Return true if there are any known feasible
0170   /// edges into the basic block.  This is generally only useful when
0171   /// querying the lattice.
0172   bool isBlockExecutable(BasicBlock *BB) const {
0173     return BBExecutable.count(BB);
0174   }
0175 
0176   /// MarkBlockExecutable - This method can be used by clients to mark all of
0177   /// the blocks that are known to be intrinsically live in the processed unit.
0178   void MarkBlockExecutable(BasicBlock *BB);
0179 
0180 private:
0181   /// UpdateState - When the state of some LatticeKey is potentially updated to
0182   /// the given LatticeVal, this function notices and adds the LLVM value
0183   /// corresponding the key to the work list, if needed.
0184   void UpdateState(LatticeKey Key, LatticeVal LV);
0185 
0186   /// markEdgeExecutable - Mark a basic block as executable, adding it to the BB
0187   /// work list if it is not already executable.
0188   void markEdgeExecutable(BasicBlock *Source, BasicBlock *Dest);
0189 
0190   /// getFeasibleSuccessors - Return a vector of booleans to indicate which
0191   /// successors are reachable from a given terminator instruction.
0192   void getFeasibleSuccessors(Instruction &TI, SmallVectorImpl<bool> &Succs,
0193                              bool AggressiveUndef);
0194 
0195   void visitInst(Instruction &I);
0196   void visitPHINode(PHINode &I);
0197   void visitTerminator(Instruction &TI);
0198 };
0199 
0200 //===----------------------------------------------------------------------===//
0201 //                  AbstractLatticeFunction Implementation
0202 //===----------------------------------------------------------------------===//
0203 
0204 template <class LatticeKey, class LatticeVal>
0205 void AbstractLatticeFunction<LatticeKey, LatticeVal>::PrintLatticeVal(
0206     LatticeVal V, raw_ostream &OS) {
0207   if (V == UndefVal)
0208     OS << "undefined";
0209   else if (V == OverdefinedVal)
0210     OS << "overdefined";
0211   else if (V == UntrackedVal)
0212     OS << "untracked";
0213   else
0214     OS << "unknown lattice value";
0215 }
0216 
0217 template <class LatticeKey, class LatticeVal>
0218 void AbstractLatticeFunction<LatticeKey, LatticeVal>::PrintLatticeKey(
0219     LatticeKey Key, raw_ostream &OS) {
0220   OS << "unknown lattice key";
0221 }
0222 
0223 //===----------------------------------------------------------------------===//
0224 //                          SparseSolver Implementation
0225 //===----------------------------------------------------------------------===//
0226 
0227 template <class LatticeKey, class LatticeVal, class KeyInfo>
0228 LatticeVal
0229 SparseSolver<LatticeKey, LatticeVal, KeyInfo>::getValueState(LatticeKey Key) {
0230   auto I = ValueState.find(Key);
0231   if (I != ValueState.end())
0232     return I->second; // Common case, in the map
0233 
0234   if (LatticeFunc->IsUntrackedValue(Key))
0235     return LatticeFunc->getUntrackedVal();
0236   LatticeVal LV = LatticeFunc->ComputeLatticeVal(Key);
0237 
0238   // If this value is untracked, don't add it to the map.
0239   if (LV == LatticeFunc->getUntrackedVal())
0240     return LV;
0241   return ValueState[Key] = std::move(LV);
0242 }
0243 
0244 template <class LatticeKey, class LatticeVal, class KeyInfo>
0245 void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::UpdateState(LatticeKey Key,
0246                                                                 LatticeVal LV) {
0247   auto I = ValueState.find(Key);
0248   if (I != ValueState.end() && I->second == LV)
0249     return; // No change.
0250 
0251   // Update the state of the given LatticeKey and add its corresponding LLVM
0252   // value to the work list.
0253   ValueState[Key] = std::move(LV);
0254   if (Value *V = KeyInfo::getValueFromLatticeKey(Key))
0255     ValueWorkList.push_back(V);
0256 }
0257 
0258 template <class LatticeKey, class LatticeVal, class KeyInfo>
0259 void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::MarkBlockExecutable(
0260     BasicBlock *BB) {
0261   if (!BBExecutable.insert(BB).second)
0262     return;
0263   LLVM_DEBUG(dbgs() << "Marking Block Executable: " << BB->getName() << "\n");
0264   BBWorkList.push_back(BB); // Add the block to the work list!
0265 }
0266 
0267 template <class LatticeKey, class LatticeVal, class KeyInfo>
0268 void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::markEdgeExecutable(
0269     BasicBlock *Source, BasicBlock *Dest) {
0270   if (!KnownFeasibleEdges.insert(Edge(Source, Dest)).second)
0271     return; // This edge is already known to be executable!
0272 
0273   LLVM_DEBUG(dbgs() << "Marking Edge Executable: " << Source->getName()
0274                     << " -> " << Dest->getName() << "\n");
0275 
0276   if (BBExecutable.count(Dest)) {
0277     // The destination is already executable, but we just made an edge
0278     // feasible that wasn't before.  Revisit the PHI nodes in the block
0279     // because they have potentially new operands.
0280     for (BasicBlock::iterator I = Dest->begin(); isa<PHINode>(I); ++I)
0281       visitPHINode(*cast<PHINode>(I));
0282   } else {
0283     MarkBlockExecutable(Dest);
0284   }
0285 }
0286 
0287 template <class LatticeKey, class LatticeVal, class KeyInfo>
0288 void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::getFeasibleSuccessors(
0289     Instruction &TI, SmallVectorImpl<bool> &Succs, bool AggressiveUndef) {
0290   Succs.resize(TI.getNumSuccessors());
0291   if (TI.getNumSuccessors() == 0)
0292     return;
0293 
0294   if (BranchInst *BI = dyn_cast<BranchInst>(&TI)) {
0295     if (BI->isUnconditional()) {
0296       Succs[0] = true;
0297       return;
0298     }
0299 
0300     LatticeVal BCValue;
0301     if (AggressiveUndef)
0302       BCValue =
0303           getValueState(KeyInfo::getLatticeKeyFromValue(BI->getCondition()));
0304     else
0305       BCValue = getExistingValueState(
0306           KeyInfo::getLatticeKeyFromValue(BI->getCondition()));
0307 
0308     if (BCValue == LatticeFunc->getOverdefinedVal() ||
0309         BCValue == LatticeFunc->getUntrackedVal()) {
0310       // Overdefined condition variables can branch either way.
0311       Succs[0] = Succs[1] = true;
0312       return;
0313     }
0314 
0315     // If undefined, neither is feasible yet.
0316     if (BCValue == LatticeFunc->getUndefVal())
0317       return;
0318 
0319     Constant *C =
0320         dyn_cast_or_null<Constant>(LatticeFunc->GetValueFromLatticeVal(
0321             std::move(BCValue), BI->getCondition()->getType()));
0322     if (!C || !isa<ConstantInt>(C)) {
0323       // Non-constant values can go either way.
0324       Succs[0] = Succs[1] = true;
0325       return;
0326     }
0327 
0328     // Constant condition variables mean the branch can only go a single way
0329     Succs[C->isNullValue()] = true;
0330     return;
0331   }
0332 
0333   if (!isa<SwitchInst>(TI)) {
0334     // Unknown termintor, assume all successors are feasible.
0335     Succs.assign(Succs.size(), true);
0336     return;
0337   }
0338 
0339   SwitchInst &SI = cast<SwitchInst>(TI);
0340   LatticeVal SCValue;
0341   if (AggressiveUndef)
0342     SCValue = getValueState(KeyInfo::getLatticeKeyFromValue(SI.getCondition()));
0343   else
0344     SCValue = getExistingValueState(
0345         KeyInfo::getLatticeKeyFromValue(SI.getCondition()));
0346 
0347   if (SCValue == LatticeFunc->getOverdefinedVal() ||
0348       SCValue == LatticeFunc->getUntrackedVal()) {
0349     // All destinations are executable!
0350     Succs.assign(TI.getNumSuccessors(), true);
0351     return;
0352   }
0353 
0354   // If undefined, neither is feasible yet.
0355   if (SCValue == LatticeFunc->getUndefVal())
0356     return;
0357 
0358   Constant *C = dyn_cast_or_null<Constant>(LatticeFunc->GetValueFromLatticeVal(
0359       std::move(SCValue), SI.getCondition()->getType()));
0360   if (!C || !isa<ConstantInt>(C)) {
0361     // All destinations are executable!
0362     Succs.assign(TI.getNumSuccessors(), true);
0363     return;
0364   }
0365   SwitchInst::CaseHandle Case = *SI.findCaseValue(cast<ConstantInt>(C));
0366   Succs[Case.getSuccessorIndex()] = true;
0367 }
0368 
0369 template <class LatticeKey, class LatticeVal, class KeyInfo>
0370 bool SparseSolver<LatticeKey, LatticeVal, KeyInfo>::isEdgeFeasible(
0371     BasicBlock *From, BasicBlock *To, bool AggressiveUndef) {
0372   SmallVector<bool, 16> SuccFeasible;
0373   Instruction *TI = From->getTerminator();
0374   getFeasibleSuccessors(*TI, SuccFeasible, AggressiveUndef);
0375 
0376   for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i)
0377     if (TI->getSuccessor(i) == To && SuccFeasible[i])
0378       return true;
0379 
0380   return false;
0381 }
0382 
0383 template <class LatticeKey, class LatticeVal, class KeyInfo>
0384 void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::visitTerminator(
0385     Instruction &TI) {
0386   SmallVector<bool, 16> SuccFeasible;
0387   getFeasibleSuccessors(TI, SuccFeasible, true);
0388 
0389   BasicBlock *BB = TI.getParent();
0390 
0391   // Mark all feasible successors executable...
0392   for (unsigned i = 0, e = SuccFeasible.size(); i != e; ++i)
0393     if (SuccFeasible[i])
0394       markEdgeExecutable(BB, TI.getSuccessor(i));
0395 }
0396 
0397 template <class LatticeKey, class LatticeVal, class KeyInfo>
0398 void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::visitPHINode(PHINode &PN) {
0399   // The lattice function may store more information on a PHINode than could be
0400   // computed from its incoming values.  For example, SSI form stores its sigma
0401   // functions as PHINodes with a single incoming value.
0402   if (LatticeFunc->IsSpecialCasedPHI(&PN)) {
0403     SmallDenseMap<LatticeKey, LatticeVal, 16> ChangedValues;
0404     LatticeFunc->ComputeInstructionState(PN, ChangedValues, *this);
0405     for (auto &ChangedValue : ChangedValues)
0406       if (ChangedValue.second != LatticeFunc->getUntrackedVal())
0407         UpdateState(std::move(ChangedValue.first),
0408                     std::move(ChangedValue.second));
0409     return;
0410   }
0411 
0412   LatticeKey Key = KeyInfo::getLatticeKeyFromValue(&PN);
0413   LatticeVal PNIV = getValueState(Key);
0414   LatticeVal Overdefined = LatticeFunc->getOverdefinedVal();
0415 
0416   // If this value is already overdefined (common) just return.
0417   if (PNIV == Overdefined || PNIV == LatticeFunc->getUntrackedVal())
0418     return; // Quick exit
0419 
0420   // Super-extra-high-degree PHI nodes are unlikely to ever be interesting,
0421   // and slow us down a lot.  Just mark them overdefined.
0422   if (PN.getNumIncomingValues() > 64) {
0423     UpdateState(Key, Overdefined);
0424     return;
0425   }
0426 
0427   // Look at all of the executable operands of the PHI node.  If any of them
0428   // are overdefined, the PHI becomes overdefined as well.  Otherwise, ask the
0429   // transfer function to give us the merge of the incoming values.
0430   for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) {
0431     // If the edge is not yet known to be feasible, it doesn't impact the PHI.
0432     if (!isEdgeFeasible(PN.getIncomingBlock(i), PN.getParent(), true))
0433       continue;
0434 
0435     // Merge in this value.
0436     LatticeVal OpVal =
0437         getValueState(KeyInfo::getLatticeKeyFromValue(PN.getIncomingValue(i)));
0438     if (OpVal != PNIV)
0439       PNIV = LatticeFunc->MergeValues(PNIV, OpVal);
0440 
0441     if (PNIV == Overdefined)
0442       break; // Rest of input values don't matter.
0443   }
0444 
0445   // Update the PHI with the compute value, which is the merge of the inputs.
0446   UpdateState(Key, PNIV);
0447 }
0448 
0449 template <class LatticeKey, class LatticeVal, class KeyInfo>
0450 void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::visitInst(Instruction &I) {
0451   // PHIs are handled by the propagation logic, they are never passed into the
0452   // transfer functions.
0453   if (PHINode *PN = dyn_cast<PHINode>(&I))
0454     return visitPHINode(*PN);
0455 
0456   // Otherwise, ask the transfer function what the result is.  If this is
0457   // something that we care about, remember it.
0458   SmallDenseMap<LatticeKey, LatticeVal, 16> ChangedValues;
0459   LatticeFunc->ComputeInstructionState(I, ChangedValues, *this);
0460   for (auto &ChangedValue : ChangedValues)
0461     if (ChangedValue.second != LatticeFunc->getUntrackedVal())
0462       UpdateState(ChangedValue.first, ChangedValue.second);
0463 
0464   if (I.isTerminator())
0465     visitTerminator(I);
0466 }
0467 
0468 template <class LatticeKey, class LatticeVal, class KeyInfo>
0469 void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::Solve() {
0470   // Process the work lists until they are empty!
0471   while (!BBWorkList.empty() || !ValueWorkList.empty()) {
0472     // Process the value work list.
0473     while (!ValueWorkList.empty()) {
0474       Value *V = ValueWorkList.pop_back_val();
0475 
0476       LLVM_DEBUG(dbgs() << "\nPopped off V-WL: " << *V << "\n");
0477 
0478       // "V" got into the work list because it made a transition. See if any
0479       // users are both live and in need of updating.
0480       for (User *U : V->users())
0481         if (Instruction *Inst = dyn_cast<Instruction>(U))
0482           if (BBExecutable.count(Inst->getParent())) // Inst is executable?
0483             visitInst(*Inst);
0484     }
0485 
0486     // Process the basic block work list.
0487     while (!BBWorkList.empty()) {
0488       BasicBlock *BB = BBWorkList.pop_back_val();
0489 
0490       LLVM_DEBUG(dbgs() << "\nPopped off BBWL: " << *BB);
0491 
0492       // Notify all instructions in this basic block that they are newly
0493       // executable.
0494       for (Instruction &I : *BB)
0495         visitInst(I);
0496     }
0497   }
0498 }
0499 
0500 template <class LatticeKey, class LatticeVal, class KeyInfo>
0501 void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::Print(
0502     raw_ostream &OS) const {
0503   if (ValueState.empty())
0504     return;
0505 
0506   LatticeKey Key;
0507   LatticeVal LV;
0508 
0509   OS << "ValueState:\n";
0510   for (auto &Entry : ValueState) {
0511     std::tie(Key, LV) = Entry;
0512     if (LV == LatticeFunc->getUntrackedVal())
0513       continue;
0514     OS << "\t";
0515     LatticeFunc->PrintLatticeVal(LV, OS);
0516     OS << ": ";
0517     LatticeFunc->PrintLatticeKey(Key, OS);
0518     OS << "\n";
0519   }
0520 }
0521 } // end namespace llvm
0522 
0523 #undef DEBUG_TYPE
0524 
0525 #endif // LLVM_ANALYSIS_SPARSEPROPAGATION_H