xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp (revision 8a4dda33d67586ca2624f2a38417baa03a533a7f)
1e8d8bef9SDimitry Andric //===-- ConstraintElimination.cpp - Eliminate conds using constraints. ----===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric //
9e8d8bef9SDimitry Andric // Eliminate conditions based on constraints collected from dominating
10e8d8bef9SDimitry Andric // conditions.
11e8d8bef9SDimitry Andric //
12e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
13e8d8bef9SDimitry Andric 
14e8d8bef9SDimitry Andric #include "llvm/Transforms/Scalar/ConstraintElimination.h"
15e8d8bef9SDimitry Andric #include "llvm/ADT/STLExtras.h"
16fe6060f1SDimitry Andric #include "llvm/ADT/ScopeExit.h"
17e8d8bef9SDimitry Andric #include "llvm/ADT/SmallVector.h"
18e8d8bef9SDimitry Andric #include "llvm/ADT/Statistic.h"
19e8d8bef9SDimitry Andric #include "llvm/Analysis/ConstraintSystem.h"
20e8d8bef9SDimitry Andric #include "llvm/Analysis/GlobalsModRef.h"
2106c3fb27SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
22349cc55cSDimitry Andric #include "llvm/Analysis/ValueTracking.h"
23bdd1243dSDimitry Andric #include "llvm/IR/DataLayout.h"
24e8d8bef9SDimitry Andric #include "llvm/IR/Dominators.h"
25e8d8bef9SDimitry Andric #include "llvm/IR/Function.h"
26bdd1243dSDimitry Andric #include "llvm/IR/GetElementPtrTypeIterator.h"
2781ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h"
28e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h"
29e8d8bef9SDimitry Andric #include "llvm/IR/PatternMatch.h"
3006c3fb27SDimitry Andric #include "llvm/IR/Verifier.h"
31e8d8bef9SDimitry Andric #include "llvm/Pass.h"
32bdd1243dSDimitry Andric #include "llvm/Support/CommandLine.h"
33e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h"
34e8d8bef9SDimitry Andric #include "llvm/Support/DebugCounter.h"
3506c3fb27SDimitry Andric #include "llvm/Support/KnownBits.h"
3681ad6265SDimitry Andric #include "llvm/Support/MathExtras.h"
3706c3fb27SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h"
3806c3fb27SDimitry Andric #include "llvm/Transforms/Utils/ValueMapper.h"
39e8d8bef9SDimitry Andric 
40bdd1243dSDimitry Andric #include <cmath>
4106c3fb27SDimitry Andric #include <optional>
42fe6060f1SDimitry Andric #include <string>
43fe6060f1SDimitry Andric 
44e8d8bef9SDimitry Andric using namespace llvm;
45e8d8bef9SDimitry Andric using namespace PatternMatch;
46e8d8bef9SDimitry Andric 
47e8d8bef9SDimitry Andric #define DEBUG_TYPE "constraint-elimination"
48e8d8bef9SDimitry Andric 
49e8d8bef9SDimitry Andric STATISTIC(NumCondsRemoved, "Number of instructions removed");
50e8d8bef9SDimitry Andric DEBUG_COUNTER(EliminatedCounter, "conds-eliminated",
51e8d8bef9SDimitry Andric               "Controls which conditions are eliminated");
52e8d8bef9SDimitry Andric 
53bdd1243dSDimitry Andric static cl::opt<unsigned>
54bdd1243dSDimitry Andric     MaxRows("constraint-elimination-max-rows", cl::init(500), cl::Hidden,
55bdd1243dSDimitry Andric             cl::desc("Maximum number of rows to keep in constraint system"));
56bdd1243dSDimitry Andric 
5706c3fb27SDimitry Andric static cl::opt<bool> DumpReproducers(
5806c3fb27SDimitry Andric     "constraint-elimination-dump-reproducers", cl::init(false), cl::Hidden,
5906c3fb27SDimitry Andric     cl::desc("Dump IR to reproduce successful transformations."));
6006c3fb27SDimitry Andric 
61e8d8bef9SDimitry Andric static int64_t MaxConstraintValue = std::numeric_limits<int64_t>::max();
6281ad6265SDimitry Andric static int64_t MinSignedConstraintValue = std::numeric_limits<int64_t>::min();
63e8d8bef9SDimitry Andric 
64bdd1243dSDimitry Andric // A helper to multiply 2 signed integers where overflowing is allowed.
65bdd1243dSDimitry Andric static int64_t multiplyWithOverflow(int64_t A, int64_t B) {
66bdd1243dSDimitry Andric   int64_t Result;
67bdd1243dSDimitry Andric   MulOverflow(A, B, Result);
68bdd1243dSDimitry Andric   return Result;
69bdd1243dSDimitry Andric }
70bdd1243dSDimitry Andric 
71bdd1243dSDimitry Andric // A helper to add 2 signed integers where overflowing is allowed.
72bdd1243dSDimitry Andric static int64_t addWithOverflow(int64_t A, int64_t B) {
73bdd1243dSDimitry Andric   int64_t Result;
74bdd1243dSDimitry Andric   AddOverflow(A, B, Result);
75bdd1243dSDimitry Andric   return Result;
76bdd1243dSDimitry Andric }
77bdd1243dSDimitry Andric 
7806c3fb27SDimitry Andric static Instruction *getContextInstForUse(Use &U) {
7906c3fb27SDimitry Andric   Instruction *UserI = cast<Instruction>(U.getUser());
8006c3fb27SDimitry Andric   if (auto *Phi = dyn_cast<PHINode>(UserI))
8106c3fb27SDimitry Andric     UserI = Phi->getIncomingBlock(U)->getTerminator();
8206c3fb27SDimitry Andric   return UserI;
8306c3fb27SDimitry Andric }
8406c3fb27SDimitry Andric 
8504eeddc0SDimitry Andric namespace {
8606c3fb27SDimitry Andric /// Represents either
8706c3fb27SDimitry Andric ///  * a condition that holds on entry to a block (=conditional fact)
8806c3fb27SDimitry Andric ///  * an assume (=assume fact)
8906c3fb27SDimitry Andric ///  * a use of a compare instruction to simplify.
9006c3fb27SDimitry Andric /// It also tracks the Dominator DFS in and out numbers for each entry.
9106c3fb27SDimitry Andric struct FactOrCheck {
9206c3fb27SDimitry Andric   union {
9306c3fb27SDimitry Andric     Instruction *Inst;
9406c3fb27SDimitry Andric     Use *U;
9506c3fb27SDimitry Andric   };
9606c3fb27SDimitry Andric   unsigned NumIn;
9706c3fb27SDimitry Andric   unsigned NumOut;
9806c3fb27SDimitry Andric   bool HasInst;
9906c3fb27SDimitry Andric   bool Not;
10006c3fb27SDimitry Andric 
10106c3fb27SDimitry Andric   FactOrCheck(DomTreeNode *DTN, Instruction *Inst, bool Not)
10206c3fb27SDimitry Andric       : Inst(Inst), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
10306c3fb27SDimitry Andric         HasInst(true), Not(Not) {}
10406c3fb27SDimitry Andric 
10506c3fb27SDimitry Andric   FactOrCheck(DomTreeNode *DTN, Use *U)
10606c3fb27SDimitry Andric       : U(U), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
10706c3fb27SDimitry Andric         HasInst(false), Not(false) {}
10806c3fb27SDimitry Andric 
10906c3fb27SDimitry Andric   static FactOrCheck getFact(DomTreeNode *DTN, Instruction *Inst,
11006c3fb27SDimitry Andric                              bool Not = false) {
11106c3fb27SDimitry Andric     return FactOrCheck(DTN, Inst, Not);
11206c3fb27SDimitry Andric   }
11306c3fb27SDimitry Andric 
11406c3fb27SDimitry Andric   static FactOrCheck getCheck(DomTreeNode *DTN, Use *U) {
11506c3fb27SDimitry Andric     return FactOrCheck(DTN, U);
11606c3fb27SDimitry Andric   }
11706c3fb27SDimitry Andric 
11806c3fb27SDimitry Andric   static FactOrCheck getCheck(DomTreeNode *DTN, CallInst *CI) {
11906c3fb27SDimitry Andric     return FactOrCheck(DTN, CI, false);
12006c3fb27SDimitry Andric   }
12106c3fb27SDimitry Andric 
12206c3fb27SDimitry Andric   bool isCheck() const {
12306c3fb27SDimitry Andric     return !HasInst ||
12406c3fb27SDimitry Andric            match(Inst, m_Intrinsic<Intrinsic::ssub_with_overflow>());
12506c3fb27SDimitry Andric   }
12606c3fb27SDimitry Andric 
12706c3fb27SDimitry Andric   Instruction *getContextInst() const {
12806c3fb27SDimitry Andric     if (HasInst)
12906c3fb27SDimitry Andric       return Inst;
13006c3fb27SDimitry Andric     return getContextInstForUse(*U);
13106c3fb27SDimitry Andric   }
13206c3fb27SDimitry Andric   Instruction *getInstructionToSimplify() const {
13306c3fb27SDimitry Andric     assert(isCheck());
13406c3fb27SDimitry Andric     if (HasInst)
13506c3fb27SDimitry Andric       return Inst;
13606c3fb27SDimitry Andric     // The use may have been simplified to a constant already.
13706c3fb27SDimitry Andric     return dyn_cast<Instruction>(*U);
13806c3fb27SDimitry Andric   }
13906c3fb27SDimitry Andric   bool isConditionFact() const { return !isCheck() && isa<CmpInst>(Inst); }
14006c3fb27SDimitry Andric };
14106c3fb27SDimitry Andric 
14206c3fb27SDimitry Andric /// Keep state required to build worklist.
14306c3fb27SDimitry Andric struct State {
14406c3fb27SDimitry Andric   DominatorTree &DT;
14506c3fb27SDimitry Andric   SmallVector<FactOrCheck, 64> WorkList;
14606c3fb27SDimitry Andric 
14706c3fb27SDimitry Andric   State(DominatorTree &DT) : DT(DT) {}
14806c3fb27SDimitry Andric 
14906c3fb27SDimitry Andric   /// Process block \p BB and add known facts to work-list.
15006c3fb27SDimitry Andric   void addInfoFor(BasicBlock &BB);
15106c3fb27SDimitry Andric 
15206c3fb27SDimitry Andric   /// Returns true if we can add a known condition from BB to its successor
15306c3fb27SDimitry Andric   /// block Succ.
15406c3fb27SDimitry Andric   bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ) const {
15506c3fb27SDimitry Andric     return DT.dominates(BasicBlockEdge(&BB, Succ), Succ);
15606c3fb27SDimitry Andric   }
15706c3fb27SDimitry Andric };
15804eeddc0SDimitry Andric 
15981ad6265SDimitry Andric class ConstraintInfo;
16004eeddc0SDimitry Andric 
16181ad6265SDimitry Andric struct StackEntry {
16281ad6265SDimitry Andric   unsigned NumIn;
16381ad6265SDimitry Andric   unsigned NumOut;
16481ad6265SDimitry Andric   bool IsSigned = false;
16581ad6265SDimitry Andric   /// Variables that can be removed from the system once the stack entry gets
16681ad6265SDimitry Andric   /// removed.
16781ad6265SDimitry Andric   SmallVector<Value *, 2> ValuesToRelease;
16881ad6265SDimitry Andric 
169bdd1243dSDimitry Andric   StackEntry(unsigned NumIn, unsigned NumOut, bool IsSigned,
17081ad6265SDimitry Andric              SmallVector<Value *, 2> ValuesToRelease)
171bdd1243dSDimitry Andric       : NumIn(NumIn), NumOut(NumOut), IsSigned(IsSigned),
17281ad6265SDimitry Andric         ValuesToRelease(ValuesToRelease) {}
17304eeddc0SDimitry Andric };
17404eeddc0SDimitry Andric 
17581ad6265SDimitry Andric /// Struct to express a pre-condition of the form %Op0 Pred %Op1.
17681ad6265SDimitry Andric struct PreconditionTy {
17781ad6265SDimitry Andric   CmpInst::Predicate Pred;
17881ad6265SDimitry Andric   Value *Op0;
17981ad6265SDimitry Andric   Value *Op1;
18004eeddc0SDimitry Andric 
18181ad6265SDimitry Andric   PreconditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1)
18281ad6265SDimitry Andric       : Pred(Pred), Op0(Op0), Op1(Op1) {}
18381ad6265SDimitry Andric };
18404eeddc0SDimitry Andric 
18581ad6265SDimitry Andric struct ConstraintTy {
18681ad6265SDimitry Andric   SmallVector<int64_t, 8> Coefficients;
18781ad6265SDimitry Andric   SmallVector<PreconditionTy, 2> Preconditions;
18804eeddc0SDimitry Andric 
189bdd1243dSDimitry Andric   SmallVector<SmallVector<int64_t, 8>> ExtraInfo;
190bdd1243dSDimitry Andric 
19181ad6265SDimitry Andric   bool IsSigned = false;
19204eeddc0SDimitry Andric 
19381ad6265SDimitry Andric   ConstraintTy() = default;
19404eeddc0SDimitry Andric 
19506c3fb27SDimitry Andric   ConstraintTy(SmallVector<int64_t, 8> Coefficients, bool IsSigned, bool IsEq,
19606c3fb27SDimitry Andric                bool IsNe)
19706c3fb27SDimitry Andric       : Coefficients(Coefficients), IsSigned(IsSigned), IsEq(IsEq), IsNe(IsNe) {
19806c3fb27SDimitry Andric   }
19981ad6265SDimitry Andric 
20081ad6265SDimitry Andric   unsigned size() const { return Coefficients.size(); }
20181ad6265SDimitry Andric 
20281ad6265SDimitry Andric   unsigned empty() const { return Coefficients.empty(); }
20304eeddc0SDimitry Andric 
20481ad6265SDimitry Andric   /// Returns true if all preconditions for this list of constraints are
20581ad6265SDimitry Andric   /// satisfied given \p CS and the corresponding \p Value2Index mapping.
20681ad6265SDimitry Andric   bool isValid(const ConstraintInfo &Info) const;
20706c3fb27SDimitry Andric 
20806c3fb27SDimitry Andric   bool isEq() const { return IsEq; }
20906c3fb27SDimitry Andric 
21006c3fb27SDimitry Andric   bool isNe() const { return IsNe; }
21106c3fb27SDimitry Andric 
21206c3fb27SDimitry Andric   /// Check if the current constraint is implied by the given ConstraintSystem.
21306c3fb27SDimitry Andric   ///
21406c3fb27SDimitry Andric   /// \return true or false if the constraint is proven to be respectively true,
21506c3fb27SDimitry Andric   /// or false. When the constraint cannot be proven to be either true or false,
21606c3fb27SDimitry Andric   /// std::nullopt is returned.
21706c3fb27SDimitry Andric   std::optional<bool> isImpliedBy(const ConstraintSystem &CS) const;
21806c3fb27SDimitry Andric 
21906c3fb27SDimitry Andric private:
22006c3fb27SDimitry Andric   bool IsEq = false;
22106c3fb27SDimitry Andric   bool IsNe = false;
22281ad6265SDimitry Andric };
22381ad6265SDimitry Andric 
22481ad6265SDimitry Andric /// Wrapper encapsulating separate constraint systems and corresponding value
22581ad6265SDimitry Andric /// mappings for both unsigned and signed information. Facts are added to and
22681ad6265SDimitry Andric /// conditions are checked against the corresponding system depending on the
22781ad6265SDimitry Andric /// signed-ness of their predicates. While the information is kept separate
22881ad6265SDimitry Andric /// based on signed-ness, certain conditions can be transferred between the two
22981ad6265SDimitry Andric /// systems.
23081ad6265SDimitry Andric class ConstraintInfo {
23181ad6265SDimitry Andric 
23281ad6265SDimitry Andric   ConstraintSystem UnsignedCS;
23381ad6265SDimitry Andric   ConstraintSystem SignedCS;
23481ad6265SDimitry Andric 
235bdd1243dSDimitry Andric   const DataLayout &DL;
236bdd1243dSDimitry Andric 
23781ad6265SDimitry Andric public:
23806c3fb27SDimitry Andric   ConstraintInfo(const DataLayout &DL, ArrayRef<Value *> FunctionArgs)
23906c3fb27SDimitry Andric       : UnsignedCS(FunctionArgs), SignedCS(FunctionArgs), DL(DL) {}
240bdd1243dSDimitry Andric 
24181ad6265SDimitry Andric   DenseMap<Value *, unsigned> &getValue2Index(bool Signed) {
24206c3fb27SDimitry Andric     return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
24381ad6265SDimitry Andric   }
24481ad6265SDimitry Andric   const DenseMap<Value *, unsigned> &getValue2Index(bool Signed) const {
24506c3fb27SDimitry Andric     return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
24681ad6265SDimitry Andric   }
24781ad6265SDimitry Andric 
24881ad6265SDimitry Andric   ConstraintSystem &getCS(bool Signed) {
24981ad6265SDimitry Andric     return Signed ? SignedCS : UnsignedCS;
25081ad6265SDimitry Andric   }
25181ad6265SDimitry Andric   const ConstraintSystem &getCS(bool Signed) const {
25281ad6265SDimitry Andric     return Signed ? SignedCS : UnsignedCS;
25381ad6265SDimitry Andric   }
25481ad6265SDimitry Andric 
25581ad6265SDimitry Andric   void popLastConstraint(bool Signed) { getCS(Signed).popLastConstraint(); }
25681ad6265SDimitry Andric   void popLastNVariables(bool Signed, unsigned N) {
25781ad6265SDimitry Andric     getCS(Signed).popLastNVariables(N);
25881ad6265SDimitry Andric   }
25981ad6265SDimitry Andric 
26081ad6265SDimitry Andric   bool doesHold(CmpInst::Predicate Pred, Value *A, Value *B) const;
26181ad6265SDimitry Andric 
262bdd1243dSDimitry Andric   void addFact(CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn,
263bdd1243dSDimitry Andric                unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack);
26481ad6265SDimitry Andric 
26581ad6265SDimitry Andric   /// Turn a comparison of the form \p Op0 \p Pred \p Op1 into a vector of
26681ad6265SDimitry Andric   /// constraints, using indices from the corresponding constraint system.
267bdd1243dSDimitry Andric   /// New variables that need to be added to the system are collected in
268bdd1243dSDimitry Andric   /// \p NewVariables.
26981ad6265SDimitry Andric   ConstraintTy getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
270bdd1243dSDimitry Andric                              SmallVectorImpl<Value *> &NewVariables) const;
27181ad6265SDimitry Andric 
272bdd1243dSDimitry Andric   /// Turns a comparison of the form \p Op0 \p Pred \p Op1 into a vector of
273bdd1243dSDimitry Andric   /// constraints using getConstraint. Returns an empty constraint if the result
274bdd1243dSDimitry Andric   /// cannot be used to query the existing constraint system, e.g. because it
275bdd1243dSDimitry Andric   /// would require adding new variables. Also tries to convert signed
276bdd1243dSDimitry Andric   /// predicates to unsigned ones if possible to allow using the unsigned system
277bdd1243dSDimitry Andric   /// which increases the effectiveness of the signed <-> unsigned transfer
278bdd1243dSDimitry Andric   /// logic.
279bdd1243dSDimitry Andric   ConstraintTy getConstraintForSolving(CmpInst::Predicate Pred, Value *Op0,
280bdd1243dSDimitry Andric                                        Value *Op1) const;
28181ad6265SDimitry Andric 
28281ad6265SDimitry Andric   /// Try to add information from \p A \p Pred \p B to the unsigned/signed
28381ad6265SDimitry Andric   /// system if \p Pred is signed/unsigned.
28481ad6265SDimitry Andric   void transferToOtherSystem(CmpInst::Predicate Pred, Value *A, Value *B,
285bdd1243dSDimitry Andric                              unsigned NumIn, unsigned NumOut,
28681ad6265SDimitry Andric                              SmallVectorImpl<StackEntry> &DFSInStack);
28704eeddc0SDimitry Andric };
28804eeddc0SDimitry Andric 
289bdd1243dSDimitry Andric /// Represents a (Coefficient * Variable) entry after IR decomposition.
290bdd1243dSDimitry Andric struct DecompEntry {
291bdd1243dSDimitry Andric   int64_t Coefficient;
292bdd1243dSDimitry Andric   Value *Variable;
293bdd1243dSDimitry Andric   /// True if the variable is known positive in the current constraint.
294bdd1243dSDimitry Andric   bool IsKnownNonNegative;
295bdd1243dSDimitry Andric 
296bdd1243dSDimitry Andric   DecompEntry(int64_t Coefficient, Value *Variable,
297bdd1243dSDimitry Andric               bool IsKnownNonNegative = false)
298bdd1243dSDimitry Andric       : Coefficient(Coefficient), Variable(Variable),
299bdd1243dSDimitry Andric         IsKnownNonNegative(IsKnownNonNegative) {}
300bdd1243dSDimitry Andric };
301bdd1243dSDimitry Andric 
302bdd1243dSDimitry Andric /// Represents an Offset + Coefficient1 * Variable1 + ... decomposition.
303bdd1243dSDimitry Andric struct Decomposition {
304bdd1243dSDimitry Andric   int64_t Offset = 0;
305bdd1243dSDimitry Andric   SmallVector<DecompEntry, 3> Vars;
306bdd1243dSDimitry Andric 
307bdd1243dSDimitry Andric   Decomposition(int64_t Offset) : Offset(Offset) {}
308bdd1243dSDimitry Andric   Decomposition(Value *V, bool IsKnownNonNegative = false) {
309bdd1243dSDimitry Andric     Vars.emplace_back(1, V, IsKnownNonNegative);
310bdd1243dSDimitry Andric   }
311bdd1243dSDimitry Andric   Decomposition(int64_t Offset, ArrayRef<DecompEntry> Vars)
312bdd1243dSDimitry Andric       : Offset(Offset), Vars(Vars) {}
313bdd1243dSDimitry Andric 
314bdd1243dSDimitry Andric   void add(int64_t OtherOffset) {
315bdd1243dSDimitry Andric     Offset = addWithOverflow(Offset, OtherOffset);
316bdd1243dSDimitry Andric   }
317bdd1243dSDimitry Andric 
318bdd1243dSDimitry Andric   void add(const Decomposition &Other) {
319bdd1243dSDimitry Andric     add(Other.Offset);
320bdd1243dSDimitry Andric     append_range(Vars, Other.Vars);
321bdd1243dSDimitry Andric   }
322bdd1243dSDimitry Andric 
323bdd1243dSDimitry Andric   void mul(int64_t Factor) {
324bdd1243dSDimitry Andric     Offset = multiplyWithOverflow(Offset, Factor);
325bdd1243dSDimitry Andric     for (auto &Var : Vars)
326bdd1243dSDimitry Andric       Var.Coefficient = multiplyWithOverflow(Var.Coefficient, Factor);
327bdd1243dSDimitry Andric   }
328bdd1243dSDimitry Andric };
329bdd1243dSDimitry Andric 
33004eeddc0SDimitry Andric } // namespace
33104eeddc0SDimitry Andric 
332bdd1243dSDimitry Andric static Decomposition decompose(Value *V,
333bdd1243dSDimitry Andric                                SmallVectorImpl<PreconditionTy> &Preconditions,
334bdd1243dSDimitry Andric                                bool IsSigned, const DataLayout &DL);
33581ad6265SDimitry Andric 
336bdd1243dSDimitry Andric static bool canUseSExt(ConstantInt *CI) {
33781ad6265SDimitry Andric   const APInt &Val = CI->getValue();
33881ad6265SDimitry Andric   return Val.sgt(MinSignedConstraintValue) && Val.slt(MaxConstraintValue);
339bdd1243dSDimitry Andric }
340bdd1243dSDimitry Andric 
341bdd1243dSDimitry Andric static Decomposition
34206c3fb27SDimitry Andric decomposeGEP(GEPOperator &GEP, SmallVectorImpl<PreconditionTy> &Preconditions,
34306c3fb27SDimitry Andric              bool IsSigned, const DataLayout &DL) {
344bdd1243dSDimitry Andric   // Do not reason about pointers where the index size is larger than 64 bits,
345bdd1243dSDimitry Andric   // as the coefficients used to encode constraints are 64 bit integers.
346bdd1243dSDimitry Andric   if (DL.getIndexTypeSizeInBits(GEP.getPointerOperand()->getType()) > 64)
347bdd1243dSDimitry Andric     return &GEP;
348bdd1243dSDimitry Andric 
349bdd1243dSDimitry Andric   if (!GEP.isInBounds())
350bdd1243dSDimitry Andric     return &GEP;
351bdd1243dSDimitry Andric 
352bdd1243dSDimitry Andric   assert(!IsSigned && "The logic below only supports decomposition for "
353bdd1243dSDimitry Andric                       "unsinged predicates at the moment.");
354bdd1243dSDimitry Andric   Type *PtrTy = GEP.getType()->getScalarType();
355bdd1243dSDimitry Andric   unsigned BitWidth = DL.getIndexTypeSizeInBits(PtrTy);
356bdd1243dSDimitry Andric   MapVector<Value *, APInt> VariableOffsets;
357bdd1243dSDimitry Andric   APInt ConstantOffset(BitWidth, 0);
358bdd1243dSDimitry Andric   if (!GEP.collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset))
359bdd1243dSDimitry Andric     return &GEP;
360bdd1243dSDimitry Andric 
361bdd1243dSDimitry Andric   // Handle the (gep (gep ....), C) case by incrementing the constant
362bdd1243dSDimitry Andric   // coefficient of the inner GEP, if C is a constant.
36306c3fb27SDimitry Andric   auto *InnerGEP = dyn_cast<GEPOperator>(GEP.getPointerOperand());
364bdd1243dSDimitry Andric   if (VariableOffsets.empty() && InnerGEP && InnerGEP->getNumOperands() == 2) {
365bdd1243dSDimitry Andric     auto Result = decompose(InnerGEP, Preconditions, IsSigned, DL);
366bdd1243dSDimitry Andric     Result.add(ConstantOffset.getSExtValue());
367bdd1243dSDimitry Andric 
368bdd1243dSDimitry Andric     if (ConstantOffset.isNegative()) {
369bdd1243dSDimitry Andric       unsigned Scale = DL.getTypeAllocSize(InnerGEP->getResultElementType());
370bdd1243dSDimitry Andric       int64_t ConstantOffsetI = ConstantOffset.getSExtValue();
371bdd1243dSDimitry Andric       if (ConstantOffsetI % Scale != 0)
372bdd1243dSDimitry Andric         return &GEP;
373bdd1243dSDimitry Andric       // Add pre-condition ensuring the GEP is increasing monotonically and
374bdd1243dSDimitry Andric       // can be de-composed.
375bdd1243dSDimitry Andric       // Both sides are normalized by being divided by Scale.
376bdd1243dSDimitry Andric       Preconditions.emplace_back(
377bdd1243dSDimitry Andric           CmpInst::ICMP_SGE, InnerGEP->getOperand(1),
378bdd1243dSDimitry Andric           ConstantInt::get(InnerGEP->getOperand(1)->getType(),
379bdd1243dSDimitry Andric                            -1 * (ConstantOffsetI / Scale)));
380bdd1243dSDimitry Andric     }
381bdd1243dSDimitry Andric     return Result;
382bdd1243dSDimitry Andric   }
383bdd1243dSDimitry Andric 
384bdd1243dSDimitry Andric   Decomposition Result(ConstantOffset.getSExtValue(),
385bdd1243dSDimitry Andric                        DecompEntry(1, GEP.getPointerOperand()));
386bdd1243dSDimitry Andric   for (auto [Index, Scale] : VariableOffsets) {
387bdd1243dSDimitry Andric     auto IdxResult = decompose(Index, Preconditions, IsSigned, DL);
388bdd1243dSDimitry Andric     IdxResult.mul(Scale.getSExtValue());
389bdd1243dSDimitry Andric     Result.add(IdxResult);
390bdd1243dSDimitry Andric 
391bdd1243dSDimitry Andric     // If Op0 is signed non-negative, the GEP is increasing monotonically and
392bdd1243dSDimitry Andric     // can be de-composed.
393bdd1243dSDimitry Andric     if (!isKnownNonNegative(Index, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
394bdd1243dSDimitry Andric       Preconditions.emplace_back(CmpInst::ICMP_SGE, Index,
395bdd1243dSDimitry Andric                                  ConstantInt::get(Index->getType(), 0));
396bdd1243dSDimitry Andric   }
397bdd1243dSDimitry Andric   return Result;
398bdd1243dSDimitry Andric }
399bdd1243dSDimitry Andric 
400bdd1243dSDimitry Andric // Decomposes \p V into a constant offset + list of pairs { Coefficient,
401bdd1243dSDimitry Andric // Variable } where Coefficient * Variable. The sum of the constant offset and
402bdd1243dSDimitry Andric // pairs equals \p V.
403bdd1243dSDimitry Andric static Decomposition decompose(Value *V,
404bdd1243dSDimitry Andric                                SmallVectorImpl<PreconditionTy> &Preconditions,
405bdd1243dSDimitry Andric                                bool IsSigned, const DataLayout &DL) {
406bdd1243dSDimitry Andric 
407bdd1243dSDimitry Andric   auto MergeResults = [&Preconditions, IsSigned, &DL](Value *A, Value *B,
408bdd1243dSDimitry Andric                                                       bool IsSignedB) {
409bdd1243dSDimitry Andric     auto ResA = decompose(A, Preconditions, IsSigned, DL);
410bdd1243dSDimitry Andric     auto ResB = decompose(B, Preconditions, IsSignedB, DL);
411bdd1243dSDimitry Andric     ResA.add(ResB);
412bdd1243dSDimitry Andric     return ResA;
41381ad6265SDimitry Andric   };
414bdd1243dSDimitry Andric 
41581ad6265SDimitry Andric   // Decompose \p V used with a signed predicate.
41681ad6265SDimitry Andric   if (IsSigned) {
417e8d8bef9SDimitry Andric     if (auto *CI = dyn_cast<ConstantInt>(V)) {
418bdd1243dSDimitry Andric       if (canUseSExt(CI))
419bdd1243dSDimitry Andric         return CI->getSExtValue();
420e8d8bef9SDimitry Andric     }
421bdd1243dSDimitry Andric     Value *Op0;
422bdd1243dSDimitry Andric     Value *Op1;
423bdd1243dSDimitry Andric     if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1))))
424bdd1243dSDimitry Andric       return MergeResults(Op0, Op1, IsSigned);
42581ad6265SDimitry Andric 
42606c3fb27SDimitry Andric     ConstantInt *CI;
427*8a4dda33SDimitry Andric     if (match(V, m_NSWMul(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI)) {
42806c3fb27SDimitry Andric       auto Result = decompose(Op0, Preconditions, IsSigned, DL);
42906c3fb27SDimitry Andric       Result.mul(CI->getSExtValue());
43006c3fb27SDimitry Andric       return Result;
43106c3fb27SDimitry Andric     }
43206c3fb27SDimitry Andric 
433bdd1243dSDimitry Andric     return V;
43481ad6265SDimitry Andric   }
43581ad6265SDimitry Andric 
43681ad6265SDimitry Andric   if (auto *CI = dyn_cast<ConstantInt>(V)) {
43781ad6265SDimitry Andric     if (CI->uge(MaxConstraintValue))
438bdd1243dSDimitry Andric       return V;
439bdd1243dSDimitry Andric     return int64_t(CI->getZExtValue());
440fe6060f1SDimitry Andric   }
441fe6060f1SDimitry Andric 
44206c3fb27SDimitry Andric   if (auto *GEP = dyn_cast<GEPOperator>(V))
443bdd1243dSDimitry Andric     return decomposeGEP(*GEP, Preconditions, IsSigned, DL);
444e8d8bef9SDimitry Andric 
445e8d8bef9SDimitry Andric   Value *Op0;
446bdd1243dSDimitry Andric   bool IsKnownNonNegative = false;
447bdd1243dSDimitry Andric   if (match(V, m_ZExt(m_Value(Op0)))) {
448bdd1243dSDimitry Andric     IsKnownNonNegative = true;
449fe6060f1SDimitry Andric     V = Op0;
450bdd1243dSDimitry Andric   }
451fe6060f1SDimitry Andric 
452e8d8bef9SDimitry Andric   Value *Op1;
453e8d8bef9SDimitry Andric   ConstantInt *CI;
454bdd1243dSDimitry Andric   if (match(V, m_NUWAdd(m_Value(Op0), m_Value(Op1)))) {
455bdd1243dSDimitry Andric     return MergeResults(Op0, Op1, IsSigned);
456bdd1243dSDimitry Andric   }
457bdd1243dSDimitry Andric   if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) {
458bdd1243dSDimitry Andric     if (!isKnownNonNegative(Op0, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
459bdd1243dSDimitry Andric       Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,
460bdd1243dSDimitry Andric                                  ConstantInt::get(Op0->getType(), 0));
461bdd1243dSDimitry Andric     if (!isKnownNonNegative(Op1, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
462bdd1243dSDimitry Andric       Preconditions.emplace_back(CmpInst::ICMP_SGE, Op1,
463bdd1243dSDimitry Andric                                  ConstantInt::get(Op1->getType(), 0));
464bdd1243dSDimitry Andric 
465bdd1243dSDimitry Andric     return MergeResults(Op0, Op1, IsSigned);
466bdd1243dSDimitry Andric   }
467bdd1243dSDimitry Andric 
46881ad6265SDimitry Andric   if (match(V, m_Add(m_Value(Op0), m_ConstantInt(CI))) && CI->isNegative() &&
469bdd1243dSDimitry Andric       canUseSExt(CI)) {
47081ad6265SDimitry Andric     Preconditions.emplace_back(
47181ad6265SDimitry Andric         CmpInst::ICMP_UGE, Op0,
47281ad6265SDimitry Andric         ConstantInt::get(Op0->getType(), CI->getSExtValue() * -1));
473bdd1243dSDimitry Andric     return MergeResults(Op0, CI, true);
47481ad6265SDimitry Andric   }
475e8d8bef9SDimitry Andric 
47606c3fb27SDimitry Andric   // Decompose or as an add if there are no common bits between the operands.
47706c3fb27SDimitry Andric   if (match(V, m_Or(m_Value(Op0), m_ConstantInt(CI))) &&
47806c3fb27SDimitry Andric       haveNoCommonBitsSet(Op0, CI, DL)) {
47906c3fb27SDimitry Andric     return MergeResults(Op0, CI, IsSigned);
48006c3fb27SDimitry Andric   }
48106c3fb27SDimitry Andric 
482bdd1243dSDimitry Andric   if (match(V, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI)) {
48306c3fb27SDimitry Andric     if (CI->getSExtValue() < 0 || CI->getSExtValue() >= 64)
48406c3fb27SDimitry Andric       return {V, IsKnownNonNegative};
485bdd1243dSDimitry Andric     auto Result = decompose(Op1, Preconditions, IsSigned, DL);
48606c3fb27SDimitry Andric     Result.mul(int64_t{1} << CI->getSExtValue());
487bdd1243dSDimitry Andric     return Result;
488bdd1243dSDimitry Andric   }
489bdd1243dSDimitry Andric 
490bdd1243dSDimitry Andric   if (match(V, m_NUWMul(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI) &&
491bdd1243dSDimitry Andric       (!CI->isNegative())) {
492bdd1243dSDimitry Andric     auto Result = decompose(Op1, Preconditions, IsSigned, DL);
493bdd1243dSDimitry Andric     Result.mul(CI->getSExtValue());
494bdd1243dSDimitry Andric     return Result;
495bdd1243dSDimitry Andric   }
496bdd1243dSDimitry Andric 
497bdd1243dSDimitry Andric   if (match(V, m_NUWSub(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI))
498bdd1243dSDimitry Andric     return {-1 * CI->getSExtValue(), {{1, Op0}}};
499e8d8bef9SDimitry Andric   if (match(V, m_NUWSub(m_Value(Op0), m_Value(Op1))))
500bdd1243dSDimitry Andric     return {0, {{1, Op0}, {-1, Op1}}};
501e8d8bef9SDimitry Andric 
502bdd1243dSDimitry Andric   return {V, IsKnownNonNegative};
503e8d8bef9SDimitry Andric }
504e8d8bef9SDimitry Andric 
50581ad6265SDimitry Andric ConstraintTy
50681ad6265SDimitry Andric ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
507bdd1243dSDimitry Andric                               SmallVectorImpl<Value *> &NewVariables) const {
508bdd1243dSDimitry Andric   assert(NewVariables.empty() && "NewVariables must be empty when passed in");
50981ad6265SDimitry Andric   bool IsEq = false;
51006c3fb27SDimitry Andric   bool IsNe = false;
51106c3fb27SDimitry Andric 
51281ad6265SDimitry Andric   // Try to convert Pred to one of ULE/SLT/SLE/SLT.
51381ad6265SDimitry Andric   switch (Pred) {
51481ad6265SDimitry Andric   case CmpInst::ICMP_UGT:
51581ad6265SDimitry Andric   case CmpInst::ICMP_UGE:
51681ad6265SDimitry Andric   case CmpInst::ICMP_SGT:
51781ad6265SDimitry Andric   case CmpInst::ICMP_SGE: {
51881ad6265SDimitry Andric     Pred = CmpInst::getSwappedPredicate(Pred);
51981ad6265SDimitry Andric     std::swap(Op0, Op1);
52081ad6265SDimitry Andric     break;
52181ad6265SDimitry Andric   }
52281ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
52381ad6265SDimitry Andric     if (match(Op1, m_Zero())) {
52481ad6265SDimitry Andric       Pred = CmpInst::ICMP_ULE;
52581ad6265SDimitry Andric     } else {
52681ad6265SDimitry Andric       IsEq = true;
52781ad6265SDimitry Andric       Pred = CmpInst::ICMP_ULE;
52881ad6265SDimitry Andric     }
52981ad6265SDimitry Andric     break;
53081ad6265SDimitry Andric   case CmpInst::ICMP_NE:
53106c3fb27SDimitry Andric     if (match(Op1, m_Zero())) {
53281ad6265SDimitry Andric       Pred = CmpInst::getSwappedPredicate(CmpInst::ICMP_UGT);
53381ad6265SDimitry Andric       std::swap(Op0, Op1);
53406c3fb27SDimitry Andric     } else {
53506c3fb27SDimitry Andric       IsNe = true;
53606c3fb27SDimitry Andric       Pred = CmpInst::ICMP_ULE;
53706c3fb27SDimitry Andric     }
53881ad6265SDimitry Andric     break;
53981ad6265SDimitry Andric   default:
54081ad6265SDimitry Andric     break;
54181ad6265SDimitry Andric   }
54281ad6265SDimitry Andric 
54381ad6265SDimitry Andric   if (Pred != CmpInst::ICMP_ULE && Pred != CmpInst::ICMP_ULT &&
54481ad6265SDimitry Andric       Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SLT)
54581ad6265SDimitry Andric     return {};
54681ad6265SDimitry Andric 
54781ad6265SDimitry Andric   SmallVector<PreconditionTy, 4> Preconditions;
54881ad6265SDimitry Andric   bool IsSigned = CmpInst::isSigned(Pred);
54981ad6265SDimitry Andric   auto &Value2Index = getValue2Index(IsSigned);
55081ad6265SDimitry Andric   auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(),
551bdd1243dSDimitry Andric                         Preconditions, IsSigned, DL);
55281ad6265SDimitry Andric   auto BDec = decompose(Op1->stripPointerCastsSameRepresentation(),
553bdd1243dSDimitry Andric                         Preconditions, IsSigned, DL);
554bdd1243dSDimitry Andric   int64_t Offset1 = ADec.Offset;
555bdd1243dSDimitry Andric   int64_t Offset2 = BDec.Offset;
55681ad6265SDimitry Andric   Offset1 *= -1;
55781ad6265SDimitry Andric 
558bdd1243dSDimitry Andric   auto &VariablesA = ADec.Vars;
559bdd1243dSDimitry Andric   auto &VariablesB = BDec.Vars;
560e8d8bef9SDimitry Andric 
561bdd1243dSDimitry Andric   // First try to look up \p V in Value2Index and NewVariables. Otherwise add a
562bdd1243dSDimitry Andric   // new entry to NewVariables.
563bdd1243dSDimitry Andric   DenseMap<Value *, unsigned> NewIndexMap;
564bdd1243dSDimitry Andric   auto GetOrAddIndex = [&Value2Index, &NewVariables,
565bdd1243dSDimitry Andric                         &NewIndexMap](Value *V) -> unsigned {
566fe6060f1SDimitry Andric     auto V2I = Value2Index.find(V);
567fe6060f1SDimitry Andric     if (V2I != Value2Index.end())
568fe6060f1SDimitry Andric       return V2I->second;
569fe6060f1SDimitry Andric     auto Insert =
570bdd1243dSDimitry Andric         NewIndexMap.insert({V, Value2Index.size() + NewVariables.size() + 1});
571bdd1243dSDimitry Andric     if (Insert.second)
572bdd1243dSDimitry Andric       NewVariables.push_back(V);
573fe6060f1SDimitry Andric     return Insert.first->second;
574e8d8bef9SDimitry Andric   };
575e8d8bef9SDimitry Andric 
576bdd1243dSDimitry Andric   // Make sure all variables have entries in Value2Index or NewVariables.
577bdd1243dSDimitry Andric   for (const auto &KV : concat<DecompEntry>(VariablesA, VariablesB))
578bdd1243dSDimitry Andric     GetOrAddIndex(KV.Variable);
579e8d8bef9SDimitry Andric 
580e8d8bef9SDimitry Andric   // Build result constraint, by first adding all coefficients from A and then
581e8d8bef9SDimitry Andric   // subtracting all coefficients from B.
58281ad6265SDimitry Andric   ConstraintTy Res(
583bdd1243dSDimitry Andric       SmallVector<int64_t, 8>(Value2Index.size() + NewVariables.size() + 1, 0),
58406c3fb27SDimitry Andric       IsSigned, IsEq, IsNe);
585bdd1243dSDimitry Andric   // Collect variables that are known to be positive in all uses in the
586bdd1243dSDimitry Andric   // constraint.
587bdd1243dSDimitry Andric   DenseMap<Value *, bool> KnownNonNegativeVariables;
58881ad6265SDimitry Andric   auto &R = Res.Coefficients;
589bdd1243dSDimitry Andric   for (const auto &KV : VariablesA) {
590bdd1243dSDimitry Andric     R[GetOrAddIndex(KV.Variable)] += KV.Coefficient;
591bdd1243dSDimitry Andric     auto I =
592bdd1243dSDimitry Andric         KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative});
593bdd1243dSDimitry Andric     I.first->second &= KV.IsKnownNonNegative;
594bdd1243dSDimitry Andric   }
595e8d8bef9SDimitry Andric 
596bdd1243dSDimitry Andric   for (const auto &KV : VariablesB) {
59706c3fb27SDimitry Andric     if (SubOverflow(R[GetOrAddIndex(KV.Variable)], KV.Coefficient,
59806c3fb27SDimitry Andric                     R[GetOrAddIndex(KV.Variable)]))
59906c3fb27SDimitry Andric       return {};
600bdd1243dSDimitry Andric     auto I =
601bdd1243dSDimitry Andric         KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative});
602bdd1243dSDimitry Andric     I.first->second &= KV.IsKnownNonNegative;
603bdd1243dSDimitry Andric   }
604e8d8bef9SDimitry Andric 
60581ad6265SDimitry Andric   int64_t OffsetSum;
60681ad6265SDimitry Andric   if (AddOverflow(Offset1, Offset2, OffsetSum))
60781ad6265SDimitry Andric     return {};
60881ad6265SDimitry Andric   if (Pred == (IsSigned ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT))
60981ad6265SDimitry Andric     if (AddOverflow(OffsetSum, int64_t(-1), OffsetSum))
61081ad6265SDimitry Andric       return {};
61181ad6265SDimitry Andric   R[0] = OffsetSum;
61281ad6265SDimitry Andric   Res.Preconditions = std::move(Preconditions);
613bdd1243dSDimitry Andric 
614bdd1243dSDimitry Andric   // Remove any (Coefficient, Variable) entry where the Coefficient is 0 for new
615bdd1243dSDimitry Andric   // variables.
616bdd1243dSDimitry Andric   while (!NewVariables.empty()) {
617bdd1243dSDimitry Andric     int64_t Last = R.back();
618bdd1243dSDimitry Andric     if (Last != 0)
619bdd1243dSDimitry Andric       break;
620bdd1243dSDimitry Andric     R.pop_back();
621bdd1243dSDimitry Andric     Value *RemovedV = NewVariables.pop_back_val();
622bdd1243dSDimitry Andric     NewIndexMap.erase(RemovedV);
623bdd1243dSDimitry Andric   }
624bdd1243dSDimitry Andric 
625bdd1243dSDimitry Andric   // Add extra constraints for variables that are known positive.
626bdd1243dSDimitry Andric   for (auto &KV : KnownNonNegativeVariables) {
62706c3fb27SDimitry Andric     if (!KV.second ||
62806c3fb27SDimitry Andric         (!Value2Index.contains(KV.first) && !NewIndexMap.contains(KV.first)))
629bdd1243dSDimitry Andric       continue;
630bdd1243dSDimitry Andric     SmallVector<int64_t, 8> C(Value2Index.size() + NewVariables.size() + 1, 0);
631bdd1243dSDimitry Andric     C[GetOrAddIndex(KV.first)] = -1;
632bdd1243dSDimitry Andric     Res.ExtraInfo.push_back(C);
633bdd1243dSDimitry Andric   }
63481ad6265SDimitry Andric   return Res;
635e8d8bef9SDimitry Andric }
636e8d8bef9SDimitry Andric 
637bdd1243dSDimitry Andric ConstraintTy ConstraintInfo::getConstraintForSolving(CmpInst::Predicate Pred,
638bdd1243dSDimitry Andric                                                      Value *Op0,
639bdd1243dSDimitry Andric                                                      Value *Op1) const {
640bdd1243dSDimitry Andric   // If both operands are known to be non-negative, change signed predicates to
641bdd1243dSDimitry Andric   // unsigned ones. This increases the reasoning effectiveness in combination
642bdd1243dSDimitry Andric   // with the signed <-> unsigned transfer logic.
643bdd1243dSDimitry Andric   if (CmpInst::isSigned(Pred) &&
644bdd1243dSDimitry Andric       isKnownNonNegative(Op0, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1) &&
645bdd1243dSDimitry Andric       isKnownNonNegative(Op1, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
646bdd1243dSDimitry Andric     Pred = CmpInst::getUnsignedPredicate(Pred);
647bdd1243dSDimitry Andric 
648bdd1243dSDimitry Andric   SmallVector<Value *> NewVariables;
649bdd1243dSDimitry Andric   ConstraintTy R = getConstraint(Pred, Op0, Op1, NewVariables);
65006c3fb27SDimitry Andric   if (!NewVariables.empty())
651bdd1243dSDimitry Andric     return {};
652bdd1243dSDimitry Andric   return R;
653bdd1243dSDimitry Andric }
654bdd1243dSDimitry Andric 
65581ad6265SDimitry Andric bool ConstraintTy::isValid(const ConstraintInfo &Info) const {
65681ad6265SDimitry Andric   return Coefficients.size() > 0 &&
65781ad6265SDimitry Andric          all_of(Preconditions, [&Info](const PreconditionTy &C) {
65881ad6265SDimitry Andric            return Info.doesHold(C.Pred, C.Op0, C.Op1);
65981ad6265SDimitry Andric          });
66081ad6265SDimitry Andric }
66181ad6265SDimitry Andric 
66206c3fb27SDimitry Andric std::optional<bool>
66306c3fb27SDimitry Andric ConstraintTy::isImpliedBy(const ConstraintSystem &CS) const {
66406c3fb27SDimitry Andric   bool IsConditionImplied = CS.isConditionImplied(Coefficients);
66506c3fb27SDimitry Andric 
66606c3fb27SDimitry Andric   if (IsEq || IsNe) {
66706c3fb27SDimitry Andric     auto NegatedOrEqual = ConstraintSystem::negateOrEqual(Coefficients);
66806c3fb27SDimitry Andric     bool IsNegatedOrEqualImplied =
66906c3fb27SDimitry Andric         !NegatedOrEqual.empty() && CS.isConditionImplied(NegatedOrEqual);
67006c3fb27SDimitry Andric 
67106c3fb27SDimitry Andric     // In order to check that `%a == %b` is true (equality), both conditions `%a
67206c3fb27SDimitry Andric     // >= %b` and `%a <= %b` must hold true. When checking for equality (`IsEq`
67306c3fb27SDimitry Andric     // is true), we return true if they both hold, false in the other cases.
67406c3fb27SDimitry Andric     if (IsConditionImplied && IsNegatedOrEqualImplied)
67506c3fb27SDimitry Andric       return IsEq;
67606c3fb27SDimitry Andric 
67706c3fb27SDimitry Andric     auto Negated = ConstraintSystem::negate(Coefficients);
67806c3fb27SDimitry Andric     bool IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated);
67906c3fb27SDimitry Andric 
68006c3fb27SDimitry Andric     auto StrictLessThan = ConstraintSystem::toStrictLessThan(Coefficients);
68106c3fb27SDimitry Andric     bool IsStrictLessThanImplied =
68206c3fb27SDimitry Andric         !StrictLessThan.empty() && CS.isConditionImplied(StrictLessThan);
68306c3fb27SDimitry Andric 
68406c3fb27SDimitry Andric     // In order to check that `%a != %b` is true (non-equality), either
68506c3fb27SDimitry Andric     // condition `%a > %b` or `%a < %b` must hold true. When checking for
68606c3fb27SDimitry Andric     // non-equality (`IsNe` is true), we return true if one of the two holds,
68706c3fb27SDimitry Andric     // false in the other cases.
68806c3fb27SDimitry Andric     if (IsNegatedImplied || IsStrictLessThanImplied)
68906c3fb27SDimitry Andric       return IsNe;
69006c3fb27SDimitry Andric 
69106c3fb27SDimitry Andric     return std::nullopt;
69206c3fb27SDimitry Andric   }
69306c3fb27SDimitry Andric 
69406c3fb27SDimitry Andric   if (IsConditionImplied)
69506c3fb27SDimitry Andric     return true;
69606c3fb27SDimitry Andric 
69706c3fb27SDimitry Andric   auto Negated = ConstraintSystem::negate(Coefficients);
69806c3fb27SDimitry Andric   auto IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated);
69906c3fb27SDimitry Andric   if (IsNegatedImplied)
70006c3fb27SDimitry Andric     return false;
70106c3fb27SDimitry Andric 
70206c3fb27SDimitry Andric   // Neither the condition nor its negated holds, did not prove anything.
70306c3fb27SDimitry Andric   return std::nullopt;
70406c3fb27SDimitry Andric }
70506c3fb27SDimitry Andric 
70681ad6265SDimitry Andric bool ConstraintInfo::doesHold(CmpInst::Predicate Pred, Value *A,
70781ad6265SDimitry Andric                               Value *B) const {
708bdd1243dSDimitry Andric   auto R = getConstraintForSolving(Pred, A, B);
70906c3fb27SDimitry Andric   return R.isValid(*this) &&
710bdd1243dSDimitry Andric          getCS(R.IsSigned).isConditionImplied(R.Coefficients);
71181ad6265SDimitry Andric }
71281ad6265SDimitry Andric 
71381ad6265SDimitry Andric void ConstraintInfo::transferToOtherSystem(
714bdd1243dSDimitry Andric     CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn,
71581ad6265SDimitry Andric     unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack) {
71681ad6265SDimitry Andric   // Check if we can combine facts from the signed and unsigned systems to
71781ad6265SDimitry Andric   // derive additional facts.
71881ad6265SDimitry Andric   if (!A->getType()->isIntegerTy())
71981ad6265SDimitry Andric     return;
72081ad6265SDimitry Andric   // FIXME: This currently depends on the order we add facts. Ideally we
72181ad6265SDimitry Andric   // would first add all known facts and only then try to add additional
72281ad6265SDimitry Andric   // facts.
72381ad6265SDimitry Andric   switch (Pred) {
72481ad6265SDimitry Andric   default:
72581ad6265SDimitry Andric     break;
72681ad6265SDimitry Andric   case CmpInst::ICMP_ULT:
72781ad6265SDimitry Andric     //  If B is a signed positive constant, A >=s 0 and A <s B.
72881ad6265SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0))) {
729bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_SGE, A, ConstantInt::get(B->getType(), 0), NumIn,
730bdd1243dSDimitry Andric               NumOut, DFSInStack);
731bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_SLT, A, B, NumIn, NumOut, DFSInStack);
73281ad6265SDimitry Andric     }
73381ad6265SDimitry Andric     break;
73481ad6265SDimitry Andric   case CmpInst::ICMP_SLT:
73581ad6265SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, A, ConstantInt::get(B->getType(), 0)))
736bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_ULT, A, B, NumIn, NumOut, DFSInStack);
73781ad6265SDimitry Andric     break;
73806c3fb27SDimitry Andric   case CmpInst::ICMP_SGT: {
73981ad6265SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), -1)))
740bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_UGE, A, ConstantInt::get(B->getType(), 0), NumIn,
741bdd1243dSDimitry Andric               NumOut, DFSInStack);
74206c3fb27SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0)))
74306c3fb27SDimitry Andric       addFact(CmpInst::ICMP_UGT, A, B, NumIn, NumOut, DFSInStack);
74406c3fb27SDimitry Andric 
74581ad6265SDimitry Andric     break;
74606c3fb27SDimitry Andric   }
74781ad6265SDimitry Andric   case CmpInst::ICMP_SGE:
74881ad6265SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0))) {
749bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_UGE, A, B, NumIn, NumOut, DFSInStack);
75081ad6265SDimitry Andric     }
75181ad6265SDimitry Andric     break;
75281ad6265SDimitry Andric   }
753e8d8bef9SDimitry Andric }
754e8d8bef9SDimitry Andric 
755fe6060f1SDimitry Andric #ifndef NDEBUG
75681ad6265SDimitry Andric 
75706c3fb27SDimitry Andric static void dumpConstraint(ArrayRef<int64_t> C,
75806c3fb27SDimitry Andric                            const DenseMap<Value *, unsigned> &Value2Index) {
75906c3fb27SDimitry Andric   ConstraintSystem CS(Value2Index);
76081ad6265SDimitry Andric   CS.addVariableRowFill(C);
76106c3fb27SDimitry Andric   CS.dump();
76281ad6265SDimitry Andric }
763fe6060f1SDimitry Andric #endif
764fe6060f1SDimitry Andric 
76581ad6265SDimitry Andric void State::addInfoFor(BasicBlock &BB) {
766349cc55cSDimitry Andric   // True as long as long as the current instruction is guaranteed to execute.
767349cc55cSDimitry Andric   bool GuaranteedToExecute = true;
768bdd1243dSDimitry Andric   // Queue conditions and assumes.
769349cc55cSDimitry Andric   for (Instruction &I : BB) {
770bdd1243dSDimitry Andric     if (auto Cmp = dyn_cast<ICmpInst>(&I)) {
77106c3fb27SDimitry Andric       for (Use &U : Cmp->uses()) {
77206c3fb27SDimitry Andric         auto *UserI = getContextInstForUse(U);
77306c3fb27SDimitry Andric         auto *DTN = DT.getNode(UserI->getParent());
77406c3fb27SDimitry Andric         if (!DTN)
77506c3fb27SDimitry Andric           continue;
77606c3fb27SDimitry Andric         WorkList.push_back(FactOrCheck::getCheck(DTN, &U));
77706c3fb27SDimitry Andric       }
778bdd1243dSDimitry Andric       continue;
779bdd1243dSDimitry Andric     }
780bdd1243dSDimitry Andric 
781bdd1243dSDimitry Andric     if (match(&I, m_Intrinsic<Intrinsic::ssub_with_overflow>())) {
78206c3fb27SDimitry Andric       WorkList.push_back(
78306c3fb27SDimitry Andric           FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));
78406c3fb27SDimitry Andric       continue;
78506c3fb27SDimitry Andric     }
78606c3fb27SDimitry Andric 
78706c3fb27SDimitry Andric     if (isa<MinMaxIntrinsic>(&I)) {
78806c3fb27SDimitry Andric       WorkList.push_back(FactOrCheck::getFact(DT.getNode(&BB), &I));
789bdd1243dSDimitry Andric       continue;
790bdd1243dSDimitry Andric     }
791bdd1243dSDimitry Andric 
792349cc55cSDimitry Andric     Value *Cond;
793349cc55cSDimitry Andric     // For now, just handle assumes with a single compare as condition.
794349cc55cSDimitry Andric     if (match(&I, m_Intrinsic<Intrinsic::assume>(m_Value(Cond))) &&
79581ad6265SDimitry Andric         isa<ICmpInst>(Cond)) {
796349cc55cSDimitry Andric       if (GuaranteedToExecute) {
797349cc55cSDimitry Andric         // The assume is guaranteed to execute when BB is entered, hence Cond
798349cc55cSDimitry Andric         // holds on entry to BB.
799bdd1243dSDimitry Andric         WorkList.emplace_back(FactOrCheck::getFact(DT.getNode(I.getParent()),
800bdd1243dSDimitry Andric                                                    cast<Instruction>(Cond)));
801349cc55cSDimitry Andric       } else {
802bdd1243dSDimitry Andric         WorkList.emplace_back(
803bdd1243dSDimitry Andric             FactOrCheck::getFact(DT.getNode(I.getParent()), &I));
804349cc55cSDimitry Andric       }
805349cc55cSDimitry Andric     }
806349cc55cSDimitry Andric     GuaranteedToExecute &= isGuaranteedToTransferExecutionToSuccessor(&I);
807349cc55cSDimitry Andric   }
808349cc55cSDimitry Andric 
809e8d8bef9SDimitry Andric   auto *Br = dyn_cast<BranchInst>(BB.getTerminator());
810e8d8bef9SDimitry Andric   if (!Br || !Br->isConditional())
81181ad6265SDimitry Andric     return;
812e8d8bef9SDimitry Andric 
813bdd1243dSDimitry Andric   Value *Cond = Br->getCondition();
814e8d8bef9SDimitry Andric 
815bdd1243dSDimitry Andric   // If the condition is a chain of ORs/AND and the successor only has the
816bdd1243dSDimitry Andric   // current block as predecessor, queue conditions for the successor.
817bdd1243dSDimitry Andric   Value *Op0, *Op1;
818bdd1243dSDimitry Andric   if (match(Cond, m_LogicalOr(m_Value(Op0), m_Value(Op1))) ||
819bdd1243dSDimitry Andric       match(Cond, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {
820bdd1243dSDimitry Andric     bool IsOr = match(Cond, m_LogicalOr());
821bdd1243dSDimitry Andric     bool IsAnd = match(Cond, m_LogicalAnd());
822bdd1243dSDimitry Andric     // If there's a select that matches both AND and OR, we need to commit to
823bdd1243dSDimitry Andric     // one of the options. Arbitrarily pick OR.
824bdd1243dSDimitry Andric     if (IsOr && IsAnd)
825bdd1243dSDimitry Andric       IsAnd = false;
826bdd1243dSDimitry Andric 
827bdd1243dSDimitry Andric     BasicBlock *Successor = Br->getSuccessor(IsOr ? 1 : 0);
828bdd1243dSDimitry Andric     if (canAddSuccessor(BB, Successor)) {
829bdd1243dSDimitry Andric       SmallVector<Value *> CondWorkList;
830bdd1243dSDimitry Andric       SmallPtrSet<Value *, 8> SeenCond;
831bdd1243dSDimitry Andric       auto QueueValue = [&CondWorkList, &SeenCond](Value *V) {
832bdd1243dSDimitry Andric         if (SeenCond.insert(V).second)
833bdd1243dSDimitry Andric           CondWorkList.push_back(V);
834bdd1243dSDimitry Andric       };
835bdd1243dSDimitry Andric       QueueValue(Op1);
836bdd1243dSDimitry Andric       QueueValue(Op0);
837bdd1243dSDimitry Andric       while (!CondWorkList.empty()) {
838bdd1243dSDimitry Andric         Value *Cur = CondWorkList.pop_back_val();
839bdd1243dSDimitry Andric         if (auto *Cmp = dyn_cast<ICmpInst>(Cur)) {
840bdd1243dSDimitry Andric           WorkList.emplace_back(
841bdd1243dSDimitry Andric               FactOrCheck::getFact(DT.getNode(Successor), Cmp, IsOr));
842bdd1243dSDimitry Andric           continue;
843bdd1243dSDimitry Andric         }
844bdd1243dSDimitry Andric         if (IsOr && match(Cur, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) {
845bdd1243dSDimitry Andric           QueueValue(Op1);
846bdd1243dSDimitry Andric           QueueValue(Op0);
847bdd1243dSDimitry Andric           continue;
848bdd1243dSDimitry Andric         }
849bdd1243dSDimitry Andric         if (IsAnd && match(Cur, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {
850bdd1243dSDimitry Andric           QueueValue(Op1);
851bdd1243dSDimitry Andric           QueueValue(Op0);
852bdd1243dSDimitry Andric           continue;
853bdd1243dSDimitry Andric         }
854bdd1243dSDimitry Andric       }
855e8d8bef9SDimitry Andric     }
85681ad6265SDimitry Andric     return;
857e8d8bef9SDimitry Andric   }
858e8d8bef9SDimitry Andric 
85981ad6265SDimitry Andric   auto *CmpI = dyn_cast<ICmpInst>(Br->getCondition());
860e8d8bef9SDimitry Andric   if (!CmpI)
86181ad6265SDimitry Andric     return;
86281ad6265SDimitry Andric   if (canAddSuccessor(BB, Br->getSuccessor(0)))
863bdd1243dSDimitry Andric     WorkList.emplace_back(
864bdd1243dSDimitry Andric         FactOrCheck::getFact(DT.getNode(Br->getSuccessor(0)), CmpI));
86581ad6265SDimitry Andric   if (canAddSuccessor(BB, Br->getSuccessor(1)))
866bdd1243dSDimitry Andric     WorkList.emplace_back(
867bdd1243dSDimitry Andric         FactOrCheck::getFact(DT.getNode(Br->getSuccessor(1)), CmpI, true));
868bdd1243dSDimitry Andric }
869bdd1243dSDimitry Andric 
87006c3fb27SDimitry Andric namespace {
87106c3fb27SDimitry Andric /// Helper to keep track of a condition and if it should be treated as negated
87206c3fb27SDimitry Andric /// for reproducer construction.
87306c3fb27SDimitry Andric /// Pred == Predicate::BAD_ICMP_PREDICATE indicates that this entry is a
87406c3fb27SDimitry Andric /// placeholder to keep the ReproducerCondStack in sync with DFSInStack.
87506c3fb27SDimitry Andric struct ReproducerEntry {
87606c3fb27SDimitry Andric   ICmpInst::Predicate Pred;
87706c3fb27SDimitry Andric   Value *LHS;
87806c3fb27SDimitry Andric   Value *RHS;
87906c3fb27SDimitry Andric 
88006c3fb27SDimitry Andric   ReproducerEntry(ICmpInst::Predicate Pred, Value *LHS, Value *RHS)
88106c3fb27SDimitry Andric       : Pred(Pred), LHS(LHS), RHS(RHS) {}
88206c3fb27SDimitry Andric };
88306c3fb27SDimitry Andric } // namespace
88406c3fb27SDimitry Andric 
88506c3fb27SDimitry Andric /// Helper function to generate a reproducer function for simplifying \p Cond.
88606c3fb27SDimitry Andric /// The reproducer function contains a series of @llvm.assume calls, one for
88706c3fb27SDimitry Andric /// each condition in \p Stack. For each condition, the operand instruction are
88806c3fb27SDimitry Andric /// cloned until we reach operands that have an entry in \p Value2Index. Those
88906c3fb27SDimitry Andric /// will then be added as function arguments. \p DT is used to order cloned
89006c3fb27SDimitry Andric /// instructions. The reproducer function will get added to \p M, if it is
89106c3fb27SDimitry Andric /// non-null. Otherwise no reproducer function is generated.
89206c3fb27SDimitry Andric static void generateReproducer(CmpInst *Cond, Module *M,
89306c3fb27SDimitry Andric                                ArrayRef<ReproducerEntry> Stack,
89406c3fb27SDimitry Andric                                ConstraintInfo &Info, DominatorTree &DT) {
89506c3fb27SDimitry Andric   if (!M)
89606c3fb27SDimitry Andric     return;
89706c3fb27SDimitry Andric 
89806c3fb27SDimitry Andric   LLVMContext &Ctx = Cond->getContext();
89906c3fb27SDimitry Andric 
90006c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "Creating reproducer for " << *Cond << "\n");
90106c3fb27SDimitry Andric 
90206c3fb27SDimitry Andric   ValueToValueMapTy Old2New;
90306c3fb27SDimitry Andric   SmallVector<Value *> Args;
90406c3fb27SDimitry Andric   SmallPtrSet<Value *, 8> Seen;
90506c3fb27SDimitry Andric   // Traverse Cond and its operands recursively until we reach a value that's in
90606c3fb27SDimitry Andric   // Value2Index or not an instruction, or not a operation that
90706c3fb27SDimitry Andric   // ConstraintElimination can decompose. Such values will be considered as
90806c3fb27SDimitry Andric   // external inputs to the reproducer, they are collected and added as function
90906c3fb27SDimitry Andric   // arguments later.
91006c3fb27SDimitry Andric   auto CollectArguments = [&](ArrayRef<Value *> Ops, bool IsSigned) {
91106c3fb27SDimitry Andric     auto &Value2Index = Info.getValue2Index(IsSigned);
91206c3fb27SDimitry Andric     SmallVector<Value *, 4> WorkList(Ops);
91306c3fb27SDimitry Andric     while (!WorkList.empty()) {
91406c3fb27SDimitry Andric       Value *V = WorkList.pop_back_val();
91506c3fb27SDimitry Andric       if (!Seen.insert(V).second)
91606c3fb27SDimitry Andric         continue;
91706c3fb27SDimitry Andric       if (Old2New.find(V) != Old2New.end())
91806c3fb27SDimitry Andric         continue;
91906c3fb27SDimitry Andric       if (isa<Constant>(V))
92006c3fb27SDimitry Andric         continue;
92106c3fb27SDimitry Andric 
92206c3fb27SDimitry Andric       auto *I = dyn_cast<Instruction>(V);
92306c3fb27SDimitry Andric       if (Value2Index.contains(V) || !I ||
92406c3fb27SDimitry Andric           !isa<CmpInst, BinaryOperator, GEPOperator, CastInst>(V)) {
92506c3fb27SDimitry Andric         Old2New[V] = V;
92606c3fb27SDimitry Andric         Args.push_back(V);
92706c3fb27SDimitry Andric         LLVM_DEBUG(dbgs() << "  found external input " << *V << "\n");
92806c3fb27SDimitry Andric       } else {
92906c3fb27SDimitry Andric         append_range(WorkList, I->operands());
93006c3fb27SDimitry Andric       }
93106c3fb27SDimitry Andric     }
93206c3fb27SDimitry Andric   };
93306c3fb27SDimitry Andric 
93406c3fb27SDimitry Andric   for (auto &Entry : Stack)
93506c3fb27SDimitry Andric     if (Entry.Pred != ICmpInst::BAD_ICMP_PREDICATE)
93606c3fb27SDimitry Andric       CollectArguments({Entry.LHS, Entry.RHS}, ICmpInst::isSigned(Entry.Pred));
93706c3fb27SDimitry Andric   CollectArguments(Cond, ICmpInst::isSigned(Cond->getPredicate()));
93806c3fb27SDimitry Andric 
93906c3fb27SDimitry Andric   SmallVector<Type *> ParamTys;
94006c3fb27SDimitry Andric   for (auto *P : Args)
94106c3fb27SDimitry Andric     ParamTys.push_back(P->getType());
94206c3fb27SDimitry Andric 
94306c3fb27SDimitry Andric   FunctionType *FTy = FunctionType::get(Cond->getType(), ParamTys,
94406c3fb27SDimitry Andric                                         /*isVarArg=*/false);
94506c3fb27SDimitry Andric   Function *F = Function::Create(FTy, Function::ExternalLinkage,
94606c3fb27SDimitry Andric                                  Cond->getModule()->getName() +
94706c3fb27SDimitry Andric                                      Cond->getFunction()->getName() + "repro",
94806c3fb27SDimitry Andric                                  M);
94906c3fb27SDimitry Andric   // Add arguments to the reproducer function for each external value collected.
95006c3fb27SDimitry Andric   for (unsigned I = 0; I < Args.size(); ++I) {
95106c3fb27SDimitry Andric     F->getArg(I)->setName(Args[I]->getName());
95206c3fb27SDimitry Andric     Old2New[Args[I]] = F->getArg(I);
95306c3fb27SDimitry Andric   }
95406c3fb27SDimitry Andric 
95506c3fb27SDimitry Andric   BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F);
95606c3fb27SDimitry Andric   IRBuilder<> Builder(Entry);
95706c3fb27SDimitry Andric   Builder.CreateRet(Builder.getTrue());
95806c3fb27SDimitry Andric   Builder.SetInsertPoint(Entry->getTerminator());
95906c3fb27SDimitry Andric 
96006c3fb27SDimitry Andric   // Clone instructions in \p Ops and their operands recursively until reaching
96106c3fb27SDimitry Andric   // an value in Value2Index (external input to the reproducer). Update Old2New
96206c3fb27SDimitry Andric   // mapping for the original and cloned instructions. Sort instructions to
96306c3fb27SDimitry Andric   // clone by dominance, then insert the cloned instructions in the function.
96406c3fb27SDimitry Andric   auto CloneInstructions = [&](ArrayRef<Value *> Ops, bool IsSigned) {
96506c3fb27SDimitry Andric     SmallVector<Value *, 4> WorkList(Ops);
96606c3fb27SDimitry Andric     SmallVector<Instruction *> ToClone;
96706c3fb27SDimitry Andric     auto &Value2Index = Info.getValue2Index(IsSigned);
96806c3fb27SDimitry Andric     while (!WorkList.empty()) {
96906c3fb27SDimitry Andric       Value *V = WorkList.pop_back_val();
97006c3fb27SDimitry Andric       if (Old2New.find(V) != Old2New.end())
97106c3fb27SDimitry Andric         continue;
97206c3fb27SDimitry Andric 
97306c3fb27SDimitry Andric       auto *I = dyn_cast<Instruction>(V);
97406c3fb27SDimitry Andric       if (!Value2Index.contains(V) && I) {
97506c3fb27SDimitry Andric         Old2New[V] = nullptr;
97606c3fb27SDimitry Andric         ToClone.push_back(I);
97706c3fb27SDimitry Andric         append_range(WorkList, I->operands());
97806c3fb27SDimitry Andric       }
97906c3fb27SDimitry Andric     }
98006c3fb27SDimitry Andric 
98106c3fb27SDimitry Andric     sort(ToClone,
98206c3fb27SDimitry Andric          [&DT](Instruction *A, Instruction *B) { return DT.dominates(A, B); });
98306c3fb27SDimitry Andric     for (Instruction *I : ToClone) {
98406c3fb27SDimitry Andric       Instruction *Cloned = I->clone();
98506c3fb27SDimitry Andric       Old2New[I] = Cloned;
98606c3fb27SDimitry Andric       Old2New[I]->setName(I->getName());
98706c3fb27SDimitry Andric       Cloned->insertBefore(&*Builder.GetInsertPoint());
98806c3fb27SDimitry Andric       Cloned->dropUnknownNonDebugMetadata();
98906c3fb27SDimitry Andric       Cloned->setDebugLoc({});
99006c3fb27SDimitry Andric     }
99106c3fb27SDimitry Andric   };
99206c3fb27SDimitry Andric 
99306c3fb27SDimitry Andric   // Materialize the assumptions for the reproducer using the entries in Stack.
99406c3fb27SDimitry Andric   // That is, first clone the operands of the condition recursively until we
99506c3fb27SDimitry Andric   // reach an external input to the reproducer and add them to the reproducer
99606c3fb27SDimitry Andric   // function. Then add an ICmp for the condition (with the inverse predicate if
99706c3fb27SDimitry Andric   // the entry is negated) and an assert using the ICmp.
99806c3fb27SDimitry Andric   for (auto &Entry : Stack) {
99906c3fb27SDimitry Andric     if (Entry.Pred == ICmpInst::BAD_ICMP_PREDICATE)
100006c3fb27SDimitry Andric       continue;
100106c3fb27SDimitry Andric 
100206c3fb27SDimitry Andric     LLVM_DEBUG(
100306c3fb27SDimitry Andric         dbgs() << "  Materializing assumption icmp " << Entry.Pred << ' ';
100406c3fb27SDimitry Andric         Entry.LHS->printAsOperand(dbgs(), /*PrintType=*/true); dbgs() << ", ";
100506c3fb27SDimitry Andric         Entry.RHS->printAsOperand(dbgs(), /*PrintType=*/false); dbgs() << "\n");
100606c3fb27SDimitry Andric     CloneInstructions({Entry.LHS, Entry.RHS}, CmpInst::isSigned(Entry.Pred));
100706c3fb27SDimitry Andric 
100806c3fb27SDimitry Andric     auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS);
100906c3fb27SDimitry Andric     Builder.CreateAssumption(Cmp);
101006c3fb27SDimitry Andric   }
101106c3fb27SDimitry Andric 
101206c3fb27SDimitry Andric   // Finally, clone the condition to reproduce and remap instruction operands in
101306c3fb27SDimitry Andric   // the reproducer using Old2New.
101406c3fb27SDimitry Andric   CloneInstructions(Cond, CmpInst::isSigned(Cond->getPredicate()));
101506c3fb27SDimitry Andric   Entry->getTerminator()->setOperand(0, Cond);
101606c3fb27SDimitry Andric   remapInstructionsInBlocks({Entry}, Old2New);
101706c3fb27SDimitry Andric 
101806c3fb27SDimitry Andric   assert(!verifyFunction(*F, &dbgs()));
101906c3fb27SDimitry Andric }
102006c3fb27SDimitry Andric 
102106c3fb27SDimitry Andric static std::optional<bool> checkCondition(CmpInst *Cmp, ConstraintInfo &Info,
102206c3fb27SDimitry Andric                                           unsigned NumIn, unsigned NumOut,
102306c3fb27SDimitry Andric                                           Instruction *ContextInst) {
1024bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "Checking " << *Cmp << "\n");
1025bdd1243dSDimitry Andric 
1026bdd1243dSDimitry Andric   CmpInst::Predicate Pred = Cmp->getPredicate();
1027bdd1243dSDimitry Andric   Value *A = Cmp->getOperand(0);
1028bdd1243dSDimitry Andric   Value *B = Cmp->getOperand(1);
1029bdd1243dSDimitry Andric 
1030bdd1243dSDimitry Andric   auto R = Info.getConstraintForSolving(Pred, A, B);
1031bdd1243dSDimitry Andric   if (R.empty() || !R.isValid(Info)){
1032bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "   failed to decompose condition\n");
103306c3fb27SDimitry Andric     return std::nullopt;
1034bdd1243dSDimitry Andric   }
1035bdd1243dSDimitry Andric 
1036bdd1243dSDimitry Andric   auto &CSToUse = Info.getCS(R.IsSigned);
1037bdd1243dSDimitry Andric 
1038bdd1243dSDimitry Andric   // If there was extra information collected during decomposition, apply
1039bdd1243dSDimitry Andric   // it now and remove it immediately once we are done with reasoning
1040bdd1243dSDimitry Andric   // about the constraint.
1041bdd1243dSDimitry Andric   for (auto &Row : R.ExtraInfo)
1042bdd1243dSDimitry Andric     CSToUse.addVariableRow(Row);
1043bdd1243dSDimitry Andric   auto InfoRestorer = make_scope_exit([&]() {
1044bdd1243dSDimitry Andric     for (unsigned I = 0; I < R.ExtraInfo.size(); ++I)
1045bdd1243dSDimitry Andric       CSToUse.popLastConstraint();
1046bdd1243dSDimitry Andric   });
1047bdd1243dSDimitry Andric 
104806c3fb27SDimitry Andric   if (auto ImpliedCondition = R.isImpliedBy(CSToUse)) {
1049bdd1243dSDimitry Andric     if (!DebugCounter::shouldExecute(EliminatedCounter))
105006c3fb27SDimitry Andric       return std::nullopt;
1051bdd1243dSDimitry Andric 
1052bdd1243dSDimitry Andric     LLVM_DEBUG({
105306c3fb27SDimitry Andric       if (*ImpliedCondition) {
105406c3fb27SDimitry Andric         dbgs() << "Condition " << *Cmp;
105506c3fb27SDimitry Andric       } else {
105606c3fb27SDimitry Andric         auto InversePred = Cmp->getInversePredicate();
105706c3fb27SDimitry Andric         dbgs() << "Condition " << CmpInst::getPredicateName(InversePred) << " "
105806c3fb27SDimitry Andric                << *A << ", " << *B;
105906c3fb27SDimitry Andric       }
106006c3fb27SDimitry Andric       dbgs() << " implied by dominating constraints\n";
106106c3fb27SDimitry Andric       CSToUse.dump();
1062bdd1243dSDimitry Andric     });
106306c3fb27SDimitry Andric     return ImpliedCondition;
106406c3fb27SDimitry Andric   }
106506c3fb27SDimitry Andric 
106606c3fb27SDimitry Andric   return std::nullopt;
106706c3fb27SDimitry Andric }
106806c3fb27SDimitry Andric 
106906c3fb27SDimitry Andric static bool checkAndReplaceCondition(
107006c3fb27SDimitry Andric     CmpInst *Cmp, ConstraintInfo &Info, unsigned NumIn, unsigned NumOut,
107106c3fb27SDimitry Andric     Instruction *ContextInst, Module *ReproducerModule,
107206c3fb27SDimitry Andric     ArrayRef<ReproducerEntry> ReproducerCondStack, DominatorTree &DT) {
107306c3fb27SDimitry Andric   auto ReplaceCmpWithConstant = [&](CmpInst *Cmp, bool IsTrue) {
107406c3fb27SDimitry Andric     generateReproducer(Cmp, ReproducerModule, ReproducerCondStack, Info, DT);
107506c3fb27SDimitry Andric     Constant *ConstantC = ConstantInt::getBool(
107606c3fb27SDimitry Andric         CmpInst::makeCmpResultType(Cmp->getType()), IsTrue);
107706c3fb27SDimitry Andric     Cmp->replaceUsesWithIf(ConstantC, [&DT, NumIn, NumOut,
107806c3fb27SDimitry Andric                                        ContextInst](Use &U) {
107906c3fb27SDimitry Andric       auto *UserI = getContextInstForUse(U);
108006c3fb27SDimitry Andric       auto *DTN = DT.getNode(UserI->getParent());
108106c3fb27SDimitry Andric       if (!DTN || DTN->getDFSNumIn() < NumIn || DTN->getDFSNumOut() > NumOut)
108206c3fb27SDimitry Andric         return false;
108306c3fb27SDimitry Andric       if (UserI->getParent() == ContextInst->getParent() &&
108406c3fb27SDimitry Andric           UserI->comesBefore(ContextInst))
108506c3fb27SDimitry Andric         return false;
108606c3fb27SDimitry Andric 
1087bdd1243dSDimitry Andric       // Conditions in an assume trivially simplify to true. Skip uses
1088bdd1243dSDimitry Andric       // in assume calls to not destroy the available information.
1089bdd1243dSDimitry Andric       auto *II = dyn_cast<IntrinsicInst>(U.getUser());
1090bdd1243dSDimitry Andric       return !II || II->getIntrinsicID() != Intrinsic::assume;
1091bdd1243dSDimitry Andric     });
1092bdd1243dSDimitry Andric     NumCondsRemoved++;
109306c3fb27SDimitry Andric     return true;
109406c3fb27SDimitry Andric   };
109506c3fb27SDimitry Andric 
109606c3fb27SDimitry Andric   if (auto ImpliedCondition =
109706c3fb27SDimitry Andric           checkCondition(Cmp, Info, NumIn, NumOut, ContextInst))
109806c3fb27SDimitry Andric     return ReplaceCmpWithConstant(Cmp, *ImpliedCondition);
109906c3fb27SDimitry Andric   return false;
1100bdd1243dSDimitry Andric }
110106c3fb27SDimitry Andric 
110206c3fb27SDimitry Andric static void
110306c3fb27SDimitry Andric removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info,
110406c3fb27SDimitry Andric                      Module *ReproducerModule,
110506c3fb27SDimitry Andric                      SmallVectorImpl<ReproducerEntry> &ReproducerCondStack,
110606c3fb27SDimitry Andric                      SmallVectorImpl<StackEntry> &DFSInStack) {
110706c3fb27SDimitry Andric   Info.popLastConstraint(E.IsSigned);
110806c3fb27SDimitry Andric   // Remove variables in the system that went out of scope.
110906c3fb27SDimitry Andric   auto &Mapping = Info.getValue2Index(E.IsSigned);
111006c3fb27SDimitry Andric   for (Value *V : E.ValuesToRelease)
111106c3fb27SDimitry Andric     Mapping.erase(V);
111206c3fb27SDimitry Andric   Info.popLastNVariables(E.IsSigned, E.ValuesToRelease.size());
111306c3fb27SDimitry Andric   DFSInStack.pop_back();
111406c3fb27SDimitry Andric   if (ReproducerModule)
111506c3fb27SDimitry Andric     ReproducerCondStack.pop_back();
111606c3fb27SDimitry Andric }
111706c3fb27SDimitry Andric 
111806c3fb27SDimitry Andric /// Check if the first condition for an AND implies the second.
111906c3fb27SDimitry Andric static bool checkAndSecondOpImpliedByFirst(
112006c3fb27SDimitry Andric     FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule,
112106c3fb27SDimitry Andric     SmallVectorImpl<ReproducerEntry> &ReproducerCondStack,
112206c3fb27SDimitry Andric     SmallVectorImpl<StackEntry> &DFSInStack) {
112306c3fb27SDimitry Andric   CmpInst::Predicate Pred;
112406c3fb27SDimitry Andric   Value *A, *B;
112506c3fb27SDimitry Andric   Instruction *And = CB.getContextInst();
112606c3fb27SDimitry Andric   if (!match(And->getOperand(0), m_ICmp(Pred, m_Value(A), m_Value(B))))
1127bdd1243dSDimitry Andric     return false;
1128bdd1243dSDimitry Andric 
112906c3fb27SDimitry Andric   // Optimistically add fact from first condition.
113006c3fb27SDimitry Andric   unsigned OldSize = DFSInStack.size();
113106c3fb27SDimitry Andric   Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
113206c3fb27SDimitry Andric   if (OldSize == DFSInStack.size())
113306c3fb27SDimitry Andric     return false;
113406c3fb27SDimitry Andric 
113506c3fb27SDimitry Andric   bool Changed = false;
113606c3fb27SDimitry Andric   // Check if the second condition can be simplified now.
113706c3fb27SDimitry Andric   if (auto ImpliedCondition =
113806c3fb27SDimitry Andric           checkCondition(cast<ICmpInst>(And->getOperand(1)), Info, CB.NumIn,
113906c3fb27SDimitry Andric                          CB.NumOut, CB.getContextInst())) {
114006c3fb27SDimitry Andric     And->setOperand(1, ConstantInt::getBool(And->getType(), *ImpliedCondition));
1141bdd1243dSDimitry Andric     Changed = true;
1142bdd1243dSDimitry Andric   }
114306c3fb27SDimitry Andric 
114406c3fb27SDimitry Andric   // Remove entries again.
114506c3fb27SDimitry Andric   while (OldSize < DFSInStack.size()) {
114606c3fb27SDimitry Andric     StackEntry E = DFSInStack.back();
114706c3fb27SDimitry Andric     removeEntryFromStack(E, Info, ReproducerModule, ReproducerCondStack,
114806c3fb27SDimitry Andric                          DFSInStack);
114906c3fb27SDimitry Andric   }
1150bdd1243dSDimitry Andric   return Changed;
1151e8d8bef9SDimitry Andric }
1152e8d8bef9SDimitry Andric 
115381ad6265SDimitry Andric void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B,
1154bdd1243dSDimitry Andric                              unsigned NumIn, unsigned NumOut,
115581ad6265SDimitry Andric                              SmallVectorImpl<StackEntry> &DFSInStack) {
115681ad6265SDimitry Andric   // If the constraint has a pre-condition, skip the constraint if it does not
115781ad6265SDimitry Andric   // hold.
1158bdd1243dSDimitry Andric   SmallVector<Value *> NewVariables;
1159bdd1243dSDimitry Andric   auto R = getConstraint(Pred, A, B, NewVariables);
116006c3fb27SDimitry Andric 
116106c3fb27SDimitry Andric   // TODO: Support non-equality for facts as well.
116206c3fb27SDimitry Andric   if (!R.isValid(*this) || R.isNe())
116381ad6265SDimitry Andric     return;
116481ad6265SDimitry Andric 
116506c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "Adding '" << Pred << " ";
1166bdd1243dSDimitry Andric              A->printAsOperand(dbgs(), false); dbgs() << ", ";
1167bdd1243dSDimitry Andric              B->printAsOperand(dbgs(), false); dbgs() << "'\n");
116881ad6265SDimitry Andric   bool Added = false;
116981ad6265SDimitry Andric   auto &CSToUse = getCS(R.IsSigned);
117081ad6265SDimitry Andric   if (R.Coefficients.empty())
117181ad6265SDimitry Andric     return;
117281ad6265SDimitry Andric 
117381ad6265SDimitry Andric   Added |= CSToUse.addVariableRowFill(R.Coefficients);
117481ad6265SDimitry Andric 
1175bdd1243dSDimitry Andric   // If R has been added to the system, add the new variables and queue it for
1176bdd1243dSDimitry Andric   // removal once it goes out-of-scope.
117781ad6265SDimitry Andric   if (Added) {
117881ad6265SDimitry Andric     SmallVector<Value *, 2> ValuesToRelease;
1179bdd1243dSDimitry Andric     auto &Value2Index = getValue2Index(R.IsSigned);
1180bdd1243dSDimitry Andric     for (Value *V : NewVariables) {
1181bdd1243dSDimitry Andric       Value2Index.insert({V, Value2Index.size() + 1});
1182bdd1243dSDimitry Andric       ValuesToRelease.push_back(V);
118381ad6265SDimitry Andric     }
118481ad6265SDimitry Andric 
118581ad6265SDimitry Andric     LLVM_DEBUG({
118681ad6265SDimitry Andric       dbgs() << "  constraint: ";
118706c3fb27SDimitry Andric       dumpConstraint(R.Coefficients, getValue2Index(R.IsSigned));
1188bdd1243dSDimitry Andric       dbgs() << "\n";
118981ad6265SDimitry Andric     });
119081ad6265SDimitry Andric 
1191bdd1243dSDimitry Andric     DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,
1192bdd1243dSDimitry Andric                             std::move(ValuesToRelease));
119381ad6265SDimitry Andric 
119406c3fb27SDimitry Andric     if (R.isEq()) {
119581ad6265SDimitry Andric       // Also add the inverted constraint for equality constraints.
119681ad6265SDimitry Andric       for (auto &Coeff : R.Coefficients)
119781ad6265SDimitry Andric         Coeff *= -1;
119881ad6265SDimitry Andric       CSToUse.addVariableRowFill(R.Coefficients);
119981ad6265SDimitry Andric 
1200bdd1243dSDimitry Andric       DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,
120181ad6265SDimitry Andric                               SmallVector<Value *, 2>());
120281ad6265SDimitry Andric     }
120381ad6265SDimitry Andric   }
120481ad6265SDimitry Andric }
120581ad6265SDimitry Andric 
1206bdd1243dSDimitry Andric static bool replaceSubOverflowUses(IntrinsicInst *II, Value *A, Value *B,
1207bdd1243dSDimitry Andric                                    SmallVectorImpl<Instruction *> &ToRemove) {
1208bdd1243dSDimitry Andric   bool Changed = false;
1209bdd1243dSDimitry Andric   IRBuilder<> Builder(II->getParent(), II->getIterator());
1210bdd1243dSDimitry Andric   Value *Sub = nullptr;
1211bdd1243dSDimitry Andric   for (User *U : make_early_inc_range(II->users())) {
1212bdd1243dSDimitry Andric     if (match(U, m_ExtractValue<0>(m_Value()))) {
1213bdd1243dSDimitry Andric       if (!Sub)
1214bdd1243dSDimitry Andric         Sub = Builder.CreateSub(A, B);
1215bdd1243dSDimitry Andric       U->replaceAllUsesWith(Sub);
1216bdd1243dSDimitry Andric       Changed = true;
1217bdd1243dSDimitry Andric     } else if (match(U, m_ExtractValue<1>(m_Value()))) {
1218bdd1243dSDimitry Andric       U->replaceAllUsesWith(Builder.getFalse());
1219bdd1243dSDimitry Andric       Changed = true;
1220bdd1243dSDimitry Andric     } else
1221bdd1243dSDimitry Andric       continue;
1222bdd1243dSDimitry Andric 
1223bdd1243dSDimitry Andric     if (U->use_empty()) {
1224bdd1243dSDimitry Andric       auto *I = cast<Instruction>(U);
1225bdd1243dSDimitry Andric       ToRemove.push_back(I);
1226bdd1243dSDimitry Andric       I->setOperand(0, PoisonValue::get(II->getType()));
1227bdd1243dSDimitry Andric       Changed = true;
1228bdd1243dSDimitry Andric     }
1229bdd1243dSDimitry Andric   }
1230bdd1243dSDimitry Andric 
1231bdd1243dSDimitry Andric   if (II->use_empty()) {
1232bdd1243dSDimitry Andric     II->eraseFromParent();
1233bdd1243dSDimitry Andric     Changed = true;
1234bdd1243dSDimitry Andric   }
1235bdd1243dSDimitry Andric   return Changed;
1236bdd1243dSDimitry Andric }
1237bdd1243dSDimitry Andric 
1238bdd1243dSDimitry Andric static bool
123981ad6265SDimitry Andric tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
124081ad6265SDimitry Andric                           SmallVectorImpl<Instruction *> &ToRemove) {
124181ad6265SDimitry Andric   auto DoesConditionHold = [](CmpInst::Predicate Pred, Value *A, Value *B,
124281ad6265SDimitry Andric                               ConstraintInfo &Info) {
1243bdd1243dSDimitry Andric     auto R = Info.getConstraintForSolving(Pred, A, B);
1244bdd1243dSDimitry Andric     if (R.size() < 2 || !R.isValid(Info))
124581ad6265SDimitry Andric       return false;
124681ad6265SDimitry Andric 
1247bdd1243dSDimitry Andric     auto &CSToUse = Info.getCS(R.IsSigned);
124881ad6265SDimitry Andric     return CSToUse.isConditionImplied(R.Coefficients);
124981ad6265SDimitry Andric   };
125081ad6265SDimitry Andric 
1251bdd1243dSDimitry Andric   bool Changed = false;
125281ad6265SDimitry Andric   if (II->getIntrinsicID() == Intrinsic::ssub_with_overflow) {
125381ad6265SDimitry Andric     // If A s>= B && B s>= 0, ssub.with.overflow(a, b) should not overflow and
125481ad6265SDimitry Andric     // can be simplified to a regular sub.
125581ad6265SDimitry Andric     Value *A = II->getArgOperand(0);
125681ad6265SDimitry Andric     Value *B = II->getArgOperand(1);
125781ad6265SDimitry Andric     if (!DoesConditionHold(CmpInst::ICMP_SGE, A, B, Info) ||
125881ad6265SDimitry Andric         !DoesConditionHold(CmpInst::ICMP_SGE, B,
125981ad6265SDimitry Andric                            ConstantInt::get(A->getType(), 0), Info))
1260bdd1243dSDimitry Andric       return false;
1261bdd1243dSDimitry Andric     Changed = replaceSubOverflowUses(II, A, B, ToRemove);
126281ad6265SDimitry Andric   }
1263bdd1243dSDimitry Andric   return Changed;
126481ad6265SDimitry Andric }
126581ad6265SDimitry Andric 
126606c3fb27SDimitry Andric static bool eliminateConstraints(Function &F, DominatorTree &DT,
126706c3fb27SDimitry Andric                                  OptimizationRemarkEmitter &ORE) {
126881ad6265SDimitry Andric   bool Changed = false;
126981ad6265SDimitry Andric   DT.updateDFSNumbers();
127006c3fb27SDimitry Andric   SmallVector<Value *> FunctionArgs;
127106c3fb27SDimitry Andric   for (Value &Arg : F.args())
127206c3fb27SDimitry Andric     FunctionArgs.push_back(&Arg);
127306c3fb27SDimitry Andric   ConstraintInfo Info(F.getParent()->getDataLayout(), FunctionArgs);
127481ad6265SDimitry Andric   State S(DT);
127506c3fb27SDimitry Andric   std::unique_ptr<Module> ReproducerModule(
127606c3fb27SDimitry Andric       DumpReproducers ? new Module(F.getName(), F.getContext()) : nullptr);
127781ad6265SDimitry Andric 
127881ad6265SDimitry Andric   // First, collect conditions implied by branches and blocks with their
127981ad6265SDimitry Andric   // Dominator DFS in and out numbers.
128081ad6265SDimitry Andric   for (BasicBlock &BB : F) {
128181ad6265SDimitry Andric     if (!DT.getNode(&BB))
128281ad6265SDimitry Andric       continue;
128381ad6265SDimitry Andric     S.addInfoFor(BB);
128481ad6265SDimitry Andric   }
128581ad6265SDimitry Andric 
1286bdd1243dSDimitry Andric   // Next, sort worklist by dominance, so that dominating conditions to check
1287bdd1243dSDimitry Andric   // and facts come before conditions and facts dominated by them. If a
1288bdd1243dSDimitry Andric   // condition to check and a fact have the same numbers, conditional facts come
1289bdd1243dSDimitry Andric   // first. Assume facts and checks are ordered according to their relative
1290bdd1243dSDimitry Andric   // order in the containing basic block. Also make sure conditions with
1291bdd1243dSDimitry Andric   // constant operands come before conditions without constant operands. This
1292bdd1243dSDimitry Andric   // increases the effectiveness of the current signed <-> unsigned fact
1293bdd1243dSDimitry Andric   // transfer logic.
1294bdd1243dSDimitry Andric   stable_sort(S.WorkList, [](const FactOrCheck &A, const FactOrCheck &B) {
1295bdd1243dSDimitry Andric     auto HasNoConstOp = [](const FactOrCheck &B) {
1296bdd1243dSDimitry Andric       return !isa<ConstantInt>(B.Inst->getOperand(0)) &&
1297bdd1243dSDimitry Andric              !isa<ConstantInt>(B.Inst->getOperand(1));
1298bdd1243dSDimitry Andric     };
1299bdd1243dSDimitry Andric     // If both entries have the same In numbers, conditional facts come first.
1300bdd1243dSDimitry Andric     // Otherwise use the relative order in the basic block.
1301bdd1243dSDimitry Andric     if (A.NumIn == B.NumIn) {
1302bdd1243dSDimitry Andric       if (A.isConditionFact() && B.isConditionFact()) {
1303bdd1243dSDimitry Andric         bool NoConstOpA = HasNoConstOp(A);
1304bdd1243dSDimitry Andric         bool NoConstOpB = HasNoConstOp(B);
1305bdd1243dSDimitry Andric         return NoConstOpA < NoConstOpB;
1306bdd1243dSDimitry Andric       }
1307bdd1243dSDimitry Andric       if (A.isConditionFact())
1308bdd1243dSDimitry Andric         return true;
1309bdd1243dSDimitry Andric       if (B.isConditionFact())
1310bdd1243dSDimitry Andric         return false;
131106c3fb27SDimitry Andric       auto *InstA = A.getContextInst();
131206c3fb27SDimitry Andric       auto *InstB = B.getContextInst();
131306c3fb27SDimitry Andric       return InstA->comesBefore(InstB);
1314bdd1243dSDimitry Andric     }
1315bdd1243dSDimitry Andric     return A.NumIn < B.NumIn;
1316e8d8bef9SDimitry Andric   });
1317e8d8bef9SDimitry Andric 
131881ad6265SDimitry Andric   SmallVector<Instruction *> ToRemove;
131981ad6265SDimitry Andric 
1320e8d8bef9SDimitry Andric   // Finally, process ordered worklist and eliminate implied conditions.
1321e8d8bef9SDimitry Andric   SmallVector<StackEntry, 16> DFSInStack;
132206c3fb27SDimitry Andric   SmallVector<ReproducerEntry> ReproducerCondStack;
1323bdd1243dSDimitry Andric   for (FactOrCheck &CB : S.WorkList) {
1324e8d8bef9SDimitry Andric     // First, pop entries from the stack that are out-of-scope for CB. Remove
1325e8d8bef9SDimitry Andric     // the corresponding entry from the constraint system.
1326e8d8bef9SDimitry Andric     while (!DFSInStack.empty()) {
1327e8d8bef9SDimitry Andric       auto &E = DFSInStack.back();
1328e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "Top of stack : " << E.NumIn << " " << E.NumOut
1329e8d8bef9SDimitry Andric                         << "\n");
1330e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "CB: " << CB.NumIn << " " << CB.NumOut << "\n");
1331e8d8bef9SDimitry Andric       assert(E.NumIn <= CB.NumIn);
1332e8d8bef9SDimitry Andric       if (CB.NumOut <= E.NumOut)
1333e8d8bef9SDimitry Andric         break;
133481ad6265SDimitry Andric       LLVM_DEBUG({
133581ad6265SDimitry Andric         dbgs() << "Removing ";
133606c3fb27SDimitry Andric         dumpConstraint(Info.getCS(E.IsSigned).getLastConstraint(),
133781ad6265SDimitry Andric                        Info.getValue2Index(E.IsSigned));
133881ad6265SDimitry Andric         dbgs() << "\n";
133981ad6265SDimitry Andric       });
134006c3fb27SDimitry Andric       removeEntryFromStack(E, Info, ReproducerModule.get(), ReproducerCondStack,
134106c3fb27SDimitry Andric                            DFSInStack);
1342e8d8bef9SDimitry Andric     }
1343e8d8bef9SDimitry Andric 
134406c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "Processing ");
1345e8d8bef9SDimitry Andric 
1346e8d8bef9SDimitry Andric     // For a block, check if any CmpInsts become known based on the current set
1347e8d8bef9SDimitry Andric     // of constraints.
134806c3fb27SDimitry Andric     if (CB.isCheck()) {
134906c3fb27SDimitry Andric       Instruction *Inst = CB.getInstructionToSimplify();
135006c3fb27SDimitry Andric       if (!Inst)
135106c3fb27SDimitry Andric         continue;
135206c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "condition to simplify: " << *Inst << "\n");
135306c3fb27SDimitry Andric       if (auto *II = dyn_cast<WithOverflowInst>(Inst)) {
1354bdd1243dSDimitry Andric         Changed |= tryToSimplifyOverflowMath(II, Info, ToRemove);
135506c3fb27SDimitry Andric       } else if (auto *Cmp = dyn_cast<ICmpInst>(Inst)) {
135606c3fb27SDimitry Andric         bool Simplified = checkAndReplaceCondition(
135706c3fb27SDimitry Andric             Cmp, Info, CB.NumIn, CB.NumOut, CB.getContextInst(),
135806c3fb27SDimitry Andric             ReproducerModule.get(), ReproducerCondStack, S.DT);
135906c3fb27SDimitry Andric         if (!Simplified && match(CB.getContextInst(),
136006c3fb27SDimitry Andric                                  m_LogicalAnd(m_Value(), m_Specific(Inst)))) {
136106c3fb27SDimitry Andric           Simplified =
136206c3fb27SDimitry Andric               checkAndSecondOpImpliedByFirst(CB, Info, ReproducerModule.get(),
136306c3fb27SDimitry Andric                                              ReproducerCondStack, DFSInStack);
136406c3fb27SDimitry Andric         }
136506c3fb27SDimitry Andric         Changed |= Simplified;
1366e8d8bef9SDimitry Andric       }
1367e8d8bef9SDimitry Andric       continue;
1368e8d8bef9SDimitry Andric     }
1369e8d8bef9SDimitry Andric 
137006c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "fact to add to the system: " << *CB.Inst << "\n");
137106c3fb27SDimitry Andric     auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) {
1372bdd1243dSDimitry Andric       if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) {
1373bdd1243dSDimitry Andric         LLVM_DEBUG(
1374bdd1243dSDimitry Andric             dbgs()
1375bdd1243dSDimitry Andric             << "Skip adding constraint because system has too many rows.\n");
137606c3fb27SDimitry Andric         return;
137706c3fb27SDimitry Andric       }
137806c3fb27SDimitry Andric 
137906c3fb27SDimitry Andric       Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
138006c3fb27SDimitry Andric       if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size())
138106c3fb27SDimitry Andric         ReproducerCondStack.emplace_back(Pred, A, B);
138206c3fb27SDimitry Andric 
138306c3fb27SDimitry Andric       Info.transferToOtherSystem(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
138406c3fb27SDimitry Andric       if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) {
138506c3fb27SDimitry Andric         // Add dummy entries to ReproducerCondStack to keep it in sync with
138606c3fb27SDimitry Andric         // DFSInStack.
138706c3fb27SDimitry Andric         for (unsigned I = 0,
138806c3fb27SDimitry Andric                       E = (DFSInStack.size() - ReproducerCondStack.size());
138906c3fb27SDimitry Andric              I < E; ++I) {
139006c3fb27SDimitry Andric           ReproducerCondStack.emplace_back(ICmpInst::BAD_ICMP_PREDICATE,
139106c3fb27SDimitry Andric                                            nullptr, nullptr);
139206c3fb27SDimitry Andric         }
139306c3fb27SDimitry Andric       }
139406c3fb27SDimitry Andric     };
139506c3fb27SDimitry Andric 
139606c3fb27SDimitry Andric     ICmpInst::Predicate Pred;
139706c3fb27SDimitry Andric     if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {
139806c3fb27SDimitry Andric       Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
139906c3fb27SDimitry Andric       AddFact(Pred, MinMax, MinMax->getLHS());
140006c3fb27SDimitry Andric       AddFact(Pred, MinMax, MinMax->getRHS());
1401bdd1243dSDimitry Andric       continue;
1402bdd1243dSDimitry Andric     }
1403bdd1243dSDimitry Andric 
140406c3fb27SDimitry Andric     Value *A, *B;
140506c3fb27SDimitry Andric     Value *Cmp = CB.Inst;
140606c3fb27SDimitry Andric     match(Cmp, m_Intrinsic<Intrinsic::assume>(m_Value(Cmp)));
140706c3fb27SDimitry Andric     if (match(Cmp, m_ICmp(Pred, m_Value(A), m_Value(B)))) {
1408bdd1243dSDimitry Andric       // Use the inverse predicate if required.
1409bdd1243dSDimitry Andric       if (CB.Not)
1410bdd1243dSDimitry Andric         Pred = CmpInst::getInversePredicate(Pred);
1411bdd1243dSDimitry Andric 
141206c3fb27SDimitry Andric       AddFact(Pred, A, B);
1413e8d8bef9SDimitry Andric     }
1414fe6060f1SDimitry Andric   }
1415e8d8bef9SDimitry Andric 
141606c3fb27SDimitry Andric   if (ReproducerModule && !ReproducerModule->functions().empty()) {
141706c3fb27SDimitry Andric     std::string S;
141806c3fb27SDimitry Andric     raw_string_ostream StringS(S);
141906c3fb27SDimitry Andric     ReproducerModule->print(StringS, nullptr);
142006c3fb27SDimitry Andric     StringS.flush();
142106c3fb27SDimitry Andric     OptimizationRemark Rem(DEBUG_TYPE, "Reproducer", &F);
142206c3fb27SDimitry Andric     Rem << ore::NV("module") << S;
142306c3fb27SDimitry Andric     ORE.emit(Rem);
142406c3fb27SDimitry Andric   }
142506c3fb27SDimitry Andric 
142681ad6265SDimitry Andric #ifndef NDEBUG
142781ad6265SDimitry Andric   unsigned SignedEntries =
142881ad6265SDimitry Andric       count_if(DFSInStack, [](const StackEntry &E) { return E.IsSigned; });
142981ad6265SDimitry Andric   assert(Info.getCS(false).size() == DFSInStack.size() - SignedEntries &&
1430fe6060f1SDimitry Andric          "updates to CS and DFSInStack are out of sync");
143181ad6265SDimitry Andric   assert(Info.getCS(true).size() == SignedEntries &&
143281ad6265SDimitry Andric          "updates to CS and DFSInStack are out of sync");
143381ad6265SDimitry Andric #endif
143481ad6265SDimitry Andric 
143581ad6265SDimitry Andric   for (Instruction *I : ToRemove)
143681ad6265SDimitry Andric     I->eraseFromParent();
1437e8d8bef9SDimitry Andric   return Changed;
1438e8d8bef9SDimitry Andric }
1439e8d8bef9SDimitry Andric 
1440e8d8bef9SDimitry Andric PreservedAnalyses ConstraintEliminationPass::run(Function &F,
1441e8d8bef9SDimitry Andric                                                  FunctionAnalysisManager &AM) {
1442e8d8bef9SDimitry Andric   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
144306c3fb27SDimitry Andric   auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
144406c3fb27SDimitry Andric   if (!eliminateConstraints(F, DT, ORE))
1445e8d8bef9SDimitry Andric     return PreservedAnalyses::all();
1446e8d8bef9SDimitry Andric 
1447e8d8bef9SDimitry Andric   PreservedAnalyses PA;
1448e8d8bef9SDimitry Andric   PA.preserve<DominatorTreeAnalysis>();
1449e8d8bef9SDimitry Andric   PA.preserveSet<CFGAnalyses>();
1450e8d8bef9SDimitry Andric   return PA;
1451e8d8bef9SDimitry Andric }
1452