1 //===-- ConstraintElimination.cpp - Eliminate conds using constraints. ----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Eliminate conditions based on constraints collected from dominating 10 // conditions. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Transforms/Scalar/ConstraintElimination.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/ADT/ScopeExit.h" 17 #include "llvm/ADT/SmallVector.h" 18 #include "llvm/ADT/Statistic.h" 19 #include "llvm/Analysis/ConstraintSystem.h" 20 #include "llvm/Analysis/GlobalsModRef.h" 21 #include "llvm/IR/DataLayout.h" 22 #include "llvm/IR/Dominators.h" 23 #include "llvm/IR/Function.h" 24 #include "llvm/IR/Instructions.h" 25 #include "llvm/IR/PatternMatch.h" 26 #include "llvm/InitializePasses.h" 27 #include "llvm/Pass.h" 28 #include "llvm/Support/Debug.h" 29 #include "llvm/Support/DebugCounter.h" 30 #include "llvm/Transforms/Scalar.h" 31 32 #include <string> 33 34 using namespace llvm; 35 using namespace PatternMatch; 36 37 #define DEBUG_TYPE "constraint-elimination" 38 39 STATISTIC(NumCondsRemoved, "Number of instructions removed"); 40 DEBUG_COUNTER(EliminatedCounter, "conds-eliminated", 41 "Controls which conditions are eliminated"); 42 43 static int64_t MaxConstraintValue = std::numeric_limits<int64_t>::max(); 44 45 // Decomposes \p V into a vector of pairs of the form { c, X } where c * X. The 46 // sum of the pairs equals \p V. The first pair is the constant-factor and X 47 // must be nullptr. If the expression cannot be decomposed, returns an empty 48 // vector. 49 static SmallVector<std::pair<int64_t, Value *>, 4> decompose(Value *V) { 50 if (auto *CI = dyn_cast<ConstantInt>(V)) { 51 if (CI->isNegative() || CI->uge(MaxConstraintValue)) 52 return {}; 53 return {{CI->getSExtValue(), nullptr}}; 54 } 55 auto *GEP = dyn_cast<GetElementPtrInst>(V); 56 if (GEP && GEP->getNumOperands() == 2 && GEP->isInBounds()) { 57 if (isa<ConstantInt>(GEP->getOperand(GEP->getNumOperands() - 1))) { 58 return {{cast<ConstantInt>(GEP->getOperand(GEP->getNumOperands() - 1)) 59 ->getSExtValue(), 60 nullptr}, 61 {1, GEP->getPointerOperand()}}; 62 } 63 Value *Op0; 64 ConstantInt *CI; 65 if (match(GEP->getOperand(GEP->getNumOperands() - 1), 66 m_NUWShl(m_Value(Op0), m_ConstantInt(CI)))) 67 return {{0, nullptr}, 68 {1, GEP->getPointerOperand()}, 69 {std::pow(int64_t(2), CI->getSExtValue()), Op0}}; 70 if (match(GEP->getOperand(GEP->getNumOperands() - 1), 71 m_ZExt(m_NUWShl(m_Value(Op0), m_ConstantInt(CI))))) 72 return {{0, nullptr}, 73 {1, GEP->getPointerOperand()}, 74 {std::pow(int64_t(2), CI->getSExtValue()), Op0}}; 75 76 return {{0, nullptr}, 77 {1, GEP->getPointerOperand()}, 78 {1, GEP->getOperand(GEP->getNumOperands() - 1)}}; 79 } 80 81 Value *Op0; 82 if (match(V, m_ZExt(m_Value(Op0)))) 83 V = Op0; 84 85 Value *Op1; 86 ConstantInt *CI; 87 if (match(V, m_NUWAdd(m_Value(Op0), m_ConstantInt(CI)))) 88 return {{CI->getSExtValue(), nullptr}, {1, Op0}}; 89 if (match(V, m_NUWAdd(m_Value(Op0), m_Value(Op1)))) 90 return {{0, nullptr}, {1, Op0}, {1, Op1}}; 91 92 if (match(V, m_NUWSub(m_Value(Op0), m_ConstantInt(CI)))) 93 return {{-1 * CI->getSExtValue(), nullptr}, {1, Op0}}; 94 if (match(V, m_NUWSub(m_Value(Op0), m_Value(Op1)))) 95 return {{0, nullptr}, {1, Op0}, {1, Op1}}; 96 97 return {{0, nullptr}, {1, V}}; 98 } 99 100 struct ConstraintTy { 101 SmallVector<int64_t, 8> Coefficients; 102 103 ConstraintTy(SmallVector<int64_t, 8> Coefficients) 104 : Coefficients(Coefficients) {} 105 106 unsigned size() const { return Coefficients.size(); } 107 }; 108 109 /// Turn a condition \p CmpI into a vector of constraints, using indices from \p 110 /// Value2Index. Additional indices for newly discovered values are added to \p 111 /// NewIndices. 112 static SmallVector<ConstraintTy, 4> 113 getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1, 114 const DenseMap<Value *, unsigned> &Value2Index, 115 DenseMap<Value *, unsigned> &NewIndices) { 116 int64_t Offset1 = 0; 117 int64_t Offset2 = 0; 118 119 // First try to look up \p V in Value2Index and NewIndices. Otherwise add a 120 // new entry to NewIndices. 121 auto GetOrAddIndex = [&Value2Index, &NewIndices](Value *V) -> unsigned { 122 auto V2I = Value2Index.find(V); 123 if (V2I != Value2Index.end()) 124 return V2I->second; 125 auto NewI = NewIndices.find(V); 126 if (NewI != NewIndices.end()) 127 return NewI->second; 128 auto Insert = 129 NewIndices.insert({V, Value2Index.size() + NewIndices.size() + 1}); 130 return Insert.first->second; 131 }; 132 133 if (Pred == CmpInst::ICMP_UGT || Pred == CmpInst::ICMP_UGE) 134 return getConstraint(CmpInst::getSwappedPredicate(Pred), Op1, Op0, 135 Value2Index, NewIndices); 136 137 if (Pred == CmpInst::ICMP_EQ) { 138 auto A = 139 getConstraint(CmpInst::ICMP_UGE, Op0, Op1, Value2Index, NewIndices); 140 auto B = 141 getConstraint(CmpInst::ICMP_ULE, Op0, Op1, Value2Index, NewIndices); 142 append_range(A, B); 143 return A; 144 } 145 146 // Only ULE and ULT predicates are supported at the moment. 147 if (Pred != CmpInst::ICMP_ULE && Pred != CmpInst::ICMP_ULT) 148 return {}; 149 150 auto ADec = decompose(Op0->stripPointerCasts()); 151 auto BDec = decompose(Op1->stripPointerCasts()); 152 // Skip if decomposing either of the values failed. 153 if (ADec.empty() || BDec.empty()) 154 return {}; 155 156 // Skip trivial constraints without any variables. 157 if (ADec.size() == 1 && BDec.size() == 1) 158 return {}; 159 160 Offset1 = ADec[0].first; 161 Offset2 = BDec[0].first; 162 Offset1 *= -1; 163 164 // Create iterator ranges that skip the constant-factor. 165 auto VariablesA = make_range(std::next(ADec.begin()), ADec.end()); 166 auto VariablesB = make_range(std::next(BDec.begin()), BDec.end()); 167 168 // Make sure all variables have entries in Value2Index or NewIndices. 169 for (const auto &KV : 170 concat<std::pair<int64_t, Value *>>(VariablesA, VariablesB)) 171 GetOrAddIndex(KV.second); 172 173 // Build result constraint, by first adding all coefficients from A and then 174 // subtracting all coefficients from B. 175 SmallVector<int64_t, 8> R(Value2Index.size() + NewIndices.size() + 1, 0); 176 for (const auto &KV : VariablesA) 177 R[GetOrAddIndex(KV.second)] += KV.first; 178 179 for (const auto &KV : VariablesB) 180 R[GetOrAddIndex(KV.second)] -= KV.first; 181 182 R[0] = Offset1 + Offset2 + (Pred == CmpInst::ICMP_ULT ? -1 : 0); 183 return {R}; 184 } 185 186 static SmallVector<ConstraintTy, 4> 187 getConstraint(CmpInst *Cmp, const DenseMap<Value *, unsigned> &Value2Index, 188 DenseMap<Value *, unsigned> &NewIndices) { 189 return getConstraint(Cmp->getPredicate(), Cmp->getOperand(0), 190 Cmp->getOperand(1), Value2Index, NewIndices); 191 } 192 193 namespace { 194 /// Represents either a condition that holds on entry to a block or a basic 195 /// block, with their respective Dominator DFS in and out numbers. 196 struct ConstraintOrBlock { 197 unsigned NumIn; 198 unsigned NumOut; 199 bool IsBlock; 200 bool Not; 201 union { 202 BasicBlock *BB; 203 CmpInst *Condition; 204 }; 205 206 ConstraintOrBlock(DomTreeNode *DTN) 207 : NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), IsBlock(true), 208 BB(DTN->getBlock()) {} 209 ConstraintOrBlock(DomTreeNode *DTN, CmpInst *Condition, bool Not) 210 : NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), IsBlock(false), 211 Not(Not), Condition(Condition) {} 212 }; 213 214 struct StackEntry { 215 unsigned NumIn; 216 unsigned NumOut; 217 CmpInst *Condition; 218 bool IsNot; 219 220 StackEntry(unsigned NumIn, unsigned NumOut, CmpInst *Condition, bool IsNot) 221 : NumIn(NumIn), NumOut(NumOut), Condition(Condition), IsNot(IsNot) {} 222 }; 223 } // namespace 224 225 #ifndef NDEBUG 226 static void dumpWithNames(ConstraintTy &C, 227 DenseMap<Value *, unsigned> &Value2Index) { 228 SmallVector<std::string> Names(Value2Index.size(), ""); 229 for (auto &KV : Value2Index) { 230 Names[KV.second - 1] = std::string("%") + KV.first->getName().str(); 231 } 232 ConstraintSystem CS; 233 CS.addVariableRowFill(C.Coefficients); 234 CS.dump(Names); 235 } 236 #endif 237 238 static bool eliminateConstraints(Function &F, DominatorTree &DT) { 239 bool Changed = false; 240 DT.updateDFSNumbers(); 241 ConstraintSystem CS; 242 243 SmallVector<ConstraintOrBlock, 64> WorkList; 244 245 // First, collect conditions implied by branches and blocks with their 246 // Dominator DFS in and out numbers. 247 for (BasicBlock &BB : F) { 248 if (!DT.getNode(&BB)) 249 continue; 250 WorkList.emplace_back(DT.getNode(&BB)); 251 252 auto *Br = dyn_cast<BranchInst>(BB.getTerminator()); 253 if (!Br || !Br->isConditional()) 254 continue; 255 256 // Returns true if we can add a known condition from BB to its successor 257 // block Succ. Each predecessor of Succ can either be BB or be dominated by 258 // Succ (e.g. the case when adding a condition from a pre-header to a loop 259 // header). 260 auto CanAdd = [&BB, &DT](BasicBlock *Succ) { 261 return all_of(predecessors(Succ), [&BB, &DT, Succ](BasicBlock *Pred) { 262 return Pred == &BB || DT.dominates(Succ, Pred); 263 }); 264 }; 265 // If the condition is an OR of 2 compares and the false successor only has 266 // the current block as predecessor, queue both negated conditions for the 267 // false successor. 268 Value *Op0, *Op1; 269 if (match(Br->getCondition(), m_LogicalOr(m_Value(Op0), m_Value(Op1))) && 270 match(Op0, m_Cmp()) && match(Op1, m_Cmp())) { 271 BasicBlock *FalseSuccessor = Br->getSuccessor(1); 272 if (CanAdd(FalseSuccessor)) { 273 WorkList.emplace_back(DT.getNode(FalseSuccessor), cast<CmpInst>(Op0), 274 true); 275 WorkList.emplace_back(DT.getNode(FalseSuccessor), cast<CmpInst>(Op1), 276 true); 277 } 278 continue; 279 } 280 281 // If the condition is an AND of 2 compares and the true successor only has 282 // the current block as predecessor, queue both conditions for the true 283 // successor. 284 if (match(Br->getCondition(), m_LogicalAnd(m_Value(Op0), m_Value(Op1))) && 285 match(Op0, m_Cmp()) && match(Op1, m_Cmp())) { 286 BasicBlock *TrueSuccessor = Br->getSuccessor(0); 287 if (CanAdd(TrueSuccessor)) { 288 WorkList.emplace_back(DT.getNode(TrueSuccessor), cast<CmpInst>(Op0), 289 false); 290 WorkList.emplace_back(DT.getNode(TrueSuccessor), cast<CmpInst>(Op1), 291 false); 292 } 293 continue; 294 } 295 296 auto *CmpI = dyn_cast<CmpInst>(Br->getCondition()); 297 if (!CmpI) 298 continue; 299 if (CanAdd(Br->getSuccessor(0))) 300 WorkList.emplace_back(DT.getNode(Br->getSuccessor(0)), CmpI, false); 301 if (CanAdd(Br->getSuccessor(1))) 302 WorkList.emplace_back(DT.getNode(Br->getSuccessor(1)), CmpI, true); 303 } 304 305 // Next, sort worklist by dominance, so that dominating blocks and conditions 306 // come before blocks and conditions dominated by them. If a block and a 307 // condition have the same numbers, the condition comes before the block, as 308 // it holds on entry to the block. 309 sort(WorkList, [](const ConstraintOrBlock &A, const ConstraintOrBlock &B) { 310 return std::tie(A.NumIn, A.IsBlock) < std::tie(B.NumIn, B.IsBlock); 311 }); 312 313 // Finally, process ordered worklist and eliminate implied conditions. 314 SmallVector<StackEntry, 16> DFSInStack; 315 DenseMap<Value *, unsigned> Value2Index; 316 for (ConstraintOrBlock &CB : WorkList) { 317 // First, pop entries from the stack that are out-of-scope for CB. Remove 318 // the corresponding entry from the constraint system. 319 while (!DFSInStack.empty()) { 320 auto &E = DFSInStack.back(); 321 LLVM_DEBUG(dbgs() << "Top of stack : " << E.NumIn << " " << E.NumOut 322 << "\n"); 323 LLVM_DEBUG(dbgs() << "CB: " << CB.NumIn << " " << CB.NumOut << "\n"); 324 assert(E.NumIn <= CB.NumIn); 325 if (CB.NumOut <= E.NumOut) 326 break; 327 LLVM_DEBUG(dbgs() << "Removing " << *E.Condition << " " << E.IsNot 328 << "\n"); 329 DFSInStack.pop_back(); 330 CS.popLastConstraint(); 331 } 332 333 LLVM_DEBUG({ 334 dbgs() << "Processing "; 335 if (CB.IsBlock) 336 dbgs() << *CB.BB; 337 else 338 dbgs() << *CB.Condition; 339 dbgs() << "\n"; 340 }); 341 342 // For a block, check if any CmpInsts become known based on the current set 343 // of constraints. 344 if (CB.IsBlock) { 345 for (Instruction &I : *CB.BB) { 346 auto *Cmp = dyn_cast<CmpInst>(&I); 347 if (!Cmp) 348 continue; 349 350 DenseMap<Value *, unsigned> NewIndices; 351 auto R = getConstraint(Cmp, Value2Index, NewIndices); 352 if (R.size() != 1) 353 continue; 354 355 // Check if all coefficients of new indices are 0 after building the 356 // constraint. Skip if any of the new indices has a non-null 357 // coefficient. 358 bool HasNewIndex = false; 359 for (unsigned I = 0; I < NewIndices.size(); ++I) { 360 int64_t Last = R[0].Coefficients.pop_back_val(); 361 if (Last != 0) { 362 HasNewIndex = true; 363 break; 364 } 365 } 366 if (HasNewIndex || R[0].size() == 1) 367 continue; 368 369 if (CS.isConditionImplied(R[0].Coefficients)) { 370 if (!DebugCounter::shouldExecute(EliminatedCounter)) 371 continue; 372 373 LLVM_DEBUG(dbgs() << "Condition " << *Cmp 374 << " implied by dominating constraints\n"); 375 LLVM_DEBUG({ 376 for (auto &E : reverse(DFSInStack)) 377 dbgs() << " C " << *E.Condition << " " << E.IsNot << "\n"; 378 }); 379 Cmp->replaceAllUsesWith( 380 ConstantInt::getTrue(F.getParent()->getContext())); 381 NumCondsRemoved++; 382 Changed = true; 383 } 384 if (CS.isConditionImplied( 385 ConstraintSystem::negate(R[0].Coefficients))) { 386 if (!DebugCounter::shouldExecute(EliminatedCounter)) 387 continue; 388 389 LLVM_DEBUG(dbgs() << "Condition !" << *Cmp 390 << " implied by dominating constraints\n"); 391 LLVM_DEBUG({ 392 for (auto &E : reverse(DFSInStack)) 393 dbgs() << " C " << *E.Condition << " " << E.IsNot << "\n"; 394 }); 395 Cmp->replaceAllUsesWith( 396 ConstantInt::getFalse(F.getParent()->getContext())); 397 NumCondsRemoved++; 398 Changed = true; 399 } 400 } 401 continue; 402 } 403 404 // Set up a function to restore the predicate at the end of the scope if it 405 // has been negated. Negate the predicate in-place, if required. 406 auto *CI = dyn_cast<CmpInst>(CB.Condition); 407 auto PredicateRestorer = make_scope_exit([CI, &CB]() { 408 if (CB.Not && CI) 409 CI->setPredicate(CI->getInversePredicate()); 410 }); 411 if (CB.Not) { 412 if (CI) { 413 CI->setPredicate(CI->getInversePredicate()); 414 } else { 415 LLVM_DEBUG(dbgs() << "Can only negate compares so far.\n"); 416 continue; 417 } 418 } 419 420 // Otherwise, add the condition to the system and stack, if we can transform 421 // it into a constraint. 422 DenseMap<Value *, unsigned> NewIndices; 423 auto R = getConstraint(CB.Condition, Value2Index, NewIndices); 424 if (R.empty()) 425 continue; 426 427 for (auto &KV : NewIndices) 428 Value2Index.insert(KV); 429 430 LLVM_DEBUG(dbgs() << "Adding " << *CB.Condition << " " << CB.Not << "\n"); 431 bool Added = false; 432 for (auto &C : R) { 433 auto Coeffs = C.Coefficients; 434 LLVM_DEBUG({ 435 dbgs() << " constraint: "; 436 dumpWithNames(C, Value2Index); 437 }); 438 Added |= CS.addVariableRowFill(Coeffs); 439 // If R has been added to the system, queue it for removal once it goes 440 // out-of-scope. 441 if (Added) 442 DFSInStack.emplace_back(CB.NumIn, CB.NumOut, CB.Condition, CB.Not); 443 } 444 } 445 446 assert(CS.size() == DFSInStack.size() && 447 "updates to CS and DFSInStack are out of sync"); 448 return Changed; 449 } 450 451 PreservedAnalyses ConstraintEliminationPass::run(Function &F, 452 FunctionAnalysisManager &AM) { 453 auto &DT = AM.getResult<DominatorTreeAnalysis>(F); 454 if (!eliminateConstraints(F, DT)) 455 return PreservedAnalyses::all(); 456 457 PreservedAnalyses PA; 458 PA.preserve<DominatorTreeAnalysis>(); 459 PA.preserve<GlobalsAA>(); 460 PA.preserveSet<CFGAnalyses>(); 461 return PA; 462 } 463 464 namespace { 465 466 class ConstraintElimination : public FunctionPass { 467 public: 468 static char ID; 469 470 ConstraintElimination() : FunctionPass(ID) { 471 initializeConstraintEliminationPass(*PassRegistry::getPassRegistry()); 472 } 473 474 bool runOnFunction(Function &F) override { 475 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 476 return eliminateConstraints(F, DT); 477 } 478 479 void getAnalysisUsage(AnalysisUsage &AU) const override { 480 AU.setPreservesCFG(); 481 AU.addRequired<DominatorTreeWrapperPass>(); 482 AU.addPreserved<GlobalsAAWrapperPass>(); 483 AU.addPreserved<DominatorTreeWrapperPass>(); 484 } 485 }; 486 487 } // end anonymous namespace 488 489 char ConstraintElimination::ID = 0; 490 491 INITIALIZE_PASS_BEGIN(ConstraintElimination, "constraint-elimination", 492 "Constraint Elimination", false, false) 493 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 494 INITIALIZE_PASS_DEPENDENCY(LazyValueInfoWrapperPass) 495 INITIALIZE_PASS_END(ConstraintElimination, "constraint-elimination", 496 "Constraint Elimination", false, false) 497 498 FunctionPass *llvm::createConstraintEliminationPass() { 499 return new ConstraintElimination(); 500 } 501