xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp (revision b121cb0095c8c1a060f66a8c4b118a54ebaa2551)
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 
415*b121cb00SDimitry Andric   Type *Ty = V->getType()->getScalarType();
416*b121cb00SDimitry Andric   if (Ty->isPointerTy() && !IsSigned) {
417*b121cb00SDimitry Andric     if (auto *GEP = dyn_cast<GEPOperator>(V))
418*b121cb00SDimitry Andric       return decomposeGEP(*GEP, Preconditions, IsSigned, DL);
419*b121cb00SDimitry Andric     return V;
420*b121cb00SDimitry Andric   }
421*b121cb00SDimitry Andric 
422*b121cb00SDimitry Andric   // Don't handle integers > 64 bit. Our coefficients are 64-bit large, so
423*b121cb00SDimitry Andric   // coefficient add/mul may wrap, while the operation in the full bit width
424*b121cb00SDimitry Andric   // would not.
425*b121cb00SDimitry Andric   if (!Ty->isIntegerTy() || Ty->getIntegerBitWidth() > 64)
426*b121cb00SDimitry Andric     return V;
427*b121cb00SDimitry Andric 
42881ad6265SDimitry Andric   // Decompose \p V used with a signed predicate.
42981ad6265SDimitry Andric   if (IsSigned) {
430e8d8bef9SDimitry Andric     if (auto *CI = dyn_cast<ConstantInt>(V)) {
431bdd1243dSDimitry Andric       if (canUseSExt(CI))
432bdd1243dSDimitry Andric         return CI->getSExtValue();
433e8d8bef9SDimitry Andric     }
434bdd1243dSDimitry Andric     Value *Op0;
435bdd1243dSDimitry Andric     Value *Op1;
436bdd1243dSDimitry Andric     if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1))))
437bdd1243dSDimitry Andric       return MergeResults(Op0, Op1, IsSigned);
43881ad6265SDimitry Andric 
43906c3fb27SDimitry Andric     ConstantInt *CI;
4408a4dda33SDimitry Andric     if (match(V, m_NSWMul(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI)) {
44106c3fb27SDimitry Andric       auto Result = decompose(Op0, Preconditions, IsSigned, DL);
44206c3fb27SDimitry Andric       Result.mul(CI->getSExtValue());
44306c3fb27SDimitry Andric       return Result;
44406c3fb27SDimitry Andric     }
44506c3fb27SDimitry Andric 
446bdd1243dSDimitry Andric     return V;
44781ad6265SDimitry Andric   }
44881ad6265SDimitry Andric 
44981ad6265SDimitry Andric   if (auto *CI = dyn_cast<ConstantInt>(V)) {
45081ad6265SDimitry Andric     if (CI->uge(MaxConstraintValue))
451bdd1243dSDimitry Andric       return V;
452bdd1243dSDimitry Andric     return int64_t(CI->getZExtValue());
453fe6060f1SDimitry Andric   }
454fe6060f1SDimitry Andric 
455e8d8bef9SDimitry Andric   Value *Op0;
456bdd1243dSDimitry Andric   bool IsKnownNonNegative = false;
457bdd1243dSDimitry Andric   if (match(V, m_ZExt(m_Value(Op0)))) {
458bdd1243dSDimitry Andric     IsKnownNonNegative = true;
459fe6060f1SDimitry Andric     V = Op0;
460bdd1243dSDimitry Andric   }
461fe6060f1SDimitry Andric 
462e8d8bef9SDimitry Andric   Value *Op1;
463e8d8bef9SDimitry Andric   ConstantInt *CI;
464bdd1243dSDimitry Andric   if (match(V, m_NUWAdd(m_Value(Op0), m_Value(Op1)))) {
465bdd1243dSDimitry Andric     return MergeResults(Op0, Op1, IsSigned);
466bdd1243dSDimitry Andric   }
467bdd1243dSDimitry Andric   if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) {
468bdd1243dSDimitry Andric     if (!isKnownNonNegative(Op0, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
469bdd1243dSDimitry Andric       Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,
470bdd1243dSDimitry Andric                                  ConstantInt::get(Op0->getType(), 0));
471bdd1243dSDimitry Andric     if (!isKnownNonNegative(Op1, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
472bdd1243dSDimitry Andric       Preconditions.emplace_back(CmpInst::ICMP_SGE, Op1,
473bdd1243dSDimitry Andric                                  ConstantInt::get(Op1->getType(), 0));
474bdd1243dSDimitry Andric 
475bdd1243dSDimitry Andric     return MergeResults(Op0, Op1, IsSigned);
476bdd1243dSDimitry Andric   }
477bdd1243dSDimitry Andric 
47881ad6265SDimitry Andric   if (match(V, m_Add(m_Value(Op0), m_ConstantInt(CI))) && CI->isNegative() &&
479bdd1243dSDimitry Andric       canUseSExt(CI)) {
48081ad6265SDimitry Andric     Preconditions.emplace_back(
48181ad6265SDimitry Andric         CmpInst::ICMP_UGE, Op0,
48281ad6265SDimitry Andric         ConstantInt::get(Op0->getType(), CI->getSExtValue() * -1));
483bdd1243dSDimitry Andric     return MergeResults(Op0, CI, true);
48481ad6265SDimitry Andric   }
485e8d8bef9SDimitry Andric 
48606c3fb27SDimitry Andric   // Decompose or as an add if there are no common bits between the operands.
48706c3fb27SDimitry Andric   if (match(V, m_Or(m_Value(Op0), m_ConstantInt(CI))) &&
48806c3fb27SDimitry Andric       haveNoCommonBitsSet(Op0, CI, DL)) {
48906c3fb27SDimitry Andric     return MergeResults(Op0, CI, IsSigned);
49006c3fb27SDimitry Andric   }
49106c3fb27SDimitry Andric 
492bdd1243dSDimitry Andric   if (match(V, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI)) {
49306c3fb27SDimitry Andric     if (CI->getSExtValue() < 0 || CI->getSExtValue() >= 64)
49406c3fb27SDimitry Andric       return {V, IsKnownNonNegative};
495bdd1243dSDimitry Andric     auto Result = decompose(Op1, Preconditions, IsSigned, DL);
49606c3fb27SDimitry Andric     Result.mul(int64_t{1} << CI->getSExtValue());
497bdd1243dSDimitry Andric     return Result;
498bdd1243dSDimitry Andric   }
499bdd1243dSDimitry Andric 
500bdd1243dSDimitry Andric   if (match(V, m_NUWMul(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI) &&
501bdd1243dSDimitry Andric       (!CI->isNegative())) {
502bdd1243dSDimitry Andric     auto Result = decompose(Op1, Preconditions, IsSigned, DL);
503bdd1243dSDimitry Andric     Result.mul(CI->getSExtValue());
504bdd1243dSDimitry Andric     return Result;
505bdd1243dSDimitry Andric   }
506bdd1243dSDimitry Andric 
507bdd1243dSDimitry Andric   if (match(V, m_NUWSub(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI))
508bdd1243dSDimitry Andric     return {-1 * CI->getSExtValue(), {{1, Op0}}};
509e8d8bef9SDimitry Andric   if (match(V, m_NUWSub(m_Value(Op0), m_Value(Op1))))
510bdd1243dSDimitry Andric     return {0, {{1, Op0}, {-1, Op1}}};
511e8d8bef9SDimitry Andric 
512bdd1243dSDimitry Andric   return {V, IsKnownNonNegative};
513e8d8bef9SDimitry Andric }
514e8d8bef9SDimitry Andric 
51581ad6265SDimitry Andric ConstraintTy
51681ad6265SDimitry Andric ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
517bdd1243dSDimitry Andric                               SmallVectorImpl<Value *> &NewVariables) const {
518bdd1243dSDimitry Andric   assert(NewVariables.empty() && "NewVariables must be empty when passed in");
51981ad6265SDimitry Andric   bool IsEq = false;
52006c3fb27SDimitry Andric   bool IsNe = false;
52106c3fb27SDimitry Andric 
52281ad6265SDimitry Andric   // Try to convert Pred to one of ULE/SLT/SLE/SLT.
52381ad6265SDimitry Andric   switch (Pred) {
52481ad6265SDimitry Andric   case CmpInst::ICMP_UGT:
52581ad6265SDimitry Andric   case CmpInst::ICMP_UGE:
52681ad6265SDimitry Andric   case CmpInst::ICMP_SGT:
52781ad6265SDimitry Andric   case CmpInst::ICMP_SGE: {
52881ad6265SDimitry Andric     Pred = CmpInst::getSwappedPredicate(Pred);
52981ad6265SDimitry Andric     std::swap(Op0, Op1);
53081ad6265SDimitry Andric     break;
53181ad6265SDimitry Andric   }
53281ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
53381ad6265SDimitry Andric     if (match(Op1, m_Zero())) {
53481ad6265SDimitry Andric       Pred = CmpInst::ICMP_ULE;
53581ad6265SDimitry Andric     } else {
53681ad6265SDimitry Andric       IsEq = true;
53781ad6265SDimitry Andric       Pred = CmpInst::ICMP_ULE;
53881ad6265SDimitry Andric     }
53981ad6265SDimitry Andric     break;
54081ad6265SDimitry Andric   case CmpInst::ICMP_NE:
54106c3fb27SDimitry Andric     if (match(Op1, m_Zero())) {
54281ad6265SDimitry Andric       Pred = CmpInst::getSwappedPredicate(CmpInst::ICMP_UGT);
54381ad6265SDimitry Andric       std::swap(Op0, Op1);
54406c3fb27SDimitry Andric     } else {
54506c3fb27SDimitry Andric       IsNe = true;
54606c3fb27SDimitry Andric       Pred = CmpInst::ICMP_ULE;
54706c3fb27SDimitry Andric     }
54881ad6265SDimitry Andric     break;
54981ad6265SDimitry Andric   default:
55081ad6265SDimitry Andric     break;
55181ad6265SDimitry Andric   }
55281ad6265SDimitry Andric 
55381ad6265SDimitry Andric   if (Pred != CmpInst::ICMP_ULE && Pred != CmpInst::ICMP_ULT &&
55481ad6265SDimitry Andric       Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SLT)
55581ad6265SDimitry Andric     return {};
55681ad6265SDimitry Andric 
55781ad6265SDimitry Andric   SmallVector<PreconditionTy, 4> Preconditions;
55881ad6265SDimitry Andric   bool IsSigned = CmpInst::isSigned(Pred);
55981ad6265SDimitry Andric   auto &Value2Index = getValue2Index(IsSigned);
56081ad6265SDimitry Andric   auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(),
561bdd1243dSDimitry Andric                         Preconditions, IsSigned, DL);
56281ad6265SDimitry Andric   auto BDec = decompose(Op1->stripPointerCastsSameRepresentation(),
563bdd1243dSDimitry Andric                         Preconditions, IsSigned, DL);
564bdd1243dSDimitry Andric   int64_t Offset1 = ADec.Offset;
565bdd1243dSDimitry Andric   int64_t Offset2 = BDec.Offset;
56681ad6265SDimitry Andric   Offset1 *= -1;
56781ad6265SDimitry Andric 
568bdd1243dSDimitry Andric   auto &VariablesA = ADec.Vars;
569bdd1243dSDimitry Andric   auto &VariablesB = BDec.Vars;
570e8d8bef9SDimitry Andric 
571bdd1243dSDimitry Andric   // First try to look up \p V in Value2Index and NewVariables. Otherwise add a
572bdd1243dSDimitry Andric   // new entry to NewVariables.
573bdd1243dSDimitry Andric   DenseMap<Value *, unsigned> NewIndexMap;
574bdd1243dSDimitry Andric   auto GetOrAddIndex = [&Value2Index, &NewVariables,
575bdd1243dSDimitry Andric                         &NewIndexMap](Value *V) -> unsigned {
576fe6060f1SDimitry Andric     auto V2I = Value2Index.find(V);
577fe6060f1SDimitry Andric     if (V2I != Value2Index.end())
578fe6060f1SDimitry Andric       return V2I->second;
579fe6060f1SDimitry Andric     auto Insert =
580bdd1243dSDimitry Andric         NewIndexMap.insert({V, Value2Index.size() + NewVariables.size() + 1});
581bdd1243dSDimitry Andric     if (Insert.second)
582bdd1243dSDimitry Andric       NewVariables.push_back(V);
583fe6060f1SDimitry Andric     return Insert.first->second;
584e8d8bef9SDimitry Andric   };
585e8d8bef9SDimitry Andric 
586bdd1243dSDimitry Andric   // Make sure all variables have entries in Value2Index or NewVariables.
587bdd1243dSDimitry Andric   for (const auto &KV : concat<DecompEntry>(VariablesA, VariablesB))
588bdd1243dSDimitry Andric     GetOrAddIndex(KV.Variable);
589e8d8bef9SDimitry Andric 
590e8d8bef9SDimitry Andric   // Build result constraint, by first adding all coefficients from A and then
591e8d8bef9SDimitry Andric   // subtracting all coefficients from B.
59281ad6265SDimitry Andric   ConstraintTy Res(
593bdd1243dSDimitry Andric       SmallVector<int64_t, 8>(Value2Index.size() + NewVariables.size() + 1, 0),
59406c3fb27SDimitry Andric       IsSigned, IsEq, IsNe);
595bdd1243dSDimitry Andric   // Collect variables that are known to be positive in all uses in the
596bdd1243dSDimitry Andric   // constraint.
597bdd1243dSDimitry Andric   DenseMap<Value *, bool> KnownNonNegativeVariables;
59881ad6265SDimitry Andric   auto &R = Res.Coefficients;
599bdd1243dSDimitry Andric   for (const auto &KV : VariablesA) {
600bdd1243dSDimitry Andric     R[GetOrAddIndex(KV.Variable)] += KV.Coefficient;
601bdd1243dSDimitry Andric     auto I =
602bdd1243dSDimitry Andric         KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative});
603bdd1243dSDimitry Andric     I.first->second &= KV.IsKnownNonNegative;
604bdd1243dSDimitry Andric   }
605e8d8bef9SDimitry Andric 
606bdd1243dSDimitry Andric   for (const auto &KV : VariablesB) {
60706c3fb27SDimitry Andric     if (SubOverflow(R[GetOrAddIndex(KV.Variable)], KV.Coefficient,
60806c3fb27SDimitry Andric                     R[GetOrAddIndex(KV.Variable)]))
60906c3fb27SDimitry Andric       return {};
610bdd1243dSDimitry Andric     auto I =
611bdd1243dSDimitry Andric         KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative});
612bdd1243dSDimitry Andric     I.first->second &= KV.IsKnownNonNegative;
613bdd1243dSDimitry Andric   }
614e8d8bef9SDimitry Andric 
61581ad6265SDimitry Andric   int64_t OffsetSum;
61681ad6265SDimitry Andric   if (AddOverflow(Offset1, Offset2, OffsetSum))
61781ad6265SDimitry Andric     return {};
61881ad6265SDimitry Andric   if (Pred == (IsSigned ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT))
61981ad6265SDimitry Andric     if (AddOverflow(OffsetSum, int64_t(-1), OffsetSum))
62081ad6265SDimitry Andric       return {};
62181ad6265SDimitry Andric   R[0] = OffsetSum;
62281ad6265SDimitry Andric   Res.Preconditions = std::move(Preconditions);
623bdd1243dSDimitry Andric 
624bdd1243dSDimitry Andric   // Remove any (Coefficient, Variable) entry where the Coefficient is 0 for new
625bdd1243dSDimitry Andric   // variables.
626bdd1243dSDimitry Andric   while (!NewVariables.empty()) {
627bdd1243dSDimitry Andric     int64_t Last = R.back();
628bdd1243dSDimitry Andric     if (Last != 0)
629bdd1243dSDimitry Andric       break;
630bdd1243dSDimitry Andric     R.pop_back();
631bdd1243dSDimitry Andric     Value *RemovedV = NewVariables.pop_back_val();
632bdd1243dSDimitry Andric     NewIndexMap.erase(RemovedV);
633bdd1243dSDimitry Andric   }
634bdd1243dSDimitry Andric 
635bdd1243dSDimitry Andric   // Add extra constraints for variables that are known positive.
636bdd1243dSDimitry Andric   for (auto &KV : KnownNonNegativeVariables) {
63706c3fb27SDimitry Andric     if (!KV.second ||
63806c3fb27SDimitry Andric         (!Value2Index.contains(KV.first) && !NewIndexMap.contains(KV.first)))
639bdd1243dSDimitry Andric       continue;
640bdd1243dSDimitry Andric     SmallVector<int64_t, 8> C(Value2Index.size() + NewVariables.size() + 1, 0);
641bdd1243dSDimitry Andric     C[GetOrAddIndex(KV.first)] = -1;
642bdd1243dSDimitry Andric     Res.ExtraInfo.push_back(C);
643bdd1243dSDimitry Andric   }
64481ad6265SDimitry Andric   return Res;
645e8d8bef9SDimitry Andric }
646e8d8bef9SDimitry Andric 
647bdd1243dSDimitry Andric ConstraintTy ConstraintInfo::getConstraintForSolving(CmpInst::Predicate Pred,
648bdd1243dSDimitry Andric                                                      Value *Op0,
649bdd1243dSDimitry Andric                                                      Value *Op1) const {
650bdd1243dSDimitry Andric   // If both operands are known to be non-negative, change signed predicates to
651bdd1243dSDimitry Andric   // unsigned ones. This increases the reasoning effectiveness in combination
652bdd1243dSDimitry Andric   // with the signed <-> unsigned transfer logic.
653bdd1243dSDimitry Andric   if (CmpInst::isSigned(Pred) &&
654bdd1243dSDimitry Andric       isKnownNonNegative(Op0, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1) &&
655bdd1243dSDimitry Andric       isKnownNonNegative(Op1, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
656bdd1243dSDimitry Andric     Pred = CmpInst::getUnsignedPredicate(Pred);
657bdd1243dSDimitry Andric 
658bdd1243dSDimitry Andric   SmallVector<Value *> NewVariables;
659bdd1243dSDimitry Andric   ConstraintTy R = getConstraint(Pred, Op0, Op1, NewVariables);
66006c3fb27SDimitry Andric   if (!NewVariables.empty())
661bdd1243dSDimitry Andric     return {};
662bdd1243dSDimitry Andric   return R;
663bdd1243dSDimitry Andric }
664bdd1243dSDimitry Andric 
66581ad6265SDimitry Andric bool ConstraintTy::isValid(const ConstraintInfo &Info) const {
66681ad6265SDimitry Andric   return Coefficients.size() > 0 &&
66781ad6265SDimitry Andric          all_of(Preconditions, [&Info](const PreconditionTy &C) {
66881ad6265SDimitry Andric            return Info.doesHold(C.Pred, C.Op0, C.Op1);
66981ad6265SDimitry Andric          });
67081ad6265SDimitry Andric }
67181ad6265SDimitry Andric 
67206c3fb27SDimitry Andric std::optional<bool>
67306c3fb27SDimitry Andric ConstraintTy::isImpliedBy(const ConstraintSystem &CS) const {
67406c3fb27SDimitry Andric   bool IsConditionImplied = CS.isConditionImplied(Coefficients);
67506c3fb27SDimitry Andric 
67606c3fb27SDimitry Andric   if (IsEq || IsNe) {
67706c3fb27SDimitry Andric     auto NegatedOrEqual = ConstraintSystem::negateOrEqual(Coefficients);
67806c3fb27SDimitry Andric     bool IsNegatedOrEqualImplied =
67906c3fb27SDimitry Andric         !NegatedOrEqual.empty() && CS.isConditionImplied(NegatedOrEqual);
68006c3fb27SDimitry Andric 
68106c3fb27SDimitry Andric     // In order to check that `%a == %b` is true (equality), both conditions `%a
68206c3fb27SDimitry Andric     // >= %b` and `%a <= %b` must hold true. When checking for equality (`IsEq`
68306c3fb27SDimitry Andric     // is true), we return true if they both hold, false in the other cases.
68406c3fb27SDimitry Andric     if (IsConditionImplied && IsNegatedOrEqualImplied)
68506c3fb27SDimitry Andric       return IsEq;
68606c3fb27SDimitry Andric 
68706c3fb27SDimitry Andric     auto Negated = ConstraintSystem::negate(Coefficients);
68806c3fb27SDimitry Andric     bool IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated);
68906c3fb27SDimitry Andric 
69006c3fb27SDimitry Andric     auto StrictLessThan = ConstraintSystem::toStrictLessThan(Coefficients);
69106c3fb27SDimitry Andric     bool IsStrictLessThanImplied =
69206c3fb27SDimitry Andric         !StrictLessThan.empty() && CS.isConditionImplied(StrictLessThan);
69306c3fb27SDimitry Andric 
69406c3fb27SDimitry Andric     // In order to check that `%a != %b` is true (non-equality), either
69506c3fb27SDimitry Andric     // condition `%a > %b` or `%a < %b` must hold true. When checking for
69606c3fb27SDimitry Andric     // non-equality (`IsNe` is true), we return true if one of the two holds,
69706c3fb27SDimitry Andric     // false in the other cases.
69806c3fb27SDimitry Andric     if (IsNegatedImplied || IsStrictLessThanImplied)
69906c3fb27SDimitry Andric       return IsNe;
70006c3fb27SDimitry Andric 
70106c3fb27SDimitry Andric     return std::nullopt;
70206c3fb27SDimitry Andric   }
70306c3fb27SDimitry Andric 
70406c3fb27SDimitry Andric   if (IsConditionImplied)
70506c3fb27SDimitry Andric     return true;
70606c3fb27SDimitry Andric 
70706c3fb27SDimitry Andric   auto Negated = ConstraintSystem::negate(Coefficients);
70806c3fb27SDimitry Andric   auto IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated);
70906c3fb27SDimitry Andric   if (IsNegatedImplied)
71006c3fb27SDimitry Andric     return false;
71106c3fb27SDimitry Andric 
71206c3fb27SDimitry Andric   // Neither the condition nor its negated holds, did not prove anything.
71306c3fb27SDimitry Andric   return std::nullopt;
71406c3fb27SDimitry Andric }
71506c3fb27SDimitry Andric 
71681ad6265SDimitry Andric bool ConstraintInfo::doesHold(CmpInst::Predicate Pred, Value *A,
71781ad6265SDimitry Andric                               Value *B) const {
718bdd1243dSDimitry Andric   auto R = getConstraintForSolving(Pred, A, B);
71906c3fb27SDimitry Andric   return R.isValid(*this) &&
720bdd1243dSDimitry Andric          getCS(R.IsSigned).isConditionImplied(R.Coefficients);
72181ad6265SDimitry Andric }
72281ad6265SDimitry Andric 
72381ad6265SDimitry Andric void ConstraintInfo::transferToOtherSystem(
724bdd1243dSDimitry Andric     CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn,
72581ad6265SDimitry Andric     unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack) {
72681ad6265SDimitry Andric   // Check if we can combine facts from the signed and unsigned systems to
72781ad6265SDimitry Andric   // derive additional facts.
72881ad6265SDimitry Andric   if (!A->getType()->isIntegerTy())
72981ad6265SDimitry Andric     return;
73081ad6265SDimitry Andric   // FIXME: This currently depends on the order we add facts. Ideally we
73181ad6265SDimitry Andric   // would first add all known facts and only then try to add additional
73281ad6265SDimitry Andric   // facts.
73381ad6265SDimitry Andric   switch (Pred) {
73481ad6265SDimitry Andric   default:
73581ad6265SDimitry Andric     break;
73681ad6265SDimitry Andric   case CmpInst::ICMP_ULT:
73781ad6265SDimitry Andric     //  If B is a signed positive constant, A >=s 0 and A <s B.
73881ad6265SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0))) {
739bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_SGE, A, ConstantInt::get(B->getType(), 0), NumIn,
740bdd1243dSDimitry Andric               NumOut, DFSInStack);
741bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_SLT, A, B, NumIn, NumOut, DFSInStack);
74281ad6265SDimitry Andric     }
74381ad6265SDimitry Andric     break;
74481ad6265SDimitry Andric   case CmpInst::ICMP_SLT:
74581ad6265SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, A, ConstantInt::get(B->getType(), 0)))
746bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_ULT, A, B, NumIn, NumOut, DFSInStack);
74781ad6265SDimitry Andric     break;
74806c3fb27SDimitry Andric   case CmpInst::ICMP_SGT: {
74981ad6265SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), -1)))
750bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_UGE, A, ConstantInt::get(B->getType(), 0), NumIn,
751bdd1243dSDimitry Andric               NumOut, DFSInStack);
75206c3fb27SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0)))
75306c3fb27SDimitry Andric       addFact(CmpInst::ICMP_UGT, A, B, NumIn, NumOut, DFSInStack);
75406c3fb27SDimitry Andric 
75581ad6265SDimitry Andric     break;
75606c3fb27SDimitry Andric   }
75781ad6265SDimitry Andric   case CmpInst::ICMP_SGE:
75881ad6265SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0))) {
759bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_UGE, A, B, NumIn, NumOut, DFSInStack);
76081ad6265SDimitry Andric     }
76181ad6265SDimitry Andric     break;
76281ad6265SDimitry Andric   }
763e8d8bef9SDimitry Andric }
764e8d8bef9SDimitry Andric 
765fe6060f1SDimitry Andric #ifndef NDEBUG
76681ad6265SDimitry Andric 
76706c3fb27SDimitry Andric static void dumpConstraint(ArrayRef<int64_t> C,
76806c3fb27SDimitry Andric                            const DenseMap<Value *, unsigned> &Value2Index) {
76906c3fb27SDimitry Andric   ConstraintSystem CS(Value2Index);
77081ad6265SDimitry Andric   CS.addVariableRowFill(C);
77106c3fb27SDimitry Andric   CS.dump();
77281ad6265SDimitry Andric }
773fe6060f1SDimitry Andric #endif
774fe6060f1SDimitry Andric 
77581ad6265SDimitry Andric void State::addInfoFor(BasicBlock &BB) {
776349cc55cSDimitry Andric   // True as long as long as the current instruction is guaranteed to execute.
777349cc55cSDimitry Andric   bool GuaranteedToExecute = true;
778bdd1243dSDimitry Andric   // Queue conditions and assumes.
779349cc55cSDimitry Andric   for (Instruction &I : BB) {
780bdd1243dSDimitry Andric     if (auto Cmp = dyn_cast<ICmpInst>(&I)) {
78106c3fb27SDimitry Andric       for (Use &U : Cmp->uses()) {
78206c3fb27SDimitry Andric         auto *UserI = getContextInstForUse(U);
78306c3fb27SDimitry Andric         auto *DTN = DT.getNode(UserI->getParent());
78406c3fb27SDimitry Andric         if (!DTN)
78506c3fb27SDimitry Andric           continue;
78606c3fb27SDimitry Andric         WorkList.push_back(FactOrCheck::getCheck(DTN, &U));
78706c3fb27SDimitry Andric       }
788bdd1243dSDimitry Andric       continue;
789bdd1243dSDimitry Andric     }
790bdd1243dSDimitry Andric 
791bdd1243dSDimitry Andric     if (match(&I, m_Intrinsic<Intrinsic::ssub_with_overflow>())) {
79206c3fb27SDimitry Andric       WorkList.push_back(
79306c3fb27SDimitry Andric           FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));
79406c3fb27SDimitry Andric       continue;
79506c3fb27SDimitry Andric     }
79606c3fb27SDimitry Andric 
79706c3fb27SDimitry Andric     if (isa<MinMaxIntrinsic>(&I)) {
79806c3fb27SDimitry Andric       WorkList.push_back(FactOrCheck::getFact(DT.getNode(&BB), &I));
799bdd1243dSDimitry Andric       continue;
800bdd1243dSDimitry Andric     }
801bdd1243dSDimitry Andric 
802349cc55cSDimitry Andric     Value *Cond;
803349cc55cSDimitry Andric     // For now, just handle assumes with a single compare as condition.
804349cc55cSDimitry Andric     if (match(&I, m_Intrinsic<Intrinsic::assume>(m_Value(Cond))) &&
80581ad6265SDimitry Andric         isa<ICmpInst>(Cond)) {
806349cc55cSDimitry Andric       if (GuaranteedToExecute) {
807349cc55cSDimitry Andric         // The assume is guaranteed to execute when BB is entered, hence Cond
808349cc55cSDimitry Andric         // holds on entry to BB.
809bdd1243dSDimitry Andric         WorkList.emplace_back(FactOrCheck::getFact(DT.getNode(I.getParent()),
810bdd1243dSDimitry Andric                                                    cast<Instruction>(Cond)));
811349cc55cSDimitry Andric       } else {
812bdd1243dSDimitry Andric         WorkList.emplace_back(
813bdd1243dSDimitry Andric             FactOrCheck::getFact(DT.getNode(I.getParent()), &I));
814349cc55cSDimitry Andric       }
815349cc55cSDimitry Andric     }
816349cc55cSDimitry Andric     GuaranteedToExecute &= isGuaranteedToTransferExecutionToSuccessor(&I);
817349cc55cSDimitry Andric   }
818349cc55cSDimitry Andric 
819e8d8bef9SDimitry Andric   auto *Br = dyn_cast<BranchInst>(BB.getTerminator());
820e8d8bef9SDimitry Andric   if (!Br || !Br->isConditional())
82181ad6265SDimitry Andric     return;
822e8d8bef9SDimitry Andric 
823bdd1243dSDimitry Andric   Value *Cond = Br->getCondition();
824e8d8bef9SDimitry Andric 
825bdd1243dSDimitry Andric   // If the condition is a chain of ORs/AND and the successor only has the
826bdd1243dSDimitry Andric   // current block as predecessor, queue conditions for the successor.
827bdd1243dSDimitry Andric   Value *Op0, *Op1;
828bdd1243dSDimitry Andric   if (match(Cond, m_LogicalOr(m_Value(Op0), m_Value(Op1))) ||
829bdd1243dSDimitry Andric       match(Cond, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {
830bdd1243dSDimitry Andric     bool IsOr = match(Cond, m_LogicalOr());
831bdd1243dSDimitry Andric     bool IsAnd = match(Cond, m_LogicalAnd());
832bdd1243dSDimitry Andric     // If there's a select that matches both AND and OR, we need to commit to
833bdd1243dSDimitry Andric     // one of the options. Arbitrarily pick OR.
834bdd1243dSDimitry Andric     if (IsOr && IsAnd)
835bdd1243dSDimitry Andric       IsAnd = false;
836bdd1243dSDimitry Andric 
837bdd1243dSDimitry Andric     BasicBlock *Successor = Br->getSuccessor(IsOr ? 1 : 0);
838bdd1243dSDimitry Andric     if (canAddSuccessor(BB, Successor)) {
839bdd1243dSDimitry Andric       SmallVector<Value *> CondWorkList;
840bdd1243dSDimitry Andric       SmallPtrSet<Value *, 8> SeenCond;
841bdd1243dSDimitry Andric       auto QueueValue = [&CondWorkList, &SeenCond](Value *V) {
842bdd1243dSDimitry Andric         if (SeenCond.insert(V).second)
843bdd1243dSDimitry Andric           CondWorkList.push_back(V);
844bdd1243dSDimitry Andric       };
845bdd1243dSDimitry Andric       QueueValue(Op1);
846bdd1243dSDimitry Andric       QueueValue(Op0);
847bdd1243dSDimitry Andric       while (!CondWorkList.empty()) {
848bdd1243dSDimitry Andric         Value *Cur = CondWorkList.pop_back_val();
849bdd1243dSDimitry Andric         if (auto *Cmp = dyn_cast<ICmpInst>(Cur)) {
850bdd1243dSDimitry Andric           WorkList.emplace_back(
851bdd1243dSDimitry Andric               FactOrCheck::getFact(DT.getNode(Successor), Cmp, IsOr));
852bdd1243dSDimitry Andric           continue;
853bdd1243dSDimitry Andric         }
854bdd1243dSDimitry Andric         if (IsOr && match(Cur, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) {
855bdd1243dSDimitry Andric           QueueValue(Op1);
856bdd1243dSDimitry Andric           QueueValue(Op0);
857bdd1243dSDimitry Andric           continue;
858bdd1243dSDimitry Andric         }
859bdd1243dSDimitry Andric         if (IsAnd && match(Cur, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {
860bdd1243dSDimitry Andric           QueueValue(Op1);
861bdd1243dSDimitry Andric           QueueValue(Op0);
862bdd1243dSDimitry Andric           continue;
863bdd1243dSDimitry Andric         }
864bdd1243dSDimitry Andric       }
865e8d8bef9SDimitry Andric     }
86681ad6265SDimitry Andric     return;
867e8d8bef9SDimitry Andric   }
868e8d8bef9SDimitry Andric 
86981ad6265SDimitry Andric   auto *CmpI = dyn_cast<ICmpInst>(Br->getCondition());
870e8d8bef9SDimitry Andric   if (!CmpI)
87181ad6265SDimitry Andric     return;
87281ad6265SDimitry Andric   if (canAddSuccessor(BB, Br->getSuccessor(0)))
873bdd1243dSDimitry Andric     WorkList.emplace_back(
874bdd1243dSDimitry Andric         FactOrCheck::getFact(DT.getNode(Br->getSuccessor(0)), CmpI));
87581ad6265SDimitry Andric   if (canAddSuccessor(BB, Br->getSuccessor(1)))
876bdd1243dSDimitry Andric     WorkList.emplace_back(
877bdd1243dSDimitry Andric         FactOrCheck::getFact(DT.getNode(Br->getSuccessor(1)), CmpI, true));
878bdd1243dSDimitry Andric }
879bdd1243dSDimitry Andric 
88006c3fb27SDimitry Andric namespace {
88106c3fb27SDimitry Andric /// Helper to keep track of a condition and if it should be treated as negated
88206c3fb27SDimitry Andric /// for reproducer construction.
88306c3fb27SDimitry Andric /// Pred == Predicate::BAD_ICMP_PREDICATE indicates that this entry is a
88406c3fb27SDimitry Andric /// placeholder to keep the ReproducerCondStack in sync with DFSInStack.
88506c3fb27SDimitry Andric struct ReproducerEntry {
88606c3fb27SDimitry Andric   ICmpInst::Predicate Pred;
88706c3fb27SDimitry Andric   Value *LHS;
88806c3fb27SDimitry Andric   Value *RHS;
88906c3fb27SDimitry Andric 
89006c3fb27SDimitry Andric   ReproducerEntry(ICmpInst::Predicate Pred, Value *LHS, Value *RHS)
89106c3fb27SDimitry Andric       : Pred(Pred), LHS(LHS), RHS(RHS) {}
89206c3fb27SDimitry Andric };
89306c3fb27SDimitry Andric } // namespace
89406c3fb27SDimitry Andric 
89506c3fb27SDimitry Andric /// Helper function to generate a reproducer function for simplifying \p Cond.
89606c3fb27SDimitry Andric /// The reproducer function contains a series of @llvm.assume calls, one for
89706c3fb27SDimitry Andric /// each condition in \p Stack. For each condition, the operand instruction are
89806c3fb27SDimitry Andric /// cloned until we reach operands that have an entry in \p Value2Index. Those
89906c3fb27SDimitry Andric /// will then be added as function arguments. \p DT is used to order cloned
90006c3fb27SDimitry Andric /// instructions. The reproducer function will get added to \p M, if it is
90106c3fb27SDimitry Andric /// non-null. Otherwise no reproducer function is generated.
90206c3fb27SDimitry Andric static void generateReproducer(CmpInst *Cond, Module *M,
90306c3fb27SDimitry Andric                                ArrayRef<ReproducerEntry> Stack,
90406c3fb27SDimitry Andric                                ConstraintInfo &Info, DominatorTree &DT) {
90506c3fb27SDimitry Andric   if (!M)
90606c3fb27SDimitry Andric     return;
90706c3fb27SDimitry Andric 
90806c3fb27SDimitry Andric   LLVMContext &Ctx = Cond->getContext();
90906c3fb27SDimitry Andric 
91006c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "Creating reproducer for " << *Cond << "\n");
91106c3fb27SDimitry Andric 
91206c3fb27SDimitry Andric   ValueToValueMapTy Old2New;
91306c3fb27SDimitry Andric   SmallVector<Value *> Args;
91406c3fb27SDimitry Andric   SmallPtrSet<Value *, 8> Seen;
91506c3fb27SDimitry Andric   // Traverse Cond and its operands recursively until we reach a value that's in
91606c3fb27SDimitry Andric   // Value2Index or not an instruction, or not a operation that
91706c3fb27SDimitry Andric   // ConstraintElimination can decompose. Such values will be considered as
91806c3fb27SDimitry Andric   // external inputs to the reproducer, they are collected and added as function
91906c3fb27SDimitry Andric   // arguments later.
92006c3fb27SDimitry Andric   auto CollectArguments = [&](ArrayRef<Value *> Ops, bool IsSigned) {
92106c3fb27SDimitry Andric     auto &Value2Index = Info.getValue2Index(IsSigned);
92206c3fb27SDimitry Andric     SmallVector<Value *, 4> WorkList(Ops);
92306c3fb27SDimitry Andric     while (!WorkList.empty()) {
92406c3fb27SDimitry Andric       Value *V = WorkList.pop_back_val();
92506c3fb27SDimitry Andric       if (!Seen.insert(V).second)
92606c3fb27SDimitry Andric         continue;
92706c3fb27SDimitry Andric       if (Old2New.find(V) != Old2New.end())
92806c3fb27SDimitry Andric         continue;
92906c3fb27SDimitry Andric       if (isa<Constant>(V))
93006c3fb27SDimitry Andric         continue;
93106c3fb27SDimitry Andric 
93206c3fb27SDimitry Andric       auto *I = dyn_cast<Instruction>(V);
93306c3fb27SDimitry Andric       if (Value2Index.contains(V) || !I ||
93406c3fb27SDimitry Andric           !isa<CmpInst, BinaryOperator, GEPOperator, CastInst>(V)) {
93506c3fb27SDimitry Andric         Old2New[V] = V;
93606c3fb27SDimitry Andric         Args.push_back(V);
93706c3fb27SDimitry Andric         LLVM_DEBUG(dbgs() << "  found external input " << *V << "\n");
93806c3fb27SDimitry Andric       } else {
93906c3fb27SDimitry Andric         append_range(WorkList, I->operands());
94006c3fb27SDimitry Andric       }
94106c3fb27SDimitry Andric     }
94206c3fb27SDimitry Andric   };
94306c3fb27SDimitry Andric 
94406c3fb27SDimitry Andric   for (auto &Entry : Stack)
94506c3fb27SDimitry Andric     if (Entry.Pred != ICmpInst::BAD_ICMP_PREDICATE)
94606c3fb27SDimitry Andric       CollectArguments({Entry.LHS, Entry.RHS}, ICmpInst::isSigned(Entry.Pred));
94706c3fb27SDimitry Andric   CollectArguments(Cond, ICmpInst::isSigned(Cond->getPredicate()));
94806c3fb27SDimitry Andric 
94906c3fb27SDimitry Andric   SmallVector<Type *> ParamTys;
95006c3fb27SDimitry Andric   for (auto *P : Args)
95106c3fb27SDimitry Andric     ParamTys.push_back(P->getType());
95206c3fb27SDimitry Andric 
95306c3fb27SDimitry Andric   FunctionType *FTy = FunctionType::get(Cond->getType(), ParamTys,
95406c3fb27SDimitry Andric                                         /*isVarArg=*/false);
95506c3fb27SDimitry Andric   Function *F = Function::Create(FTy, Function::ExternalLinkage,
95606c3fb27SDimitry Andric                                  Cond->getModule()->getName() +
95706c3fb27SDimitry Andric                                      Cond->getFunction()->getName() + "repro",
95806c3fb27SDimitry Andric                                  M);
95906c3fb27SDimitry Andric   // Add arguments to the reproducer function for each external value collected.
96006c3fb27SDimitry Andric   for (unsigned I = 0; I < Args.size(); ++I) {
96106c3fb27SDimitry Andric     F->getArg(I)->setName(Args[I]->getName());
96206c3fb27SDimitry Andric     Old2New[Args[I]] = F->getArg(I);
96306c3fb27SDimitry Andric   }
96406c3fb27SDimitry Andric 
96506c3fb27SDimitry Andric   BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F);
96606c3fb27SDimitry Andric   IRBuilder<> Builder(Entry);
96706c3fb27SDimitry Andric   Builder.CreateRet(Builder.getTrue());
96806c3fb27SDimitry Andric   Builder.SetInsertPoint(Entry->getTerminator());
96906c3fb27SDimitry Andric 
97006c3fb27SDimitry Andric   // Clone instructions in \p Ops and their operands recursively until reaching
97106c3fb27SDimitry Andric   // an value in Value2Index (external input to the reproducer). Update Old2New
97206c3fb27SDimitry Andric   // mapping for the original and cloned instructions. Sort instructions to
97306c3fb27SDimitry Andric   // clone by dominance, then insert the cloned instructions in the function.
97406c3fb27SDimitry Andric   auto CloneInstructions = [&](ArrayRef<Value *> Ops, bool IsSigned) {
97506c3fb27SDimitry Andric     SmallVector<Value *, 4> WorkList(Ops);
97606c3fb27SDimitry Andric     SmallVector<Instruction *> ToClone;
97706c3fb27SDimitry Andric     auto &Value2Index = Info.getValue2Index(IsSigned);
97806c3fb27SDimitry Andric     while (!WorkList.empty()) {
97906c3fb27SDimitry Andric       Value *V = WorkList.pop_back_val();
98006c3fb27SDimitry Andric       if (Old2New.find(V) != Old2New.end())
98106c3fb27SDimitry Andric         continue;
98206c3fb27SDimitry Andric 
98306c3fb27SDimitry Andric       auto *I = dyn_cast<Instruction>(V);
98406c3fb27SDimitry Andric       if (!Value2Index.contains(V) && I) {
98506c3fb27SDimitry Andric         Old2New[V] = nullptr;
98606c3fb27SDimitry Andric         ToClone.push_back(I);
98706c3fb27SDimitry Andric         append_range(WorkList, I->operands());
98806c3fb27SDimitry Andric       }
98906c3fb27SDimitry Andric     }
99006c3fb27SDimitry Andric 
99106c3fb27SDimitry Andric     sort(ToClone,
99206c3fb27SDimitry Andric          [&DT](Instruction *A, Instruction *B) { return DT.dominates(A, B); });
99306c3fb27SDimitry Andric     for (Instruction *I : ToClone) {
99406c3fb27SDimitry Andric       Instruction *Cloned = I->clone();
99506c3fb27SDimitry Andric       Old2New[I] = Cloned;
99606c3fb27SDimitry Andric       Old2New[I]->setName(I->getName());
99706c3fb27SDimitry Andric       Cloned->insertBefore(&*Builder.GetInsertPoint());
99806c3fb27SDimitry Andric       Cloned->dropUnknownNonDebugMetadata();
99906c3fb27SDimitry Andric       Cloned->setDebugLoc({});
100006c3fb27SDimitry Andric     }
100106c3fb27SDimitry Andric   };
100206c3fb27SDimitry Andric 
100306c3fb27SDimitry Andric   // Materialize the assumptions for the reproducer using the entries in Stack.
100406c3fb27SDimitry Andric   // That is, first clone the operands of the condition recursively until we
100506c3fb27SDimitry Andric   // reach an external input to the reproducer and add them to the reproducer
100606c3fb27SDimitry Andric   // function. Then add an ICmp for the condition (with the inverse predicate if
100706c3fb27SDimitry Andric   // the entry is negated) and an assert using the ICmp.
100806c3fb27SDimitry Andric   for (auto &Entry : Stack) {
100906c3fb27SDimitry Andric     if (Entry.Pred == ICmpInst::BAD_ICMP_PREDICATE)
101006c3fb27SDimitry Andric       continue;
101106c3fb27SDimitry Andric 
101206c3fb27SDimitry Andric     LLVM_DEBUG(
101306c3fb27SDimitry Andric         dbgs() << "  Materializing assumption icmp " << Entry.Pred << ' ';
101406c3fb27SDimitry Andric         Entry.LHS->printAsOperand(dbgs(), /*PrintType=*/true); dbgs() << ", ";
101506c3fb27SDimitry Andric         Entry.RHS->printAsOperand(dbgs(), /*PrintType=*/false); dbgs() << "\n");
101606c3fb27SDimitry Andric     CloneInstructions({Entry.LHS, Entry.RHS}, CmpInst::isSigned(Entry.Pred));
101706c3fb27SDimitry Andric 
101806c3fb27SDimitry Andric     auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS);
101906c3fb27SDimitry Andric     Builder.CreateAssumption(Cmp);
102006c3fb27SDimitry Andric   }
102106c3fb27SDimitry Andric 
102206c3fb27SDimitry Andric   // Finally, clone the condition to reproduce and remap instruction operands in
102306c3fb27SDimitry Andric   // the reproducer using Old2New.
102406c3fb27SDimitry Andric   CloneInstructions(Cond, CmpInst::isSigned(Cond->getPredicate()));
102506c3fb27SDimitry Andric   Entry->getTerminator()->setOperand(0, Cond);
102606c3fb27SDimitry Andric   remapInstructionsInBlocks({Entry}, Old2New);
102706c3fb27SDimitry Andric 
102806c3fb27SDimitry Andric   assert(!verifyFunction(*F, &dbgs()));
102906c3fb27SDimitry Andric }
103006c3fb27SDimitry Andric 
103106c3fb27SDimitry Andric static std::optional<bool> checkCondition(CmpInst *Cmp, ConstraintInfo &Info,
103206c3fb27SDimitry Andric                                           unsigned NumIn, unsigned NumOut,
103306c3fb27SDimitry Andric                                           Instruction *ContextInst) {
1034bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "Checking " << *Cmp << "\n");
1035bdd1243dSDimitry Andric 
1036bdd1243dSDimitry Andric   CmpInst::Predicate Pred = Cmp->getPredicate();
1037bdd1243dSDimitry Andric   Value *A = Cmp->getOperand(0);
1038bdd1243dSDimitry Andric   Value *B = Cmp->getOperand(1);
1039bdd1243dSDimitry Andric 
1040bdd1243dSDimitry Andric   auto R = Info.getConstraintForSolving(Pred, A, B);
1041bdd1243dSDimitry Andric   if (R.empty() || !R.isValid(Info)){
1042bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "   failed to decompose condition\n");
104306c3fb27SDimitry Andric     return std::nullopt;
1044bdd1243dSDimitry Andric   }
1045bdd1243dSDimitry Andric 
1046bdd1243dSDimitry Andric   auto &CSToUse = Info.getCS(R.IsSigned);
1047bdd1243dSDimitry Andric 
1048bdd1243dSDimitry Andric   // If there was extra information collected during decomposition, apply
1049bdd1243dSDimitry Andric   // it now and remove it immediately once we are done with reasoning
1050bdd1243dSDimitry Andric   // about the constraint.
1051bdd1243dSDimitry Andric   for (auto &Row : R.ExtraInfo)
1052bdd1243dSDimitry Andric     CSToUse.addVariableRow(Row);
1053bdd1243dSDimitry Andric   auto InfoRestorer = make_scope_exit([&]() {
1054bdd1243dSDimitry Andric     for (unsigned I = 0; I < R.ExtraInfo.size(); ++I)
1055bdd1243dSDimitry Andric       CSToUse.popLastConstraint();
1056bdd1243dSDimitry Andric   });
1057bdd1243dSDimitry Andric 
105806c3fb27SDimitry Andric   if (auto ImpliedCondition = R.isImpliedBy(CSToUse)) {
1059bdd1243dSDimitry Andric     if (!DebugCounter::shouldExecute(EliminatedCounter))
106006c3fb27SDimitry Andric       return std::nullopt;
1061bdd1243dSDimitry Andric 
1062bdd1243dSDimitry Andric     LLVM_DEBUG({
106306c3fb27SDimitry Andric       if (*ImpliedCondition) {
106406c3fb27SDimitry Andric         dbgs() << "Condition " << *Cmp;
106506c3fb27SDimitry Andric       } else {
106606c3fb27SDimitry Andric         auto InversePred = Cmp->getInversePredicate();
106706c3fb27SDimitry Andric         dbgs() << "Condition " << CmpInst::getPredicateName(InversePred) << " "
106806c3fb27SDimitry Andric                << *A << ", " << *B;
106906c3fb27SDimitry Andric       }
107006c3fb27SDimitry Andric       dbgs() << " implied by dominating constraints\n";
107106c3fb27SDimitry Andric       CSToUse.dump();
1072bdd1243dSDimitry Andric     });
107306c3fb27SDimitry Andric     return ImpliedCondition;
107406c3fb27SDimitry Andric   }
107506c3fb27SDimitry Andric 
107606c3fb27SDimitry Andric   return std::nullopt;
107706c3fb27SDimitry Andric }
107806c3fb27SDimitry Andric 
107906c3fb27SDimitry Andric static bool checkAndReplaceCondition(
108006c3fb27SDimitry Andric     CmpInst *Cmp, ConstraintInfo &Info, unsigned NumIn, unsigned NumOut,
108106c3fb27SDimitry Andric     Instruction *ContextInst, Module *ReproducerModule,
108206c3fb27SDimitry Andric     ArrayRef<ReproducerEntry> ReproducerCondStack, DominatorTree &DT) {
108306c3fb27SDimitry Andric   auto ReplaceCmpWithConstant = [&](CmpInst *Cmp, bool IsTrue) {
108406c3fb27SDimitry Andric     generateReproducer(Cmp, ReproducerModule, ReproducerCondStack, Info, DT);
108506c3fb27SDimitry Andric     Constant *ConstantC = ConstantInt::getBool(
108606c3fb27SDimitry Andric         CmpInst::makeCmpResultType(Cmp->getType()), IsTrue);
108706c3fb27SDimitry Andric     Cmp->replaceUsesWithIf(ConstantC, [&DT, NumIn, NumOut,
108806c3fb27SDimitry Andric                                        ContextInst](Use &U) {
108906c3fb27SDimitry Andric       auto *UserI = getContextInstForUse(U);
109006c3fb27SDimitry Andric       auto *DTN = DT.getNode(UserI->getParent());
109106c3fb27SDimitry Andric       if (!DTN || DTN->getDFSNumIn() < NumIn || DTN->getDFSNumOut() > NumOut)
109206c3fb27SDimitry Andric         return false;
109306c3fb27SDimitry Andric       if (UserI->getParent() == ContextInst->getParent() &&
109406c3fb27SDimitry Andric           UserI->comesBefore(ContextInst))
109506c3fb27SDimitry Andric         return false;
109606c3fb27SDimitry Andric 
1097bdd1243dSDimitry Andric       // Conditions in an assume trivially simplify to true. Skip uses
1098bdd1243dSDimitry Andric       // in assume calls to not destroy the available information.
1099bdd1243dSDimitry Andric       auto *II = dyn_cast<IntrinsicInst>(U.getUser());
1100bdd1243dSDimitry Andric       return !II || II->getIntrinsicID() != Intrinsic::assume;
1101bdd1243dSDimitry Andric     });
1102bdd1243dSDimitry Andric     NumCondsRemoved++;
110306c3fb27SDimitry Andric     return true;
110406c3fb27SDimitry Andric   };
110506c3fb27SDimitry Andric 
110606c3fb27SDimitry Andric   if (auto ImpliedCondition =
110706c3fb27SDimitry Andric           checkCondition(Cmp, Info, NumIn, NumOut, ContextInst))
110806c3fb27SDimitry Andric     return ReplaceCmpWithConstant(Cmp, *ImpliedCondition);
110906c3fb27SDimitry Andric   return false;
1110bdd1243dSDimitry Andric }
111106c3fb27SDimitry Andric 
111206c3fb27SDimitry Andric static void
111306c3fb27SDimitry Andric removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info,
111406c3fb27SDimitry Andric                      Module *ReproducerModule,
111506c3fb27SDimitry Andric                      SmallVectorImpl<ReproducerEntry> &ReproducerCondStack,
111606c3fb27SDimitry Andric                      SmallVectorImpl<StackEntry> &DFSInStack) {
111706c3fb27SDimitry Andric   Info.popLastConstraint(E.IsSigned);
111806c3fb27SDimitry Andric   // Remove variables in the system that went out of scope.
111906c3fb27SDimitry Andric   auto &Mapping = Info.getValue2Index(E.IsSigned);
112006c3fb27SDimitry Andric   for (Value *V : E.ValuesToRelease)
112106c3fb27SDimitry Andric     Mapping.erase(V);
112206c3fb27SDimitry Andric   Info.popLastNVariables(E.IsSigned, E.ValuesToRelease.size());
112306c3fb27SDimitry Andric   DFSInStack.pop_back();
112406c3fb27SDimitry Andric   if (ReproducerModule)
112506c3fb27SDimitry Andric     ReproducerCondStack.pop_back();
112606c3fb27SDimitry Andric }
112706c3fb27SDimitry Andric 
112806c3fb27SDimitry Andric /// Check if the first condition for an AND implies the second.
112906c3fb27SDimitry Andric static bool checkAndSecondOpImpliedByFirst(
113006c3fb27SDimitry Andric     FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule,
113106c3fb27SDimitry Andric     SmallVectorImpl<ReproducerEntry> &ReproducerCondStack,
113206c3fb27SDimitry Andric     SmallVectorImpl<StackEntry> &DFSInStack) {
113306c3fb27SDimitry Andric   CmpInst::Predicate Pred;
113406c3fb27SDimitry Andric   Value *A, *B;
113506c3fb27SDimitry Andric   Instruction *And = CB.getContextInst();
113606c3fb27SDimitry Andric   if (!match(And->getOperand(0), m_ICmp(Pred, m_Value(A), m_Value(B))))
1137bdd1243dSDimitry Andric     return false;
1138bdd1243dSDimitry Andric 
113906c3fb27SDimitry Andric   // Optimistically add fact from first condition.
114006c3fb27SDimitry Andric   unsigned OldSize = DFSInStack.size();
114106c3fb27SDimitry Andric   Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
114206c3fb27SDimitry Andric   if (OldSize == DFSInStack.size())
114306c3fb27SDimitry Andric     return false;
114406c3fb27SDimitry Andric 
114506c3fb27SDimitry Andric   bool Changed = false;
114606c3fb27SDimitry Andric   // Check if the second condition can be simplified now.
114706c3fb27SDimitry Andric   if (auto ImpliedCondition =
114806c3fb27SDimitry Andric           checkCondition(cast<ICmpInst>(And->getOperand(1)), Info, CB.NumIn,
114906c3fb27SDimitry Andric                          CB.NumOut, CB.getContextInst())) {
115006c3fb27SDimitry Andric     And->setOperand(1, ConstantInt::getBool(And->getType(), *ImpliedCondition));
1151bdd1243dSDimitry Andric     Changed = true;
1152bdd1243dSDimitry Andric   }
115306c3fb27SDimitry Andric 
115406c3fb27SDimitry Andric   // Remove entries again.
115506c3fb27SDimitry Andric   while (OldSize < DFSInStack.size()) {
115606c3fb27SDimitry Andric     StackEntry E = DFSInStack.back();
115706c3fb27SDimitry Andric     removeEntryFromStack(E, Info, ReproducerModule, ReproducerCondStack,
115806c3fb27SDimitry Andric                          DFSInStack);
115906c3fb27SDimitry Andric   }
1160bdd1243dSDimitry Andric   return Changed;
1161e8d8bef9SDimitry Andric }
1162e8d8bef9SDimitry Andric 
116381ad6265SDimitry Andric void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B,
1164bdd1243dSDimitry Andric                              unsigned NumIn, unsigned NumOut,
116581ad6265SDimitry Andric                              SmallVectorImpl<StackEntry> &DFSInStack) {
116681ad6265SDimitry Andric   // If the constraint has a pre-condition, skip the constraint if it does not
116781ad6265SDimitry Andric   // hold.
1168bdd1243dSDimitry Andric   SmallVector<Value *> NewVariables;
1169bdd1243dSDimitry Andric   auto R = getConstraint(Pred, A, B, NewVariables);
117006c3fb27SDimitry Andric 
117106c3fb27SDimitry Andric   // TODO: Support non-equality for facts as well.
117206c3fb27SDimitry Andric   if (!R.isValid(*this) || R.isNe())
117381ad6265SDimitry Andric     return;
117481ad6265SDimitry Andric 
117506c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "Adding '" << Pred << " ";
1176bdd1243dSDimitry Andric              A->printAsOperand(dbgs(), false); dbgs() << ", ";
1177bdd1243dSDimitry Andric              B->printAsOperand(dbgs(), false); dbgs() << "'\n");
117881ad6265SDimitry Andric   bool Added = false;
117981ad6265SDimitry Andric   auto &CSToUse = getCS(R.IsSigned);
118081ad6265SDimitry Andric   if (R.Coefficients.empty())
118181ad6265SDimitry Andric     return;
118281ad6265SDimitry Andric 
118381ad6265SDimitry Andric   Added |= CSToUse.addVariableRowFill(R.Coefficients);
118481ad6265SDimitry Andric 
1185bdd1243dSDimitry Andric   // If R has been added to the system, add the new variables and queue it for
1186bdd1243dSDimitry Andric   // removal once it goes out-of-scope.
118781ad6265SDimitry Andric   if (Added) {
118881ad6265SDimitry Andric     SmallVector<Value *, 2> ValuesToRelease;
1189bdd1243dSDimitry Andric     auto &Value2Index = getValue2Index(R.IsSigned);
1190bdd1243dSDimitry Andric     for (Value *V : NewVariables) {
1191bdd1243dSDimitry Andric       Value2Index.insert({V, Value2Index.size() + 1});
1192bdd1243dSDimitry Andric       ValuesToRelease.push_back(V);
119381ad6265SDimitry Andric     }
119481ad6265SDimitry Andric 
119581ad6265SDimitry Andric     LLVM_DEBUG({
119681ad6265SDimitry Andric       dbgs() << "  constraint: ";
119706c3fb27SDimitry Andric       dumpConstraint(R.Coefficients, getValue2Index(R.IsSigned));
1198bdd1243dSDimitry Andric       dbgs() << "\n";
119981ad6265SDimitry Andric     });
120081ad6265SDimitry Andric 
1201bdd1243dSDimitry Andric     DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,
1202bdd1243dSDimitry Andric                             std::move(ValuesToRelease));
120381ad6265SDimitry Andric 
120406c3fb27SDimitry Andric     if (R.isEq()) {
120581ad6265SDimitry Andric       // Also add the inverted constraint for equality constraints.
120681ad6265SDimitry Andric       for (auto &Coeff : R.Coefficients)
120781ad6265SDimitry Andric         Coeff *= -1;
120881ad6265SDimitry Andric       CSToUse.addVariableRowFill(R.Coefficients);
120981ad6265SDimitry Andric 
1210bdd1243dSDimitry Andric       DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,
121181ad6265SDimitry Andric                               SmallVector<Value *, 2>());
121281ad6265SDimitry Andric     }
121381ad6265SDimitry Andric   }
121481ad6265SDimitry Andric }
121581ad6265SDimitry Andric 
1216bdd1243dSDimitry Andric static bool replaceSubOverflowUses(IntrinsicInst *II, Value *A, Value *B,
1217bdd1243dSDimitry Andric                                    SmallVectorImpl<Instruction *> &ToRemove) {
1218bdd1243dSDimitry Andric   bool Changed = false;
1219bdd1243dSDimitry Andric   IRBuilder<> Builder(II->getParent(), II->getIterator());
1220bdd1243dSDimitry Andric   Value *Sub = nullptr;
1221bdd1243dSDimitry Andric   for (User *U : make_early_inc_range(II->users())) {
1222bdd1243dSDimitry Andric     if (match(U, m_ExtractValue<0>(m_Value()))) {
1223bdd1243dSDimitry Andric       if (!Sub)
1224bdd1243dSDimitry Andric         Sub = Builder.CreateSub(A, B);
1225bdd1243dSDimitry Andric       U->replaceAllUsesWith(Sub);
1226bdd1243dSDimitry Andric       Changed = true;
1227bdd1243dSDimitry Andric     } else if (match(U, m_ExtractValue<1>(m_Value()))) {
1228bdd1243dSDimitry Andric       U->replaceAllUsesWith(Builder.getFalse());
1229bdd1243dSDimitry Andric       Changed = true;
1230bdd1243dSDimitry Andric     } else
1231bdd1243dSDimitry Andric       continue;
1232bdd1243dSDimitry Andric 
1233bdd1243dSDimitry Andric     if (U->use_empty()) {
1234bdd1243dSDimitry Andric       auto *I = cast<Instruction>(U);
1235bdd1243dSDimitry Andric       ToRemove.push_back(I);
1236bdd1243dSDimitry Andric       I->setOperand(0, PoisonValue::get(II->getType()));
1237bdd1243dSDimitry Andric       Changed = true;
1238bdd1243dSDimitry Andric     }
1239bdd1243dSDimitry Andric   }
1240bdd1243dSDimitry Andric 
1241bdd1243dSDimitry Andric   if (II->use_empty()) {
1242bdd1243dSDimitry Andric     II->eraseFromParent();
1243bdd1243dSDimitry Andric     Changed = true;
1244bdd1243dSDimitry Andric   }
1245bdd1243dSDimitry Andric   return Changed;
1246bdd1243dSDimitry Andric }
1247bdd1243dSDimitry Andric 
1248bdd1243dSDimitry Andric static bool
124981ad6265SDimitry Andric tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
125081ad6265SDimitry Andric                           SmallVectorImpl<Instruction *> &ToRemove) {
125181ad6265SDimitry Andric   auto DoesConditionHold = [](CmpInst::Predicate Pred, Value *A, Value *B,
125281ad6265SDimitry Andric                               ConstraintInfo &Info) {
1253bdd1243dSDimitry Andric     auto R = Info.getConstraintForSolving(Pred, A, B);
1254bdd1243dSDimitry Andric     if (R.size() < 2 || !R.isValid(Info))
125581ad6265SDimitry Andric       return false;
125681ad6265SDimitry Andric 
1257bdd1243dSDimitry Andric     auto &CSToUse = Info.getCS(R.IsSigned);
125881ad6265SDimitry Andric     return CSToUse.isConditionImplied(R.Coefficients);
125981ad6265SDimitry Andric   };
126081ad6265SDimitry Andric 
1261bdd1243dSDimitry Andric   bool Changed = false;
126281ad6265SDimitry Andric   if (II->getIntrinsicID() == Intrinsic::ssub_with_overflow) {
126381ad6265SDimitry Andric     // If A s>= B && B s>= 0, ssub.with.overflow(a, b) should not overflow and
126481ad6265SDimitry Andric     // can be simplified to a regular sub.
126581ad6265SDimitry Andric     Value *A = II->getArgOperand(0);
126681ad6265SDimitry Andric     Value *B = II->getArgOperand(1);
126781ad6265SDimitry Andric     if (!DoesConditionHold(CmpInst::ICMP_SGE, A, B, Info) ||
126881ad6265SDimitry Andric         !DoesConditionHold(CmpInst::ICMP_SGE, B,
126981ad6265SDimitry Andric                            ConstantInt::get(A->getType(), 0), Info))
1270bdd1243dSDimitry Andric       return false;
1271bdd1243dSDimitry Andric     Changed = replaceSubOverflowUses(II, A, B, ToRemove);
127281ad6265SDimitry Andric   }
1273bdd1243dSDimitry Andric   return Changed;
127481ad6265SDimitry Andric }
127581ad6265SDimitry Andric 
127606c3fb27SDimitry Andric static bool eliminateConstraints(Function &F, DominatorTree &DT,
127706c3fb27SDimitry Andric                                  OptimizationRemarkEmitter &ORE) {
127881ad6265SDimitry Andric   bool Changed = false;
127981ad6265SDimitry Andric   DT.updateDFSNumbers();
128006c3fb27SDimitry Andric   SmallVector<Value *> FunctionArgs;
128106c3fb27SDimitry Andric   for (Value &Arg : F.args())
128206c3fb27SDimitry Andric     FunctionArgs.push_back(&Arg);
128306c3fb27SDimitry Andric   ConstraintInfo Info(F.getParent()->getDataLayout(), FunctionArgs);
128481ad6265SDimitry Andric   State S(DT);
128506c3fb27SDimitry Andric   std::unique_ptr<Module> ReproducerModule(
128606c3fb27SDimitry Andric       DumpReproducers ? new Module(F.getName(), F.getContext()) : nullptr);
128781ad6265SDimitry Andric 
128881ad6265SDimitry Andric   // First, collect conditions implied by branches and blocks with their
128981ad6265SDimitry Andric   // Dominator DFS in and out numbers.
129081ad6265SDimitry Andric   for (BasicBlock &BB : F) {
129181ad6265SDimitry Andric     if (!DT.getNode(&BB))
129281ad6265SDimitry Andric       continue;
129381ad6265SDimitry Andric     S.addInfoFor(BB);
129481ad6265SDimitry Andric   }
129581ad6265SDimitry Andric 
1296bdd1243dSDimitry Andric   // Next, sort worklist by dominance, so that dominating conditions to check
1297bdd1243dSDimitry Andric   // and facts come before conditions and facts dominated by them. If a
1298bdd1243dSDimitry Andric   // condition to check and a fact have the same numbers, conditional facts come
1299bdd1243dSDimitry Andric   // first. Assume facts and checks are ordered according to their relative
1300bdd1243dSDimitry Andric   // order in the containing basic block. Also make sure conditions with
1301bdd1243dSDimitry Andric   // constant operands come before conditions without constant operands. This
1302bdd1243dSDimitry Andric   // increases the effectiveness of the current signed <-> unsigned fact
1303bdd1243dSDimitry Andric   // transfer logic.
1304bdd1243dSDimitry Andric   stable_sort(S.WorkList, [](const FactOrCheck &A, const FactOrCheck &B) {
1305bdd1243dSDimitry Andric     auto HasNoConstOp = [](const FactOrCheck &B) {
1306bdd1243dSDimitry Andric       return !isa<ConstantInt>(B.Inst->getOperand(0)) &&
1307bdd1243dSDimitry Andric              !isa<ConstantInt>(B.Inst->getOperand(1));
1308bdd1243dSDimitry Andric     };
1309bdd1243dSDimitry Andric     // If both entries have the same In numbers, conditional facts come first.
1310bdd1243dSDimitry Andric     // Otherwise use the relative order in the basic block.
1311bdd1243dSDimitry Andric     if (A.NumIn == B.NumIn) {
1312bdd1243dSDimitry Andric       if (A.isConditionFact() && B.isConditionFact()) {
1313bdd1243dSDimitry Andric         bool NoConstOpA = HasNoConstOp(A);
1314bdd1243dSDimitry Andric         bool NoConstOpB = HasNoConstOp(B);
1315bdd1243dSDimitry Andric         return NoConstOpA < NoConstOpB;
1316bdd1243dSDimitry Andric       }
1317bdd1243dSDimitry Andric       if (A.isConditionFact())
1318bdd1243dSDimitry Andric         return true;
1319bdd1243dSDimitry Andric       if (B.isConditionFact())
1320bdd1243dSDimitry Andric         return false;
132106c3fb27SDimitry Andric       auto *InstA = A.getContextInst();
132206c3fb27SDimitry Andric       auto *InstB = B.getContextInst();
132306c3fb27SDimitry Andric       return InstA->comesBefore(InstB);
1324bdd1243dSDimitry Andric     }
1325bdd1243dSDimitry Andric     return A.NumIn < B.NumIn;
1326e8d8bef9SDimitry Andric   });
1327e8d8bef9SDimitry Andric 
132881ad6265SDimitry Andric   SmallVector<Instruction *> ToRemove;
132981ad6265SDimitry Andric 
1330e8d8bef9SDimitry Andric   // Finally, process ordered worklist and eliminate implied conditions.
1331e8d8bef9SDimitry Andric   SmallVector<StackEntry, 16> DFSInStack;
133206c3fb27SDimitry Andric   SmallVector<ReproducerEntry> ReproducerCondStack;
1333bdd1243dSDimitry Andric   for (FactOrCheck &CB : S.WorkList) {
1334e8d8bef9SDimitry Andric     // First, pop entries from the stack that are out-of-scope for CB. Remove
1335e8d8bef9SDimitry Andric     // the corresponding entry from the constraint system.
1336e8d8bef9SDimitry Andric     while (!DFSInStack.empty()) {
1337e8d8bef9SDimitry Andric       auto &E = DFSInStack.back();
1338e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "Top of stack : " << E.NumIn << " " << E.NumOut
1339e8d8bef9SDimitry Andric                         << "\n");
1340e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "CB: " << CB.NumIn << " " << CB.NumOut << "\n");
1341e8d8bef9SDimitry Andric       assert(E.NumIn <= CB.NumIn);
1342e8d8bef9SDimitry Andric       if (CB.NumOut <= E.NumOut)
1343e8d8bef9SDimitry Andric         break;
134481ad6265SDimitry Andric       LLVM_DEBUG({
134581ad6265SDimitry Andric         dbgs() << "Removing ";
134606c3fb27SDimitry Andric         dumpConstraint(Info.getCS(E.IsSigned).getLastConstraint(),
134781ad6265SDimitry Andric                        Info.getValue2Index(E.IsSigned));
134881ad6265SDimitry Andric         dbgs() << "\n";
134981ad6265SDimitry Andric       });
135006c3fb27SDimitry Andric       removeEntryFromStack(E, Info, ReproducerModule.get(), ReproducerCondStack,
135106c3fb27SDimitry Andric                            DFSInStack);
1352e8d8bef9SDimitry Andric     }
1353e8d8bef9SDimitry Andric 
135406c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "Processing ");
1355e8d8bef9SDimitry Andric 
1356e8d8bef9SDimitry Andric     // For a block, check if any CmpInsts become known based on the current set
1357e8d8bef9SDimitry Andric     // of constraints.
135806c3fb27SDimitry Andric     if (CB.isCheck()) {
135906c3fb27SDimitry Andric       Instruction *Inst = CB.getInstructionToSimplify();
136006c3fb27SDimitry Andric       if (!Inst)
136106c3fb27SDimitry Andric         continue;
136206c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "condition to simplify: " << *Inst << "\n");
136306c3fb27SDimitry Andric       if (auto *II = dyn_cast<WithOverflowInst>(Inst)) {
1364bdd1243dSDimitry Andric         Changed |= tryToSimplifyOverflowMath(II, Info, ToRemove);
136506c3fb27SDimitry Andric       } else if (auto *Cmp = dyn_cast<ICmpInst>(Inst)) {
136606c3fb27SDimitry Andric         bool Simplified = checkAndReplaceCondition(
136706c3fb27SDimitry Andric             Cmp, Info, CB.NumIn, CB.NumOut, CB.getContextInst(),
136806c3fb27SDimitry Andric             ReproducerModule.get(), ReproducerCondStack, S.DT);
136906c3fb27SDimitry Andric         if (!Simplified && match(CB.getContextInst(),
137006c3fb27SDimitry Andric                                  m_LogicalAnd(m_Value(), m_Specific(Inst)))) {
137106c3fb27SDimitry Andric           Simplified =
137206c3fb27SDimitry Andric               checkAndSecondOpImpliedByFirst(CB, Info, ReproducerModule.get(),
137306c3fb27SDimitry Andric                                              ReproducerCondStack, DFSInStack);
137406c3fb27SDimitry Andric         }
137506c3fb27SDimitry Andric         Changed |= Simplified;
1376e8d8bef9SDimitry Andric       }
1377e8d8bef9SDimitry Andric       continue;
1378e8d8bef9SDimitry Andric     }
1379e8d8bef9SDimitry Andric 
138006c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "fact to add to the system: " << *CB.Inst << "\n");
138106c3fb27SDimitry Andric     auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) {
1382bdd1243dSDimitry Andric       if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) {
1383bdd1243dSDimitry Andric         LLVM_DEBUG(
1384bdd1243dSDimitry Andric             dbgs()
1385bdd1243dSDimitry Andric             << "Skip adding constraint because system has too many rows.\n");
138606c3fb27SDimitry Andric         return;
138706c3fb27SDimitry Andric       }
138806c3fb27SDimitry Andric 
138906c3fb27SDimitry Andric       Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
139006c3fb27SDimitry Andric       if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size())
139106c3fb27SDimitry Andric         ReproducerCondStack.emplace_back(Pred, A, B);
139206c3fb27SDimitry Andric 
139306c3fb27SDimitry Andric       Info.transferToOtherSystem(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
139406c3fb27SDimitry Andric       if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) {
139506c3fb27SDimitry Andric         // Add dummy entries to ReproducerCondStack to keep it in sync with
139606c3fb27SDimitry Andric         // DFSInStack.
139706c3fb27SDimitry Andric         for (unsigned I = 0,
139806c3fb27SDimitry Andric                       E = (DFSInStack.size() - ReproducerCondStack.size());
139906c3fb27SDimitry Andric              I < E; ++I) {
140006c3fb27SDimitry Andric           ReproducerCondStack.emplace_back(ICmpInst::BAD_ICMP_PREDICATE,
140106c3fb27SDimitry Andric                                            nullptr, nullptr);
140206c3fb27SDimitry Andric         }
140306c3fb27SDimitry Andric       }
140406c3fb27SDimitry Andric     };
140506c3fb27SDimitry Andric 
140606c3fb27SDimitry Andric     ICmpInst::Predicate Pred;
140706c3fb27SDimitry Andric     if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {
140806c3fb27SDimitry Andric       Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
140906c3fb27SDimitry Andric       AddFact(Pred, MinMax, MinMax->getLHS());
141006c3fb27SDimitry Andric       AddFact(Pred, MinMax, MinMax->getRHS());
1411bdd1243dSDimitry Andric       continue;
1412bdd1243dSDimitry Andric     }
1413bdd1243dSDimitry Andric 
141406c3fb27SDimitry Andric     Value *A, *B;
141506c3fb27SDimitry Andric     Value *Cmp = CB.Inst;
141606c3fb27SDimitry Andric     match(Cmp, m_Intrinsic<Intrinsic::assume>(m_Value(Cmp)));
141706c3fb27SDimitry Andric     if (match(Cmp, m_ICmp(Pred, m_Value(A), m_Value(B)))) {
1418bdd1243dSDimitry Andric       // Use the inverse predicate if required.
1419bdd1243dSDimitry Andric       if (CB.Not)
1420bdd1243dSDimitry Andric         Pred = CmpInst::getInversePredicate(Pred);
1421bdd1243dSDimitry Andric 
142206c3fb27SDimitry Andric       AddFact(Pred, A, B);
1423e8d8bef9SDimitry Andric     }
1424fe6060f1SDimitry Andric   }
1425e8d8bef9SDimitry Andric 
142606c3fb27SDimitry Andric   if (ReproducerModule && !ReproducerModule->functions().empty()) {
142706c3fb27SDimitry Andric     std::string S;
142806c3fb27SDimitry Andric     raw_string_ostream StringS(S);
142906c3fb27SDimitry Andric     ReproducerModule->print(StringS, nullptr);
143006c3fb27SDimitry Andric     StringS.flush();
143106c3fb27SDimitry Andric     OptimizationRemark Rem(DEBUG_TYPE, "Reproducer", &F);
143206c3fb27SDimitry Andric     Rem << ore::NV("module") << S;
143306c3fb27SDimitry Andric     ORE.emit(Rem);
143406c3fb27SDimitry Andric   }
143506c3fb27SDimitry Andric 
143681ad6265SDimitry Andric #ifndef NDEBUG
143781ad6265SDimitry Andric   unsigned SignedEntries =
143881ad6265SDimitry Andric       count_if(DFSInStack, [](const StackEntry &E) { return E.IsSigned; });
143981ad6265SDimitry Andric   assert(Info.getCS(false).size() == DFSInStack.size() - SignedEntries &&
1440fe6060f1SDimitry Andric          "updates to CS and DFSInStack are out of sync");
144181ad6265SDimitry Andric   assert(Info.getCS(true).size() == SignedEntries &&
144281ad6265SDimitry Andric          "updates to CS and DFSInStack are out of sync");
144381ad6265SDimitry Andric #endif
144481ad6265SDimitry Andric 
144581ad6265SDimitry Andric   for (Instruction *I : ToRemove)
144681ad6265SDimitry Andric     I->eraseFromParent();
1447e8d8bef9SDimitry Andric   return Changed;
1448e8d8bef9SDimitry Andric }
1449e8d8bef9SDimitry Andric 
1450e8d8bef9SDimitry Andric PreservedAnalyses ConstraintEliminationPass::run(Function &F,
1451e8d8bef9SDimitry Andric                                                  FunctionAnalysisManager &AM) {
1452e8d8bef9SDimitry Andric   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
145306c3fb27SDimitry Andric   auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
145406c3fb27SDimitry Andric   if (!eliminateConstraints(F, DT, ORE))
1455e8d8bef9SDimitry Andric     return PreservedAnalyses::all();
1456e8d8bef9SDimitry Andric 
1457e8d8bef9SDimitry Andric   PreservedAnalyses PA;
1458e8d8bef9SDimitry Andric   PA.preserve<DominatorTreeAnalysis>();
1459e8d8bef9SDimitry Andric   PA.preserveSet<CFGAnalyses>();
1460e8d8bef9SDimitry Andric   return PA;
1461e8d8bef9SDimitry Andric }
1462