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