xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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