File indexing completed on 2026-05-10 08:43:17
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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
0028
0029 template <class LatticeKey> struct LatticeKeyInfo {
0030
0031
0032 };
0033
0034 template <class LatticeKey, class LatticeVal,
0035 class KeyInfo = LatticeKeyInfo<LatticeKey>>
0036 class SparseSolver;
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
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
0066
0067
0068 virtual bool IsUntrackedValue(LatticeKey Key) { return false; }
0069
0070
0071
0072 virtual LatticeVal ComputeLatticeVal(LatticeKey Key) {
0073 return getOverdefinedVal();
0074 }
0075
0076
0077
0078 virtual bool IsSpecialCasedPHI(PHINode *PN) { return false; }
0079
0080
0081
0082
0083 virtual LatticeVal MergeValues(LatticeVal X, LatticeVal Y) {
0084 return getOverdefinedVal();
0085 }
0086
0087
0088
0089
0090 virtual void ComputeInstructionState(
0091 Instruction &I, SmallDenseMap<LatticeKey, LatticeVal, 16> &ChangedValues,
0092 SparseSolver<LatticeKey, LatticeVal> &SS) = 0;
0093
0094
0095 virtual void PrintLatticeVal(LatticeVal LV, raw_ostream &OS);
0096
0097
0098 virtual void PrintLatticeKey(LatticeKey Key, raw_ostream &OS);
0099
0100
0101
0102
0103
0104 virtual Value *GetValueFromLatticeVal(LatticeVal LV, Type *Ty = nullptr) {
0105 return nullptr;
0106 }
0107 };
0108
0109
0110
0111 template <class LatticeKey, class LatticeVal, class KeyInfo>
0112 class SparseSolver {
0113
0114
0115
0116 AbstractLatticeFunction<LatticeKey, LatticeVal> *LatticeFunc;
0117
0118
0119 DenseMap<LatticeKey, LatticeVal> ValueState;
0120
0121
0122 SmallPtrSet<BasicBlock *, 16> BBExecutable;
0123
0124
0125 SmallVector<Value *, 64> ValueWorkList;
0126
0127
0128 SmallVector<BasicBlock *, 64> BBWorkList;
0129
0130 using Edge = std::pair<BasicBlock *, BasicBlock *>;
0131
0132
0133
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
0144 void Solve();
0145
0146 void Print(raw_ostream &OS) const;
0147
0148
0149
0150
0151 LatticeVal getExistingValueState(LatticeKey Key) const {
0152 auto I = ValueState.find(Key);
0153 return I != ValueState.end() ? I->second : LatticeFunc->getUntrackedVal();
0154 }
0155
0156
0157
0158
0159 LatticeVal getValueState(LatticeKey Key);
0160
0161
0162
0163
0164
0165
0166 bool isEdgeFeasible(BasicBlock *From, BasicBlock *To,
0167 bool AggressiveUndef = false);
0168
0169
0170
0171
0172 bool isBlockExecutable(BasicBlock *BB) const {
0173 return BBExecutable.count(BB);
0174 }
0175
0176
0177
0178 void MarkBlockExecutable(BasicBlock *BB);
0179
0180 private:
0181
0182
0183
0184 void UpdateState(LatticeKey Key, LatticeVal LV);
0185
0186
0187
0188 void markEdgeExecutable(BasicBlock *Source, BasicBlock *Dest);
0189
0190
0191
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
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
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;
0233
0234 if (LatticeFunc->IsUntrackedValue(Key))
0235 return LatticeFunc->getUntrackedVal();
0236 LatticeVal LV = LatticeFunc->ComputeLatticeVal(Key);
0237
0238
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;
0250
0251
0252
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);
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;
0272
0273 LLVM_DEBUG(dbgs() << "Marking Edge Executable: " << Source->getName()
0274 << " -> " << Dest->getName() << "\n");
0275
0276 if (BBExecutable.count(Dest)) {
0277
0278
0279
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
0311 Succs[0] = Succs[1] = true;
0312 return;
0313 }
0314
0315
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
0324 Succs[0] = Succs[1] = true;
0325 return;
0326 }
0327
0328
0329 Succs[C->isNullValue()] = true;
0330 return;
0331 }
0332
0333 if (!isa<SwitchInst>(TI)) {
0334
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
0350 Succs.assign(TI.getNumSuccessors(), true);
0351 return;
0352 }
0353
0354
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
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
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
0400
0401
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
0417 if (PNIV == Overdefined || PNIV == LatticeFunc->getUntrackedVal())
0418 return;
0419
0420
0421
0422 if (PN.getNumIncomingValues() > 64) {
0423 UpdateState(Key, Overdefined);
0424 return;
0425 }
0426
0427
0428
0429
0430 for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) {
0431
0432 if (!isEdgeFeasible(PN.getIncomingBlock(i), PN.getParent(), true))
0433 continue;
0434
0435
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;
0443 }
0444
0445
0446 UpdateState(Key, PNIV);
0447 }
0448
0449 template <class LatticeKey, class LatticeVal, class KeyInfo>
0450 void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::visitInst(Instruction &I) {
0451
0452
0453 if (PHINode *PN = dyn_cast<PHINode>(&I))
0454 return visitPHINode(*PN);
0455
0456
0457
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
0471 while (!BBWorkList.empty() || !ValueWorkList.empty()) {
0472
0473 while (!ValueWorkList.empty()) {
0474 Value *V = ValueWorkList.pop_back_val();
0475
0476 LLVM_DEBUG(dbgs() << "\nPopped off V-WL: " << *V << "\n");
0477
0478
0479
0480 for (User *U : V->users())
0481 if (Instruction *Inst = dyn_cast<Instruction>(U))
0482 if (BBExecutable.count(Inst->getParent()))
0483 visitInst(*Inst);
0484 }
0485
0486
0487 while (!BBWorkList.empty()) {
0488 BasicBlock *BB = BBWorkList.pop_back_val();
0489
0490 LLVM_DEBUG(dbgs() << "\nPopped off BBWL: " << *BB);
0491
0492
0493
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 }
0522
0523 #undef DEBUG_TYPE
0524
0525 #endif