xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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"
21*5f757f3fSDimitry Andric #include "llvm/Analysis/LoopInfo.h"
2206c3fb27SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
23*5f757f3fSDimitry Andric #include "llvm/Analysis/ScalarEvolution.h"
24*5f757f3fSDimitry Andric #include "llvm/Analysis/ScalarEvolutionExpressions.h"
25349cc55cSDimitry Andric #include "llvm/Analysis/ValueTracking.h"
26bdd1243dSDimitry Andric #include "llvm/IR/DataLayout.h"
27e8d8bef9SDimitry Andric #include "llvm/IR/Dominators.h"
28e8d8bef9SDimitry Andric #include "llvm/IR/Function.h"
2981ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h"
30*5f757f3fSDimitry Andric #include "llvm/IR/InstrTypes.h"
31e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h"
32e8d8bef9SDimitry Andric #include "llvm/IR/PatternMatch.h"
3306c3fb27SDimitry Andric #include "llvm/IR/Verifier.h"
34e8d8bef9SDimitry Andric #include "llvm/Pass.h"
35bdd1243dSDimitry Andric #include "llvm/Support/CommandLine.h"
36e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h"
37e8d8bef9SDimitry Andric #include "llvm/Support/DebugCounter.h"
3881ad6265SDimitry Andric #include "llvm/Support/MathExtras.h"
3906c3fb27SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h"
4006c3fb27SDimitry Andric #include "llvm/Transforms/Utils/ValueMapper.h"
41e8d8bef9SDimitry Andric 
42bdd1243dSDimitry Andric #include <cmath>
4306c3fb27SDimitry Andric #include <optional>
44fe6060f1SDimitry Andric #include <string>
45fe6060f1SDimitry Andric 
46e8d8bef9SDimitry Andric using namespace llvm;
47e8d8bef9SDimitry Andric using namespace PatternMatch;
48e8d8bef9SDimitry Andric 
49e8d8bef9SDimitry Andric #define DEBUG_TYPE "constraint-elimination"
50e8d8bef9SDimitry Andric 
51e8d8bef9SDimitry Andric STATISTIC(NumCondsRemoved, "Number of instructions removed");
52e8d8bef9SDimitry Andric DEBUG_COUNTER(EliminatedCounter, "conds-eliminated",
53e8d8bef9SDimitry Andric               "Controls which conditions are eliminated");
54e8d8bef9SDimitry Andric 
55bdd1243dSDimitry Andric static cl::opt<unsigned>
56bdd1243dSDimitry Andric     MaxRows("constraint-elimination-max-rows", cl::init(500), cl::Hidden,
57bdd1243dSDimitry Andric             cl::desc("Maximum number of rows to keep in constraint system"));
58bdd1243dSDimitry Andric 
5906c3fb27SDimitry Andric static cl::opt<bool> DumpReproducers(
6006c3fb27SDimitry Andric     "constraint-elimination-dump-reproducers", cl::init(false), cl::Hidden,
6106c3fb27SDimitry Andric     cl::desc("Dump IR to reproduce successful transformations."));
6206c3fb27SDimitry Andric 
63e8d8bef9SDimitry Andric static int64_t MaxConstraintValue = std::numeric_limits<int64_t>::max();
6481ad6265SDimitry Andric static int64_t MinSignedConstraintValue = std::numeric_limits<int64_t>::min();
65e8d8bef9SDimitry Andric 
66bdd1243dSDimitry Andric // A helper to multiply 2 signed integers where overflowing is allowed.
67bdd1243dSDimitry Andric static int64_t multiplyWithOverflow(int64_t A, int64_t B) {
68bdd1243dSDimitry Andric   int64_t Result;
69bdd1243dSDimitry Andric   MulOverflow(A, B, Result);
70bdd1243dSDimitry Andric   return Result;
71bdd1243dSDimitry Andric }
72bdd1243dSDimitry Andric 
73bdd1243dSDimitry Andric // A helper to add 2 signed integers where overflowing is allowed.
74bdd1243dSDimitry Andric static int64_t addWithOverflow(int64_t A, int64_t B) {
75bdd1243dSDimitry Andric   int64_t Result;
76bdd1243dSDimitry Andric   AddOverflow(A, B, Result);
77bdd1243dSDimitry Andric   return Result;
78bdd1243dSDimitry Andric }
79bdd1243dSDimitry Andric 
8006c3fb27SDimitry Andric static Instruction *getContextInstForUse(Use &U) {
8106c3fb27SDimitry Andric   Instruction *UserI = cast<Instruction>(U.getUser());
8206c3fb27SDimitry Andric   if (auto *Phi = dyn_cast<PHINode>(UserI))
8306c3fb27SDimitry Andric     UserI = Phi->getIncomingBlock(U)->getTerminator();
8406c3fb27SDimitry Andric   return UserI;
8506c3fb27SDimitry Andric }
8606c3fb27SDimitry Andric 
8704eeddc0SDimitry Andric namespace {
88*5f757f3fSDimitry Andric /// Struct to express a condition of the form %Op0 Pred %Op1.
89*5f757f3fSDimitry Andric struct ConditionTy {
90*5f757f3fSDimitry Andric   CmpInst::Predicate Pred;
91*5f757f3fSDimitry Andric   Value *Op0;
92*5f757f3fSDimitry Andric   Value *Op1;
93*5f757f3fSDimitry Andric 
94*5f757f3fSDimitry Andric   ConditionTy()
95*5f757f3fSDimitry Andric       : Pred(CmpInst::BAD_ICMP_PREDICATE), Op0(nullptr), Op1(nullptr) {}
96*5f757f3fSDimitry Andric   ConditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1)
97*5f757f3fSDimitry Andric       : Pred(Pred), Op0(Op0), Op1(Op1) {}
98*5f757f3fSDimitry Andric };
99*5f757f3fSDimitry Andric 
10006c3fb27SDimitry Andric /// Represents either
101*5f757f3fSDimitry Andric ///  * a condition that holds on entry to a block (=condition fact)
10206c3fb27SDimitry Andric ///  * an assume (=assume fact)
10306c3fb27SDimitry Andric ///  * a use of a compare instruction to simplify.
10406c3fb27SDimitry Andric /// It also tracks the Dominator DFS in and out numbers for each entry.
10506c3fb27SDimitry Andric struct FactOrCheck {
106*5f757f3fSDimitry Andric   enum class EntryTy {
107*5f757f3fSDimitry Andric     ConditionFact, /// A condition that holds on entry to a block.
108*5f757f3fSDimitry Andric     InstFact,      /// A fact that holds after Inst executed (e.g. an assume or
109*5f757f3fSDimitry Andric                    /// min/mix intrinsic.
110*5f757f3fSDimitry Andric     InstCheck,     /// An instruction to simplify (e.g. an overflow math
111*5f757f3fSDimitry Andric                    /// intrinsics).
112*5f757f3fSDimitry Andric     UseCheck       /// An use of a compare instruction to simplify.
113*5f757f3fSDimitry Andric   };
114*5f757f3fSDimitry Andric 
11506c3fb27SDimitry Andric   union {
11606c3fb27SDimitry Andric     Instruction *Inst;
11706c3fb27SDimitry Andric     Use *U;
118*5f757f3fSDimitry Andric     ConditionTy Cond;
11906c3fb27SDimitry Andric   };
120*5f757f3fSDimitry Andric 
121*5f757f3fSDimitry Andric   /// A pre-condition that must hold for the current fact to be added to the
122*5f757f3fSDimitry Andric   /// system.
123*5f757f3fSDimitry Andric   ConditionTy DoesHold;
124*5f757f3fSDimitry Andric 
12506c3fb27SDimitry Andric   unsigned NumIn;
12606c3fb27SDimitry Andric   unsigned NumOut;
127*5f757f3fSDimitry Andric   EntryTy Ty;
12806c3fb27SDimitry Andric 
129*5f757f3fSDimitry Andric   FactOrCheck(EntryTy Ty, DomTreeNode *DTN, Instruction *Inst)
13006c3fb27SDimitry Andric       : Inst(Inst), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
131*5f757f3fSDimitry Andric         Ty(Ty) {}
13206c3fb27SDimitry Andric 
13306c3fb27SDimitry Andric   FactOrCheck(DomTreeNode *DTN, Use *U)
134*5f757f3fSDimitry Andric       : U(U), DoesHold(CmpInst::BAD_ICMP_PREDICATE, nullptr, nullptr),
135*5f757f3fSDimitry Andric         NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
136*5f757f3fSDimitry Andric         Ty(EntryTy::UseCheck) {}
13706c3fb27SDimitry Andric 
138*5f757f3fSDimitry Andric   FactOrCheck(DomTreeNode *DTN, CmpInst::Predicate Pred, Value *Op0, Value *Op1,
139*5f757f3fSDimitry Andric               ConditionTy Precond = ConditionTy())
140*5f757f3fSDimitry Andric       : Cond(Pred, Op0, Op1), DoesHold(Precond), NumIn(DTN->getDFSNumIn()),
141*5f757f3fSDimitry Andric         NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {}
142*5f757f3fSDimitry Andric 
143*5f757f3fSDimitry Andric   static FactOrCheck getConditionFact(DomTreeNode *DTN, CmpInst::Predicate Pred,
144*5f757f3fSDimitry Andric                                       Value *Op0, Value *Op1,
145*5f757f3fSDimitry Andric                                       ConditionTy Precond = ConditionTy()) {
146*5f757f3fSDimitry Andric     return FactOrCheck(DTN, Pred, Op0, Op1, Precond);
147*5f757f3fSDimitry Andric   }
148*5f757f3fSDimitry Andric 
149*5f757f3fSDimitry Andric   static FactOrCheck getInstFact(DomTreeNode *DTN, Instruction *Inst) {
150*5f757f3fSDimitry Andric     return FactOrCheck(EntryTy::InstFact, DTN, Inst);
15106c3fb27SDimitry Andric   }
15206c3fb27SDimitry Andric 
15306c3fb27SDimitry Andric   static FactOrCheck getCheck(DomTreeNode *DTN, Use *U) {
15406c3fb27SDimitry Andric     return FactOrCheck(DTN, U);
15506c3fb27SDimitry Andric   }
15606c3fb27SDimitry Andric 
15706c3fb27SDimitry Andric   static FactOrCheck getCheck(DomTreeNode *DTN, CallInst *CI) {
158*5f757f3fSDimitry Andric     return FactOrCheck(EntryTy::InstCheck, DTN, CI);
15906c3fb27SDimitry Andric   }
16006c3fb27SDimitry Andric 
16106c3fb27SDimitry Andric   bool isCheck() const {
162*5f757f3fSDimitry Andric     return Ty == EntryTy::InstCheck || Ty == EntryTy::UseCheck;
16306c3fb27SDimitry Andric   }
16406c3fb27SDimitry Andric 
16506c3fb27SDimitry Andric   Instruction *getContextInst() const {
166*5f757f3fSDimitry Andric     if (Ty == EntryTy::UseCheck)
16706c3fb27SDimitry Andric       return getContextInstForUse(*U);
168*5f757f3fSDimitry Andric     return Inst;
16906c3fb27SDimitry Andric   }
170*5f757f3fSDimitry Andric 
17106c3fb27SDimitry Andric   Instruction *getInstructionToSimplify() const {
17206c3fb27SDimitry Andric     assert(isCheck());
173*5f757f3fSDimitry Andric     if (Ty == EntryTy::InstCheck)
17406c3fb27SDimitry Andric       return Inst;
17506c3fb27SDimitry Andric     // The use may have been simplified to a constant already.
17606c3fb27SDimitry Andric     return dyn_cast<Instruction>(*U);
17706c3fb27SDimitry Andric   }
178*5f757f3fSDimitry Andric 
179*5f757f3fSDimitry Andric   bool isConditionFact() const { return Ty == EntryTy::ConditionFact; }
18006c3fb27SDimitry Andric };
18106c3fb27SDimitry Andric 
18206c3fb27SDimitry Andric /// Keep state required to build worklist.
18306c3fb27SDimitry Andric struct State {
18406c3fb27SDimitry Andric   DominatorTree &DT;
185*5f757f3fSDimitry Andric   LoopInfo &LI;
186*5f757f3fSDimitry Andric   ScalarEvolution &SE;
18706c3fb27SDimitry Andric   SmallVector<FactOrCheck, 64> WorkList;
18806c3fb27SDimitry Andric 
189*5f757f3fSDimitry Andric   State(DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE)
190*5f757f3fSDimitry Andric       : DT(DT), LI(LI), SE(SE) {}
19106c3fb27SDimitry Andric 
19206c3fb27SDimitry Andric   /// Process block \p BB and add known facts to work-list.
19306c3fb27SDimitry Andric   void addInfoFor(BasicBlock &BB);
19406c3fb27SDimitry Andric 
195*5f757f3fSDimitry Andric   /// Try to add facts for loop inductions (AddRecs) in EQ/NE compares
196*5f757f3fSDimitry Andric   /// controlling the loop header.
197*5f757f3fSDimitry Andric   void addInfoForInductions(BasicBlock &BB);
198*5f757f3fSDimitry Andric 
19906c3fb27SDimitry Andric   /// Returns true if we can add a known condition from BB to its successor
20006c3fb27SDimitry Andric   /// block Succ.
20106c3fb27SDimitry Andric   bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ) const {
20206c3fb27SDimitry Andric     return DT.dominates(BasicBlockEdge(&BB, Succ), Succ);
20306c3fb27SDimitry Andric   }
20406c3fb27SDimitry Andric };
20504eeddc0SDimitry Andric 
20681ad6265SDimitry Andric class ConstraintInfo;
20704eeddc0SDimitry Andric 
20881ad6265SDimitry Andric struct StackEntry {
20981ad6265SDimitry Andric   unsigned NumIn;
21081ad6265SDimitry Andric   unsigned NumOut;
21181ad6265SDimitry Andric   bool IsSigned = false;
21281ad6265SDimitry Andric   /// Variables that can be removed from the system once the stack entry gets
21381ad6265SDimitry Andric   /// removed.
21481ad6265SDimitry Andric   SmallVector<Value *, 2> ValuesToRelease;
21581ad6265SDimitry Andric 
216bdd1243dSDimitry Andric   StackEntry(unsigned NumIn, unsigned NumOut, bool IsSigned,
21781ad6265SDimitry Andric              SmallVector<Value *, 2> ValuesToRelease)
218bdd1243dSDimitry Andric       : NumIn(NumIn), NumOut(NumOut), IsSigned(IsSigned),
21981ad6265SDimitry Andric         ValuesToRelease(ValuesToRelease) {}
22004eeddc0SDimitry Andric };
22104eeddc0SDimitry Andric 
22281ad6265SDimitry Andric struct ConstraintTy {
22381ad6265SDimitry Andric   SmallVector<int64_t, 8> Coefficients;
224*5f757f3fSDimitry Andric   SmallVector<ConditionTy, 2> Preconditions;
22504eeddc0SDimitry Andric 
226bdd1243dSDimitry Andric   SmallVector<SmallVector<int64_t, 8>> ExtraInfo;
227bdd1243dSDimitry Andric 
22881ad6265SDimitry Andric   bool IsSigned = false;
22904eeddc0SDimitry Andric 
23081ad6265SDimitry Andric   ConstraintTy() = default;
23104eeddc0SDimitry Andric 
23206c3fb27SDimitry Andric   ConstraintTy(SmallVector<int64_t, 8> Coefficients, bool IsSigned, bool IsEq,
23306c3fb27SDimitry Andric                bool IsNe)
23406c3fb27SDimitry Andric       : Coefficients(Coefficients), IsSigned(IsSigned), IsEq(IsEq), IsNe(IsNe) {
23506c3fb27SDimitry Andric   }
23681ad6265SDimitry Andric 
23781ad6265SDimitry Andric   unsigned size() const { return Coefficients.size(); }
23881ad6265SDimitry Andric 
23981ad6265SDimitry Andric   unsigned empty() const { return Coefficients.empty(); }
24004eeddc0SDimitry Andric 
24181ad6265SDimitry Andric   /// Returns true if all preconditions for this list of constraints are
24281ad6265SDimitry Andric   /// satisfied given \p CS and the corresponding \p Value2Index mapping.
24381ad6265SDimitry Andric   bool isValid(const ConstraintInfo &Info) const;
24406c3fb27SDimitry Andric 
24506c3fb27SDimitry Andric   bool isEq() const { return IsEq; }
24606c3fb27SDimitry Andric 
24706c3fb27SDimitry Andric   bool isNe() const { return IsNe; }
24806c3fb27SDimitry Andric 
24906c3fb27SDimitry Andric   /// Check if the current constraint is implied by the given ConstraintSystem.
25006c3fb27SDimitry Andric   ///
25106c3fb27SDimitry Andric   /// \return true or false if the constraint is proven to be respectively true,
25206c3fb27SDimitry Andric   /// or false. When the constraint cannot be proven to be either true or false,
25306c3fb27SDimitry Andric   /// std::nullopt is returned.
25406c3fb27SDimitry Andric   std::optional<bool> isImpliedBy(const ConstraintSystem &CS) const;
25506c3fb27SDimitry Andric 
25606c3fb27SDimitry Andric private:
25706c3fb27SDimitry Andric   bool IsEq = false;
25806c3fb27SDimitry Andric   bool IsNe = false;
25981ad6265SDimitry Andric };
26081ad6265SDimitry Andric 
26181ad6265SDimitry Andric /// Wrapper encapsulating separate constraint systems and corresponding value
26281ad6265SDimitry Andric /// mappings for both unsigned and signed information. Facts are added to and
26381ad6265SDimitry Andric /// conditions are checked against the corresponding system depending on the
26481ad6265SDimitry Andric /// signed-ness of their predicates. While the information is kept separate
26581ad6265SDimitry Andric /// based on signed-ness, certain conditions can be transferred between the two
26681ad6265SDimitry Andric /// systems.
26781ad6265SDimitry Andric class ConstraintInfo {
26881ad6265SDimitry Andric 
26981ad6265SDimitry Andric   ConstraintSystem UnsignedCS;
27081ad6265SDimitry Andric   ConstraintSystem SignedCS;
27181ad6265SDimitry Andric 
272bdd1243dSDimitry Andric   const DataLayout &DL;
273bdd1243dSDimitry Andric 
27481ad6265SDimitry Andric public:
27506c3fb27SDimitry Andric   ConstraintInfo(const DataLayout &DL, ArrayRef<Value *> FunctionArgs)
27606c3fb27SDimitry Andric       : UnsignedCS(FunctionArgs), SignedCS(FunctionArgs), DL(DL) {}
277bdd1243dSDimitry Andric 
27881ad6265SDimitry Andric   DenseMap<Value *, unsigned> &getValue2Index(bool Signed) {
27906c3fb27SDimitry Andric     return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
28081ad6265SDimitry Andric   }
28181ad6265SDimitry Andric   const DenseMap<Value *, unsigned> &getValue2Index(bool Signed) const {
28206c3fb27SDimitry Andric     return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
28381ad6265SDimitry Andric   }
28481ad6265SDimitry Andric 
28581ad6265SDimitry Andric   ConstraintSystem &getCS(bool Signed) {
28681ad6265SDimitry Andric     return Signed ? SignedCS : UnsignedCS;
28781ad6265SDimitry Andric   }
28881ad6265SDimitry Andric   const ConstraintSystem &getCS(bool Signed) const {
28981ad6265SDimitry Andric     return Signed ? SignedCS : UnsignedCS;
29081ad6265SDimitry Andric   }
29181ad6265SDimitry Andric 
29281ad6265SDimitry Andric   void popLastConstraint(bool Signed) { getCS(Signed).popLastConstraint(); }
29381ad6265SDimitry Andric   void popLastNVariables(bool Signed, unsigned N) {
29481ad6265SDimitry Andric     getCS(Signed).popLastNVariables(N);
29581ad6265SDimitry Andric   }
29681ad6265SDimitry Andric 
29781ad6265SDimitry Andric   bool doesHold(CmpInst::Predicate Pred, Value *A, Value *B) const;
29881ad6265SDimitry Andric 
299bdd1243dSDimitry Andric   void addFact(CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn,
300bdd1243dSDimitry Andric                unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack);
30181ad6265SDimitry Andric 
30281ad6265SDimitry Andric   /// Turn a comparison of the form \p Op0 \p Pred \p Op1 into a vector of
30381ad6265SDimitry Andric   /// constraints, using indices from the corresponding constraint system.
304bdd1243dSDimitry Andric   /// New variables that need to be added to the system are collected in
305bdd1243dSDimitry Andric   /// \p NewVariables.
30681ad6265SDimitry Andric   ConstraintTy getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
307bdd1243dSDimitry Andric                              SmallVectorImpl<Value *> &NewVariables) const;
30881ad6265SDimitry Andric 
309bdd1243dSDimitry Andric   /// Turns a comparison of the form \p Op0 \p Pred \p Op1 into a vector of
310bdd1243dSDimitry Andric   /// constraints using getConstraint. Returns an empty constraint if the result
311bdd1243dSDimitry Andric   /// cannot be used to query the existing constraint system, e.g. because it
312bdd1243dSDimitry Andric   /// would require adding new variables. Also tries to convert signed
313bdd1243dSDimitry Andric   /// predicates to unsigned ones if possible to allow using the unsigned system
314bdd1243dSDimitry Andric   /// which increases the effectiveness of the signed <-> unsigned transfer
315bdd1243dSDimitry Andric   /// logic.
316bdd1243dSDimitry Andric   ConstraintTy getConstraintForSolving(CmpInst::Predicate Pred, Value *Op0,
317bdd1243dSDimitry Andric                                        Value *Op1) const;
31881ad6265SDimitry Andric 
31981ad6265SDimitry Andric   /// Try to add information from \p A \p Pred \p B to the unsigned/signed
32081ad6265SDimitry Andric   /// system if \p Pred is signed/unsigned.
32181ad6265SDimitry Andric   void transferToOtherSystem(CmpInst::Predicate Pred, Value *A, Value *B,
322bdd1243dSDimitry Andric                              unsigned NumIn, unsigned NumOut,
32381ad6265SDimitry Andric                              SmallVectorImpl<StackEntry> &DFSInStack);
32404eeddc0SDimitry Andric };
32504eeddc0SDimitry Andric 
326bdd1243dSDimitry Andric /// Represents a (Coefficient * Variable) entry after IR decomposition.
327bdd1243dSDimitry Andric struct DecompEntry {
328bdd1243dSDimitry Andric   int64_t Coefficient;
329bdd1243dSDimitry Andric   Value *Variable;
330bdd1243dSDimitry Andric   /// True if the variable is known positive in the current constraint.
331bdd1243dSDimitry Andric   bool IsKnownNonNegative;
332bdd1243dSDimitry Andric 
333bdd1243dSDimitry Andric   DecompEntry(int64_t Coefficient, Value *Variable,
334bdd1243dSDimitry Andric               bool IsKnownNonNegative = false)
335bdd1243dSDimitry Andric       : Coefficient(Coefficient), Variable(Variable),
336bdd1243dSDimitry Andric         IsKnownNonNegative(IsKnownNonNegative) {}
337bdd1243dSDimitry Andric };
338bdd1243dSDimitry Andric 
339bdd1243dSDimitry Andric /// Represents an Offset + Coefficient1 * Variable1 + ... decomposition.
340bdd1243dSDimitry Andric struct Decomposition {
341bdd1243dSDimitry Andric   int64_t Offset = 0;
342bdd1243dSDimitry Andric   SmallVector<DecompEntry, 3> Vars;
343bdd1243dSDimitry Andric 
344bdd1243dSDimitry Andric   Decomposition(int64_t Offset) : Offset(Offset) {}
345bdd1243dSDimitry Andric   Decomposition(Value *V, bool IsKnownNonNegative = false) {
346bdd1243dSDimitry Andric     Vars.emplace_back(1, V, IsKnownNonNegative);
347bdd1243dSDimitry Andric   }
348bdd1243dSDimitry Andric   Decomposition(int64_t Offset, ArrayRef<DecompEntry> Vars)
349bdd1243dSDimitry Andric       : Offset(Offset), Vars(Vars) {}
350bdd1243dSDimitry Andric 
351bdd1243dSDimitry Andric   void add(int64_t OtherOffset) {
352bdd1243dSDimitry Andric     Offset = addWithOverflow(Offset, OtherOffset);
353bdd1243dSDimitry Andric   }
354bdd1243dSDimitry Andric 
355bdd1243dSDimitry Andric   void add(const Decomposition &Other) {
356bdd1243dSDimitry Andric     add(Other.Offset);
357bdd1243dSDimitry Andric     append_range(Vars, Other.Vars);
358bdd1243dSDimitry Andric   }
359bdd1243dSDimitry Andric 
360bdd1243dSDimitry Andric   void mul(int64_t Factor) {
361bdd1243dSDimitry Andric     Offset = multiplyWithOverflow(Offset, Factor);
362bdd1243dSDimitry Andric     for (auto &Var : Vars)
363bdd1243dSDimitry Andric       Var.Coefficient = multiplyWithOverflow(Var.Coefficient, Factor);
364bdd1243dSDimitry Andric   }
365bdd1243dSDimitry Andric };
366bdd1243dSDimitry Andric 
367*5f757f3fSDimitry Andric // Variable and constant offsets for a chain of GEPs, with base pointer BasePtr.
368*5f757f3fSDimitry Andric struct OffsetResult {
369*5f757f3fSDimitry Andric   Value *BasePtr;
370*5f757f3fSDimitry Andric   APInt ConstantOffset;
371*5f757f3fSDimitry Andric   MapVector<Value *, APInt> VariableOffsets;
372*5f757f3fSDimitry Andric   bool AllInbounds;
373*5f757f3fSDimitry Andric 
374*5f757f3fSDimitry Andric   OffsetResult() : BasePtr(nullptr), ConstantOffset(0, uint64_t(0)) {}
375*5f757f3fSDimitry Andric 
376*5f757f3fSDimitry Andric   OffsetResult(GEPOperator &GEP, const DataLayout &DL)
377*5f757f3fSDimitry Andric       : BasePtr(GEP.getPointerOperand()), AllInbounds(GEP.isInBounds()) {
378*5f757f3fSDimitry Andric     ConstantOffset = APInt(DL.getIndexTypeSizeInBits(BasePtr->getType()), 0);
379*5f757f3fSDimitry Andric   }
380*5f757f3fSDimitry Andric };
38104eeddc0SDimitry Andric } // namespace
38204eeddc0SDimitry Andric 
383*5f757f3fSDimitry Andric // Try to collect variable and constant offsets for \p GEP, partly traversing
384*5f757f3fSDimitry Andric // nested GEPs. Returns an OffsetResult with nullptr as BasePtr of collecting
385*5f757f3fSDimitry Andric // the offset fails.
386*5f757f3fSDimitry Andric static OffsetResult collectOffsets(GEPOperator &GEP, const DataLayout &DL) {
387*5f757f3fSDimitry Andric   OffsetResult Result(GEP, DL);
388*5f757f3fSDimitry Andric   unsigned BitWidth = Result.ConstantOffset.getBitWidth();
389*5f757f3fSDimitry Andric   if (!GEP.collectOffset(DL, BitWidth, Result.VariableOffsets,
390*5f757f3fSDimitry Andric                          Result.ConstantOffset))
391*5f757f3fSDimitry Andric     return {};
392*5f757f3fSDimitry Andric 
393*5f757f3fSDimitry Andric   // If we have a nested GEP, check if we can combine the constant offset of the
394*5f757f3fSDimitry Andric   // inner GEP with the outer GEP.
395*5f757f3fSDimitry Andric   if (auto *InnerGEP = dyn_cast<GetElementPtrInst>(Result.BasePtr)) {
396*5f757f3fSDimitry Andric     MapVector<Value *, APInt> VariableOffsets2;
397*5f757f3fSDimitry Andric     APInt ConstantOffset2(BitWidth, 0);
398*5f757f3fSDimitry Andric     bool CanCollectInner = InnerGEP->collectOffset(
399*5f757f3fSDimitry Andric         DL, BitWidth, VariableOffsets2, ConstantOffset2);
400*5f757f3fSDimitry Andric     // TODO: Support cases with more than 1 variable offset.
401*5f757f3fSDimitry Andric     if (!CanCollectInner || Result.VariableOffsets.size() > 1 ||
402*5f757f3fSDimitry Andric         VariableOffsets2.size() > 1 ||
403*5f757f3fSDimitry Andric         (Result.VariableOffsets.size() >= 1 && VariableOffsets2.size() >= 1)) {
404*5f757f3fSDimitry Andric       // More than 1 variable index, use outer result.
405*5f757f3fSDimitry Andric       return Result;
406*5f757f3fSDimitry Andric     }
407*5f757f3fSDimitry Andric     Result.BasePtr = InnerGEP->getPointerOperand();
408*5f757f3fSDimitry Andric     Result.ConstantOffset += ConstantOffset2;
409*5f757f3fSDimitry Andric     if (Result.VariableOffsets.size() == 0 && VariableOffsets2.size() == 1)
410*5f757f3fSDimitry Andric       Result.VariableOffsets = VariableOffsets2;
411*5f757f3fSDimitry Andric     Result.AllInbounds &= InnerGEP->isInBounds();
412*5f757f3fSDimitry Andric   }
413*5f757f3fSDimitry Andric   return Result;
414*5f757f3fSDimitry Andric }
415*5f757f3fSDimitry Andric 
416bdd1243dSDimitry Andric static Decomposition decompose(Value *V,
417*5f757f3fSDimitry Andric                                SmallVectorImpl<ConditionTy> &Preconditions,
418bdd1243dSDimitry Andric                                bool IsSigned, const DataLayout &DL);
41981ad6265SDimitry Andric 
420bdd1243dSDimitry Andric static bool canUseSExt(ConstantInt *CI) {
42181ad6265SDimitry Andric   const APInt &Val = CI->getValue();
42281ad6265SDimitry Andric   return Val.sgt(MinSignedConstraintValue) && Val.slt(MaxConstraintValue);
423bdd1243dSDimitry Andric }
424bdd1243dSDimitry Andric 
425*5f757f3fSDimitry Andric static Decomposition decomposeGEP(GEPOperator &GEP,
426*5f757f3fSDimitry Andric                                   SmallVectorImpl<ConditionTy> &Preconditions,
42706c3fb27SDimitry Andric                                   bool IsSigned, const DataLayout &DL) {
428bdd1243dSDimitry Andric   // Do not reason about pointers where the index size is larger than 64 bits,
429bdd1243dSDimitry Andric   // as the coefficients used to encode constraints are 64 bit integers.
430bdd1243dSDimitry Andric   if (DL.getIndexTypeSizeInBits(GEP.getPointerOperand()->getType()) > 64)
431bdd1243dSDimitry Andric     return &GEP;
432bdd1243dSDimitry Andric 
433bdd1243dSDimitry Andric   assert(!IsSigned && "The logic below only supports decomposition for "
434*5f757f3fSDimitry Andric                       "unsigned predicates at the moment.");
435*5f757f3fSDimitry Andric   const auto &[BasePtr, ConstantOffset, VariableOffsets, AllInbounds] =
436*5f757f3fSDimitry Andric       collectOffsets(GEP, DL);
437*5f757f3fSDimitry Andric   if (!BasePtr || !AllInbounds)
438bdd1243dSDimitry Andric     return &GEP;
439bdd1243dSDimitry Andric 
440*5f757f3fSDimitry Andric   Decomposition Result(ConstantOffset.getSExtValue(), DecompEntry(1, BasePtr));
441bdd1243dSDimitry Andric   for (auto [Index, Scale] : VariableOffsets) {
442bdd1243dSDimitry Andric     auto IdxResult = decompose(Index, Preconditions, IsSigned, DL);
443bdd1243dSDimitry Andric     IdxResult.mul(Scale.getSExtValue());
444bdd1243dSDimitry Andric     Result.add(IdxResult);
445bdd1243dSDimitry Andric 
446bdd1243dSDimitry Andric     // If Op0 is signed non-negative, the GEP is increasing monotonically and
447bdd1243dSDimitry Andric     // can be de-composed.
448bdd1243dSDimitry Andric     if (!isKnownNonNegative(Index, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
449bdd1243dSDimitry Andric       Preconditions.emplace_back(CmpInst::ICMP_SGE, Index,
450bdd1243dSDimitry Andric                                  ConstantInt::get(Index->getType(), 0));
451bdd1243dSDimitry Andric   }
452bdd1243dSDimitry Andric   return Result;
453bdd1243dSDimitry Andric }
454bdd1243dSDimitry Andric 
455bdd1243dSDimitry Andric // Decomposes \p V into a constant offset + list of pairs { Coefficient,
456bdd1243dSDimitry Andric // Variable } where Coefficient * Variable. The sum of the constant offset and
457bdd1243dSDimitry Andric // pairs equals \p V.
458bdd1243dSDimitry Andric static Decomposition decompose(Value *V,
459*5f757f3fSDimitry Andric                                SmallVectorImpl<ConditionTy> &Preconditions,
460bdd1243dSDimitry Andric                                bool IsSigned, const DataLayout &DL) {
461bdd1243dSDimitry Andric 
462bdd1243dSDimitry Andric   auto MergeResults = [&Preconditions, IsSigned, &DL](Value *A, Value *B,
463bdd1243dSDimitry Andric                                                       bool IsSignedB) {
464bdd1243dSDimitry Andric     auto ResA = decompose(A, Preconditions, IsSigned, DL);
465bdd1243dSDimitry Andric     auto ResB = decompose(B, Preconditions, IsSignedB, DL);
466bdd1243dSDimitry Andric     ResA.add(ResB);
467bdd1243dSDimitry Andric     return ResA;
46881ad6265SDimitry Andric   };
469bdd1243dSDimitry Andric 
470b121cb00SDimitry Andric   Type *Ty = V->getType()->getScalarType();
471b121cb00SDimitry Andric   if (Ty->isPointerTy() && !IsSigned) {
472b121cb00SDimitry Andric     if (auto *GEP = dyn_cast<GEPOperator>(V))
473b121cb00SDimitry Andric       return decomposeGEP(*GEP, Preconditions, IsSigned, DL);
474*5f757f3fSDimitry Andric     if (isa<ConstantPointerNull>(V))
475*5f757f3fSDimitry Andric       return int64_t(0);
476*5f757f3fSDimitry Andric 
477b121cb00SDimitry Andric     return V;
478b121cb00SDimitry Andric   }
479b121cb00SDimitry Andric 
480b121cb00SDimitry Andric   // Don't handle integers > 64 bit. Our coefficients are 64-bit large, so
481b121cb00SDimitry Andric   // coefficient add/mul may wrap, while the operation in the full bit width
482b121cb00SDimitry Andric   // would not.
483b121cb00SDimitry Andric   if (!Ty->isIntegerTy() || Ty->getIntegerBitWidth() > 64)
484b121cb00SDimitry Andric     return V;
485b121cb00SDimitry Andric 
48681ad6265SDimitry Andric   // Decompose \p V used with a signed predicate.
48781ad6265SDimitry Andric   if (IsSigned) {
488e8d8bef9SDimitry Andric     if (auto *CI = dyn_cast<ConstantInt>(V)) {
489bdd1243dSDimitry Andric       if (canUseSExt(CI))
490bdd1243dSDimitry Andric         return CI->getSExtValue();
491e8d8bef9SDimitry Andric     }
492bdd1243dSDimitry Andric     Value *Op0;
493bdd1243dSDimitry Andric     Value *Op1;
494bdd1243dSDimitry Andric     if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1))))
495bdd1243dSDimitry Andric       return MergeResults(Op0, Op1, IsSigned);
49681ad6265SDimitry Andric 
49706c3fb27SDimitry Andric     ConstantInt *CI;
4988a4dda33SDimitry Andric     if (match(V, m_NSWMul(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI)) {
49906c3fb27SDimitry Andric       auto Result = decompose(Op0, Preconditions, IsSigned, DL);
50006c3fb27SDimitry Andric       Result.mul(CI->getSExtValue());
50106c3fb27SDimitry Andric       return Result;
50206c3fb27SDimitry Andric     }
50306c3fb27SDimitry Andric 
504bdd1243dSDimitry Andric     return V;
50581ad6265SDimitry Andric   }
50681ad6265SDimitry Andric 
50781ad6265SDimitry Andric   if (auto *CI = dyn_cast<ConstantInt>(V)) {
50881ad6265SDimitry Andric     if (CI->uge(MaxConstraintValue))
509bdd1243dSDimitry Andric       return V;
510bdd1243dSDimitry Andric     return int64_t(CI->getZExtValue());
511fe6060f1SDimitry Andric   }
512fe6060f1SDimitry Andric 
513e8d8bef9SDimitry Andric   Value *Op0;
514bdd1243dSDimitry Andric   bool IsKnownNonNegative = false;
515bdd1243dSDimitry Andric   if (match(V, m_ZExt(m_Value(Op0)))) {
516bdd1243dSDimitry Andric     IsKnownNonNegative = true;
517fe6060f1SDimitry Andric     V = Op0;
518bdd1243dSDimitry Andric   }
519fe6060f1SDimitry Andric 
520e8d8bef9SDimitry Andric   Value *Op1;
521e8d8bef9SDimitry Andric   ConstantInt *CI;
522bdd1243dSDimitry Andric   if (match(V, m_NUWAdd(m_Value(Op0), m_Value(Op1)))) {
523bdd1243dSDimitry Andric     return MergeResults(Op0, Op1, IsSigned);
524bdd1243dSDimitry Andric   }
525bdd1243dSDimitry Andric   if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) {
526bdd1243dSDimitry Andric     if (!isKnownNonNegative(Op0, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
527bdd1243dSDimitry Andric       Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,
528bdd1243dSDimitry Andric                                  ConstantInt::get(Op0->getType(), 0));
529bdd1243dSDimitry Andric     if (!isKnownNonNegative(Op1, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
530bdd1243dSDimitry Andric       Preconditions.emplace_back(CmpInst::ICMP_SGE, Op1,
531bdd1243dSDimitry Andric                                  ConstantInt::get(Op1->getType(), 0));
532bdd1243dSDimitry Andric 
533bdd1243dSDimitry Andric     return MergeResults(Op0, Op1, IsSigned);
534bdd1243dSDimitry Andric   }
535bdd1243dSDimitry Andric 
53681ad6265SDimitry Andric   if (match(V, m_Add(m_Value(Op0), m_ConstantInt(CI))) && CI->isNegative() &&
537bdd1243dSDimitry Andric       canUseSExt(CI)) {
53881ad6265SDimitry Andric     Preconditions.emplace_back(
53981ad6265SDimitry Andric         CmpInst::ICMP_UGE, Op0,
54081ad6265SDimitry Andric         ConstantInt::get(Op0->getType(), CI->getSExtValue() * -1));
541bdd1243dSDimitry Andric     return MergeResults(Op0, CI, true);
54281ad6265SDimitry Andric   }
543e8d8bef9SDimitry Andric 
54406c3fb27SDimitry Andric   // Decompose or as an add if there are no common bits between the operands.
545*5f757f3fSDimitry Andric   if (match(V, m_DisjointOr(m_Value(Op0), m_ConstantInt(CI))))
54606c3fb27SDimitry Andric     return MergeResults(Op0, CI, IsSigned);
54706c3fb27SDimitry Andric 
548bdd1243dSDimitry Andric   if (match(V, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI)) {
54906c3fb27SDimitry Andric     if (CI->getSExtValue() < 0 || CI->getSExtValue() >= 64)
55006c3fb27SDimitry Andric       return {V, IsKnownNonNegative};
551bdd1243dSDimitry Andric     auto Result = decompose(Op1, Preconditions, IsSigned, DL);
55206c3fb27SDimitry Andric     Result.mul(int64_t{1} << CI->getSExtValue());
553bdd1243dSDimitry Andric     return Result;
554bdd1243dSDimitry Andric   }
555bdd1243dSDimitry Andric 
556bdd1243dSDimitry Andric   if (match(V, m_NUWMul(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI) &&
557bdd1243dSDimitry Andric       (!CI->isNegative())) {
558bdd1243dSDimitry Andric     auto Result = decompose(Op1, Preconditions, IsSigned, DL);
559bdd1243dSDimitry Andric     Result.mul(CI->getSExtValue());
560bdd1243dSDimitry Andric     return Result;
561bdd1243dSDimitry Andric   }
562bdd1243dSDimitry Andric 
563bdd1243dSDimitry Andric   if (match(V, m_NUWSub(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI))
564bdd1243dSDimitry Andric     return {-1 * CI->getSExtValue(), {{1, Op0}}};
565e8d8bef9SDimitry Andric   if (match(V, m_NUWSub(m_Value(Op0), m_Value(Op1))))
566bdd1243dSDimitry Andric     return {0, {{1, Op0}, {-1, Op1}}};
567e8d8bef9SDimitry Andric 
568bdd1243dSDimitry Andric   return {V, IsKnownNonNegative};
569e8d8bef9SDimitry Andric }
570e8d8bef9SDimitry Andric 
57181ad6265SDimitry Andric ConstraintTy
57281ad6265SDimitry Andric ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
573bdd1243dSDimitry Andric                               SmallVectorImpl<Value *> &NewVariables) const {
574bdd1243dSDimitry Andric   assert(NewVariables.empty() && "NewVariables must be empty when passed in");
57581ad6265SDimitry Andric   bool IsEq = false;
57606c3fb27SDimitry Andric   bool IsNe = false;
57706c3fb27SDimitry Andric 
57881ad6265SDimitry Andric   // Try to convert Pred to one of ULE/SLT/SLE/SLT.
57981ad6265SDimitry Andric   switch (Pred) {
58081ad6265SDimitry Andric   case CmpInst::ICMP_UGT:
58181ad6265SDimitry Andric   case CmpInst::ICMP_UGE:
58281ad6265SDimitry Andric   case CmpInst::ICMP_SGT:
58381ad6265SDimitry Andric   case CmpInst::ICMP_SGE: {
58481ad6265SDimitry Andric     Pred = CmpInst::getSwappedPredicate(Pred);
58581ad6265SDimitry Andric     std::swap(Op0, Op1);
58681ad6265SDimitry Andric     break;
58781ad6265SDimitry Andric   }
58881ad6265SDimitry Andric   case CmpInst::ICMP_EQ:
58981ad6265SDimitry Andric     if (match(Op1, m_Zero())) {
59081ad6265SDimitry Andric       Pred = CmpInst::ICMP_ULE;
59181ad6265SDimitry Andric     } else {
59281ad6265SDimitry Andric       IsEq = true;
59381ad6265SDimitry Andric       Pred = CmpInst::ICMP_ULE;
59481ad6265SDimitry Andric     }
59581ad6265SDimitry Andric     break;
59681ad6265SDimitry Andric   case CmpInst::ICMP_NE:
59706c3fb27SDimitry Andric     if (match(Op1, m_Zero())) {
59881ad6265SDimitry Andric       Pred = CmpInst::getSwappedPredicate(CmpInst::ICMP_UGT);
59981ad6265SDimitry Andric       std::swap(Op0, Op1);
60006c3fb27SDimitry Andric     } else {
60106c3fb27SDimitry Andric       IsNe = true;
60206c3fb27SDimitry Andric       Pred = CmpInst::ICMP_ULE;
60306c3fb27SDimitry Andric     }
60481ad6265SDimitry Andric     break;
60581ad6265SDimitry Andric   default:
60681ad6265SDimitry Andric     break;
60781ad6265SDimitry Andric   }
60881ad6265SDimitry Andric 
60981ad6265SDimitry Andric   if (Pred != CmpInst::ICMP_ULE && Pred != CmpInst::ICMP_ULT &&
61081ad6265SDimitry Andric       Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SLT)
61181ad6265SDimitry Andric     return {};
61281ad6265SDimitry Andric 
613*5f757f3fSDimitry Andric   SmallVector<ConditionTy, 4> Preconditions;
61481ad6265SDimitry Andric   bool IsSigned = CmpInst::isSigned(Pred);
61581ad6265SDimitry Andric   auto &Value2Index = getValue2Index(IsSigned);
61681ad6265SDimitry Andric   auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(),
617bdd1243dSDimitry Andric                         Preconditions, IsSigned, DL);
61881ad6265SDimitry Andric   auto BDec = decompose(Op1->stripPointerCastsSameRepresentation(),
619bdd1243dSDimitry Andric                         Preconditions, IsSigned, DL);
620bdd1243dSDimitry Andric   int64_t Offset1 = ADec.Offset;
621bdd1243dSDimitry Andric   int64_t Offset2 = BDec.Offset;
62281ad6265SDimitry Andric   Offset1 *= -1;
62381ad6265SDimitry Andric 
624bdd1243dSDimitry Andric   auto &VariablesA = ADec.Vars;
625bdd1243dSDimitry Andric   auto &VariablesB = BDec.Vars;
626e8d8bef9SDimitry Andric 
627bdd1243dSDimitry Andric   // First try to look up \p V in Value2Index and NewVariables. Otherwise add a
628bdd1243dSDimitry Andric   // new entry to NewVariables.
629bdd1243dSDimitry Andric   DenseMap<Value *, unsigned> NewIndexMap;
630bdd1243dSDimitry Andric   auto GetOrAddIndex = [&Value2Index, &NewVariables,
631bdd1243dSDimitry Andric                         &NewIndexMap](Value *V) -> unsigned {
632fe6060f1SDimitry Andric     auto V2I = Value2Index.find(V);
633fe6060f1SDimitry Andric     if (V2I != Value2Index.end())
634fe6060f1SDimitry Andric       return V2I->second;
635fe6060f1SDimitry Andric     auto Insert =
636bdd1243dSDimitry Andric         NewIndexMap.insert({V, Value2Index.size() + NewVariables.size() + 1});
637bdd1243dSDimitry Andric     if (Insert.second)
638bdd1243dSDimitry Andric       NewVariables.push_back(V);
639fe6060f1SDimitry Andric     return Insert.first->second;
640e8d8bef9SDimitry Andric   };
641e8d8bef9SDimitry Andric 
642bdd1243dSDimitry Andric   // Make sure all variables have entries in Value2Index or NewVariables.
643bdd1243dSDimitry Andric   for (const auto &KV : concat<DecompEntry>(VariablesA, VariablesB))
644bdd1243dSDimitry Andric     GetOrAddIndex(KV.Variable);
645e8d8bef9SDimitry Andric 
646e8d8bef9SDimitry Andric   // Build result constraint, by first adding all coefficients from A and then
647e8d8bef9SDimitry Andric   // subtracting all coefficients from B.
64881ad6265SDimitry Andric   ConstraintTy Res(
649bdd1243dSDimitry Andric       SmallVector<int64_t, 8>(Value2Index.size() + NewVariables.size() + 1, 0),
65006c3fb27SDimitry Andric       IsSigned, IsEq, IsNe);
651bdd1243dSDimitry Andric   // Collect variables that are known to be positive in all uses in the
652bdd1243dSDimitry Andric   // constraint.
653bdd1243dSDimitry Andric   DenseMap<Value *, bool> KnownNonNegativeVariables;
65481ad6265SDimitry Andric   auto &R = Res.Coefficients;
655bdd1243dSDimitry Andric   for (const auto &KV : VariablesA) {
656bdd1243dSDimitry Andric     R[GetOrAddIndex(KV.Variable)] += KV.Coefficient;
657bdd1243dSDimitry Andric     auto I =
658bdd1243dSDimitry Andric         KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative});
659bdd1243dSDimitry Andric     I.first->second &= KV.IsKnownNonNegative;
660bdd1243dSDimitry Andric   }
661e8d8bef9SDimitry Andric 
662bdd1243dSDimitry Andric   for (const auto &KV : VariablesB) {
66306c3fb27SDimitry Andric     if (SubOverflow(R[GetOrAddIndex(KV.Variable)], KV.Coefficient,
66406c3fb27SDimitry Andric                     R[GetOrAddIndex(KV.Variable)]))
66506c3fb27SDimitry Andric       return {};
666bdd1243dSDimitry Andric     auto I =
667bdd1243dSDimitry Andric         KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative});
668bdd1243dSDimitry Andric     I.first->second &= KV.IsKnownNonNegative;
669bdd1243dSDimitry Andric   }
670e8d8bef9SDimitry Andric 
67181ad6265SDimitry Andric   int64_t OffsetSum;
67281ad6265SDimitry Andric   if (AddOverflow(Offset1, Offset2, OffsetSum))
67381ad6265SDimitry Andric     return {};
67481ad6265SDimitry Andric   if (Pred == (IsSigned ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT))
67581ad6265SDimitry Andric     if (AddOverflow(OffsetSum, int64_t(-1), OffsetSum))
67681ad6265SDimitry Andric       return {};
67781ad6265SDimitry Andric   R[0] = OffsetSum;
67881ad6265SDimitry Andric   Res.Preconditions = std::move(Preconditions);
679bdd1243dSDimitry Andric 
680bdd1243dSDimitry Andric   // Remove any (Coefficient, Variable) entry where the Coefficient is 0 for new
681bdd1243dSDimitry Andric   // variables.
682bdd1243dSDimitry Andric   while (!NewVariables.empty()) {
683bdd1243dSDimitry Andric     int64_t Last = R.back();
684bdd1243dSDimitry Andric     if (Last != 0)
685bdd1243dSDimitry Andric       break;
686bdd1243dSDimitry Andric     R.pop_back();
687bdd1243dSDimitry Andric     Value *RemovedV = NewVariables.pop_back_val();
688bdd1243dSDimitry Andric     NewIndexMap.erase(RemovedV);
689bdd1243dSDimitry Andric   }
690bdd1243dSDimitry Andric 
691bdd1243dSDimitry Andric   // Add extra constraints for variables that are known positive.
692bdd1243dSDimitry Andric   for (auto &KV : KnownNonNegativeVariables) {
69306c3fb27SDimitry Andric     if (!KV.second ||
69406c3fb27SDimitry Andric         (!Value2Index.contains(KV.first) && !NewIndexMap.contains(KV.first)))
695bdd1243dSDimitry Andric       continue;
696bdd1243dSDimitry Andric     SmallVector<int64_t, 8> C(Value2Index.size() + NewVariables.size() + 1, 0);
697bdd1243dSDimitry Andric     C[GetOrAddIndex(KV.first)] = -1;
698bdd1243dSDimitry Andric     Res.ExtraInfo.push_back(C);
699bdd1243dSDimitry Andric   }
70081ad6265SDimitry Andric   return Res;
701e8d8bef9SDimitry Andric }
702e8d8bef9SDimitry Andric 
703bdd1243dSDimitry Andric ConstraintTy ConstraintInfo::getConstraintForSolving(CmpInst::Predicate Pred,
704bdd1243dSDimitry Andric                                                      Value *Op0,
705bdd1243dSDimitry Andric                                                      Value *Op1) const {
706*5f757f3fSDimitry Andric   Constant *NullC = Constant::getNullValue(Op0->getType());
707*5f757f3fSDimitry Andric   // Handle trivially true compares directly to avoid adding V UGE 0 constraints
708*5f757f3fSDimitry Andric   // for all variables in the unsigned system.
709*5f757f3fSDimitry Andric   if ((Pred == CmpInst::ICMP_ULE && Op0 == NullC) ||
710*5f757f3fSDimitry Andric       (Pred == CmpInst::ICMP_UGE && Op1 == NullC)) {
711*5f757f3fSDimitry Andric     auto &Value2Index = getValue2Index(false);
712*5f757f3fSDimitry Andric     // Return constraint that's trivially true.
713*5f757f3fSDimitry Andric     return ConstraintTy(SmallVector<int64_t, 8>(Value2Index.size(), 0), false,
714*5f757f3fSDimitry Andric                         false, false);
715*5f757f3fSDimitry Andric   }
716*5f757f3fSDimitry Andric 
717bdd1243dSDimitry Andric   // If both operands are known to be non-negative, change signed predicates to
718bdd1243dSDimitry Andric   // unsigned ones. This increases the reasoning effectiveness in combination
719bdd1243dSDimitry Andric   // with the signed <-> unsigned transfer logic.
720bdd1243dSDimitry Andric   if (CmpInst::isSigned(Pred) &&
721bdd1243dSDimitry Andric       isKnownNonNegative(Op0, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1) &&
722bdd1243dSDimitry Andric       isKnownNonNegative(Op1, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))
723bdd1243dSDimitry Andric     Pred = CmpInst::getUnsignedPredicate(Pred);
724bdd1243dSDimitry Andric 
725bdd1243dSDimitry Andric   SmallVector<Value *> NewVariables;
726bdd1243dSDimitry Andric   ConstraintTy R = getConstraint(Pred, Op0, Op1, NewVariables);
72706c3fb27SDimitry Andric   if (!NewVariables.empty())
728bdd1243dSDimitry Andric     return {};
729bdd1243dSDimitry Andric   return R;
730bdd1243dSDimitry Andric }
731bdd1243dSDimitry Andric 
73281ad6265SDimitry Andric bool ConstraintTy::isValid(const ConstraintInfo &Info) const {
73381ad6265SDimitry Andric   return Coefficients.size() > 0 &&
734*5f757f3fSDimitry Andric          all_of(Preconditions, [&Info](const ConditionTy &C) {
73581ad6265SDimitry Andric            return Info.doesHold(C.Pred, C.Op0, C.Op1);
73681ad6265SDimitry Andric          });
73781ad6265SDimitry Andric }
73881ad6265SDimitry Andric 
73906c3fb27SDimitry Andric std::optional<bool>
74006c3fb27SDimitry Andric ConstraintTy::isImpliedBy(const ConstraintSystem &CS) const {
74106c3fb27SDimitry Andric   bool IsConditionImplied = CS.isConditionImplied(Coefficients);
74206c3fb27SDimitry Andric 
74306c3fb27SDimitry Andric   if (IsEq || IsNe) {
74406c3fb27SDimitry Andric     auto NegatedOrEqual = ConstraintSystem::negateOrEqual(Coefficients);
74506c3fb27SDimitry Andric     bool IsNegatedOrEqualImplied =
74606c3fb27SDimitry Andric         !NegatedOrEqual.empty() && CS.isConditionImplied(NegatedOrEqual);
74706c3fb27SDimitry Andric 
74806c3fb27SDimitry Andric     // In order to check that `%a == %b` is true (equality), both conditions `%a
74906c3fb27SDimitry Andric     // >= %b` and `%a <= %b` must hold true. When checking for equality (`IsEq`
75006c3fb27SDimitry Andric     // is true), we return true if they both hold, false in the other cases.
75106c3fb27SDimitry Andric     if (IsConditionImplied && IsNegatedOrEqualImplied)
75206c3fb27SDimitry Andric       return IsEq;
75306c3fb27SDimitry Andric 
75406c3fb27SDimitry Andric     auto Negated = ConstraintSystem::negate(Coefficients);
75506c3fb27SDimitry Andric     bool IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated);
75606c3fb27SDimitry Andric 
75706c3fb27SDimitry Andric     auto StrictLessThan = ConstraintSystem::toStrictLessThan(Coefficients);
75806c3fb27SDimitry Andric     bool IsStrictLessThanImplied =
75906c3fb27SDimitry Andric         !StrictLessThan.empty() && CS.isConditionImplied(StrictLessThan);
76006c3fb27SDimitry Andric 
76106c3fb27SDimitry Andric     // In order to check that `%a != %b` is true (non-equality), either
76206c3fb27SDimitry Andric     // condition `%a > %b` or `%a < %b` must hold true. When checking for
76306c3fb27SDimitry Andric     // non-equality (`IsNe` is true), we return true if one of the two holds,
76406c3fb27SDimitry Andric     // false in the other cases.
76506c3fb27SDimitry Andric     if (IsNegatedImplied || IsStrictLessThanImplied)
76606c3fb27SDimitry Andric       return IsNe;
76706c3fb27SDimitry Andric 
76806c3fb27SDimitry Andric     return std::nullopt;
76906c3fb27SDimitry Andric   }
77006c3fb27SDimitry Andric 
77106c3fb27SDimitry Andric   if (IsConditionImplied)
77206c3fb27SDimitry Andric     return true;
77306c3fb27SDimitry Andric 
77406c3fb27SDimitry Andric   auto Negated = ConstraintSystem::negate(Coefficients);
77506c3fb27SDimitry Andric   auto IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated);
77606c3fb27SDimitry Andric   if (IsNegatedImplied)
77706c3fb27SDimitry Andric     return false;
77806c3fb27SDimitry Andric 
77906c3fb27SDimitry Andric   // Neither the condition nor its negated holds, did not prove anything.
78006c3fb27SDimitry Andric   return std::nullopt;
78106c3fb27SDimitry Andric }
78206c3fb27SDimitry Andric 
78381ad6265SDimitry Andric bool ConstraintInfo::doesHold(CmpInst::Predicate Pred, Value *A,
78481ad6265SDimitry Andric                               Value *B) const {
785bdd1243dSDimitry Andric   auto R = getConstraintForSolving(Pred, A, B);
78606c3fb27SDimitry Andric   return R.isValid(*this) &&
787bdd1243dSDimitry Andric          getCS(R.IsSigned).isConditionImplied(R.Coefficients);
78881ad6265SDimitry Andric }
78981ad6265SDimitry Andric 
79081ad6265SDimitry Andric void ConstraintInfo::transferToOtherSystem(
791bdd1243dSDimitry Andric     CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn,
79281ad6265SDimitry Andric     unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack) {
793*5f757f3fSDimitry Andric   auto IsKnownNonNegative = [this](Value *V) {
794*5f757f3fSDimitry Andric     return doesHold(CmpInst::ICMP_SGE, V, ConstantInt::get(V->getType(), 0)) ||
795*5f757f3fSDimitry Andric            isKnownNonNegative(V, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1);
796*5f757f3fSDimitry Andric   };
79781ad6265SDimitry Andric   // Check if we can combine facts from the signed and unsigned systems to
79881ad6265SDimitry Andric   // derive additional facts.
79981ad6265SDimitry Andric   if (!A->getType()->isIntegerTy())
80081ad6265SDimitry Andric     return;
80181ad6265SDimitry Andric   // FIXME: This currently depends on the order we add facts. Ideally we
80281ad6265SDimitry Andric   // would first add all known facts and only then try to add additional
80381ad6265SDimitry Andric   // facts.
80481ad6265SDimitry Andric   switch (Pred) {
80581ad6265SDimitry Andric   default:
80681ad6265SDimitry Andric     break;
80781ad6265SDimitry Andric   case CmpInst::ICMP_ULT:
808*5f757f3fSDimitry Andric   case CmpInst::ICMP_ULE:
809*5f757f3fSDimitry Andric     //  If B is a signed positive constant, then A >=s 0 and A <s (or <=s) B.
810*5f757f3fSDimitry Andric     if (IsKnownNonNegative(B)) {
811bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_SGE, A, ConstantInt::get(B->getType(), 0), NumIn,
812bdd1243dSDimitry Andric               NumOut, DFSInStack);
813*5f757f3fSDimitry Andric       addFact(CmpInst::getSignedPredicate(Pred), A, B, NumIn, NumOut,
814*5f757f3fSDimitry Andric               DFSInStack);
815*5f757f3fSDimitry Andric     }
816*5f757f3fSDimitry Andric     break;
817*5f757f3fSDimitry Andric   case CmpInst::ICMP_UGE:
818*5f757f3fSDimitry Andric   case CmpInst::ICMP_UGT:
819*5f757f3fSDimitry Andric     //  If A is a signed positive constant, then B >=s 0 and A >s (or >=s) B.
820*5f757f3fSDimitry Andric     if (IsKnownNonNegative(A)) {
821*5f757f3fSDimitry Andric       addFact(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0), NumIn,
822*5f757f3fSDimitry Andric               NumOut, DFSInStack);
823*5f757f3fSDimitry Andric       addFact(CmpInst::getSignedPredicate(Pred), A, B, NumIn, NumOut,
824*5f757f3fSDimitry Andric               DFSInStack);
82581ad6265SDimitry Andric     }
82681ad6265SDimitry Andric     break;
82781ad6265SDimitry Andric   case CmpInst::ICMP_SLT:
828*5f757f3fSDimitry Andric     if (IsKnownNonNegative(A))
829bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_ULT, A, B, NumIn, NumOut, DFSInStack);
83081ad6265SDimitry Andric     break;
83106c3fb27SDimitry Andric   case CmpInst::ICMP_SGT: {
83281ad6265SDimitry Andric     if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), -1)))
833bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_UGE, A, ConstantInt::get(B->getType(), 0), NumIn,
834bdd1243dSDimitry Andric               NumOut, DFSInStack);
835*5f757f3fSDimitry Andric     if (IsKnownNonNegative(B))
83606c3fb27SDimitry Andric       addFact(CmpInst::ICMP_UGT, A, B, NumIn, NumOut, DFSInStack);
83706c3fb27SDimitry Andric 
83881ad6265SDimitry Andric     break;
83906c3fb27SDimitry Andric   }
84081ad6265SDimitry Andric   case CmpInst::ICMP_SGE:
841*5f757f3fSDimitry Andric     if (IsKnownNonNegative(B))
842bdd1243dSDimitry Andric       addFact(CmpInst::ICMP_UGE, A, B, NumIn, NumOut, DFSInStack);
84381ad6265SDimitry Andric     break;
84481ad6265SDimitry Andric   }
845e8d8bef9SDimitry Andric }
846e8d8bef9SDimitry Andric 
847fe6060f1SDimitry Andric #ifndef NDEBUG
84881ad6265SDimitry Andric 
84906c3fb27SDimitry Andric static void dumpConstraint(ArrayRef<int64_t> C,
85006c3fb27SDimitry Andric                            const DenseMap<Value *, unsigned> &Value2Index) {
85106c3fb27SDimitry Andric   ConstraintSystem CS(Value2Index);
85281ad6265SDimitry Andric   CS.addVariableRowFill(C);
85306c3fb27SDimitry Andric   CS.dump();
85481ad6265SDimitry Andric }
855fe6060f1SDimitry Andric #endif
856fe6060f1SDimitry Andric 
857*5f757f3fSDimitry Andric void State::addInfoForInductions(BasicBlock &BB) {
858*5f757f3fSDimitry Andric   auto *L = LI.getLoopFor(&BB);
859*5f757f3fSDimitry Andric   if (!L || L->getHeader() != &BB)
860*5f757f3fSDimitry Andric     return;
861*5f757f3fSDimitry Andric 
862*5f757f3fSDimitry Andric   Value *A;
863*5f757f3fSDimitry Andric   Value *B;
864*5f757f3fSDimitry Andric   CmpInst::Predicate Pred;
865*5f757f3fSDimitry Andric 
866*5f757f3fSDimitry Andric   if (!match(BB.getTerminator(),
867*5f757f3fSDimitry Andric              m_Br(m_ICmp(Pred, m_Value(A), m_Value(B)), m_Value(), m_Value())))
868*5f757f3fSDimitry Andric     return;
869*5f757f3fSDimitry Andric   PHINode *PN = dyn_cast<PHINode>(A);
870*5f757f3fSDimitry Andric   if (!PN) {
871*5f757f3fSDimitry Andric     Pred = CmpInst::getSwappedPredicate(Pred);
872*5f757f3fSDimitry Andric     std::swap(A, B);
873*5f757f3fSDimitry Andric     PN = dyn_cast<PHINode>(A);
874*5f757f3fSDimitry Andric   }
875*5f757f3fSDimitry Andric 
876*5f757f3fSDimitry Andric   if (!PN || PN->getParent() != &BB || PN->getNumIncomingValues() != 2 ||
877*5f757f3fSDimitry Andric       !SE.isSCEVable(PN->getType()))
878*5f757f3fSDimitry Andric     return;
879*5f757f3fSDimitry Andric 
880*5f757f3fSDimitry Andric   BasicBlock *InLoopSucc = nullptr;
881*5f757f3fSDimitry Andric   if (Pred == CmpInst::ICMP_NE)
882*5f757f3fSDimitry Andric     InLoopSucc = cast<BranchInst>(BB.getTerminator())->getSuccessor(0);
883*5f757f3fSDimitry Andric   else if (Pred == CmpInst::ICMP_EQ)
884*5f757f3fSDimitry Andric     InLoopSucc = cast<BranchInst>(BB.getTerminator())->getSuccessor(1);
885*5f757f3fSDimitry Andric   else
886*5f757f3fSDimitry Andric     return;
887*5f757f3fSDimitry Andric 
888*5f757f3fSDimitry Andric   if (!L->contains(InLoopSucc) || !L->isLoopExiting(&BB) || InLoopSucc == &BB)
889*5f757f3fSDimitry Andric     return;
890*5f757f3fSDimitry Andric 
891*5f757f3fSDimitry Andric   auto *AR = dyn_cast_or_null<SCEVAddRecExpr>(SE.getSCEV(PN));
892*5f757f3fSDimitry Andric   BasicBlock *LoopPred = L->getLoopPredecessor();
893*5f757f3fSDimitry Andric   if (!AR || AR->getLoop() != L || !LoopPred)
894*5f757f3fSDimitry Andric     return;
895*5f757f3fSDimitry Andric 
896*5f757f3fSDimitry Andric   const SCEV *StartSCEV = AR->getStart();
897*5f757f3fSDimitry Andric   Value *StartValue = nullptr;
898*5f757f3fSDimitry Andric   if (auto *C = dyn_cast<SCEVConstant>(StartSCEV)) {
899*5f757f3fSDimitry Andric     StartValue = C->getValue();
900*5f757f3fSDimitry Andric   } else {
901*5f757f3fSDimitry Andric     StartValue = PN->getIncomingValueForBlock(LoopPred);
902*5f757f3fSDimitry Andric     assert(SE.getSCEV(StartValue) == StartSCEV && "inconsistent start value");
903*5f757f3fSDimitry Andric   }
904*5f757f3fSDimitry Andric 
905*5f757f3fSDimitry Andric   DomTreeNode *DTN = DT.getNode(InLoopSucc);
906*5f757f3fSDimitry Andric   auto Inc = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_UGT);
907*5f757f3fSDimitry Andric   bool MonotonicallyIncreasing =
908*5f757f3fSDimitry Andric       Inc && *Inc == ScalarEvolution::MonotonicallyIncreasing;
909*5f757f3fSDimitry Andric   if (MonotonicallyIncreasing) {
910*5f757f3fSDimitry Andric     // SCEV guarantees that AR does not wrap, so PN >= StartValue can be added
911*5f757f3fSDimitry Andric     // unconditionally.
912*5f757f3fSDimitry Andric     WorkList.push_back(
913*5f757f3fSDimitry Andric         FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_UGE, PN, StartValue));
914*5f757f3fSDimitry Andric   }
915*5f757f3fSDimitry Andric 
916*5f757f3fSDimitry Andric   APInt StepOffset;
917*5f757f3fSDimitry Andric   if (auto *C = dyn_cast<SCEVConstant>(AR->getStepRecurrence(SE)))
918*5f757f3fSDimitry Andric     StepOffset = C->getAPInt();
919*5f757f3fSDimitry Andric   else
920*5f757f3fSDimitry Andric     return;
921*5f757f3fSDimitry Andric 
922*5f757f3fSDimitry Andric   // Make sure the bound B is loop-invariant.
923*5f757f3fSDimitry Andric   if (!L->isLoopInvariant(B))
924*5f757f3fSDimitry Andric     return;
925*5f757f3fSDimitry Andric 
926*5f757f3fSDimitry Andric   // Handle negative steps.
927*5f757f3fSDimitry Andric   if (StepOffset.isNegative()) {
928*5f757f3fSDimitry Andric     // TODO: Extend to allow steps > -1.
929*5f757f3fSDimitry Andric     if (!(-StepOffset).isOne())
930*5f757f3fSDimitry Andric       return;
931*5f757f3fSDimitry Andric 
932*5f757f3fSDimitry Andric     // AR may wrap.
933*5f757f3fSDimitry Andric     // Add StartValue >= PN conditional on B <= StartValue which guarantees that
934*5f757f3fSDimitry Andric     // the loop exits before wrapping with a step of -1.
935*5f757f3fSDimitry Andric     WorkList.push_back(FactOrCheck::getConditionFact(
936*5f757f3fSDimitry Andric         DTN, CmpInst::ICMP_UGE, StartValue, PN,
937*5f757f3fSDimitry Andric         ConditionTy(CmpInst::ICMP_ULE, B, StartValue)));
938*5f757f3fSDimitry Andric     // Add PN > B conditional on B <= StartValue which guarantees that the loop
939*5f757f3fSDimitry Andric     // exits when reaching B with a step of -1.
940*5f757f3fSDimitry Andric     WorkList.push_back(FactOrCheck::getConditionFact(
941*5f757f3fSDimitry Andric         DTN, CmpInst::ICMP_UGT, PN, B,
942*5f757f3fSDimitry Andric         ConditionTy(CmpInst::ICMP_ULE, B, StartValue)));
943*5f757f3fSDimitry Andric     return;
944*5f757f3fSDimitry Andric   }
945*5f757f3fSDimitry Andric 
946*5f757f3fSDimitry Andric   // Make sure AR either steps by 1 or that the value we compare against is a
947*5f757f3fSDimitry Andric   // GEP based on the same start value and all offsets are a multiple of the
948*5f757f3fSDimitry Andric   // step size, to guarantee that the induction will reach the value.
949*5f757f3fSDimitry Andric   if (StepOffset.isZero() || StepOffset.isNegative())
950*5f757f3fSDimitry Andric     return;
951*5f757f3fSDimitry Andric 
952*5f757f3fSDimitry Andric   if (!StepOffset.isOne()) {
953*5f757f3fSDimitry Andric     auto *UpperGEP = dyn_cast<GetElementPtrInst>(B);
954*5f757f3fSDimitry Andric     if (!UpperGEP || UpperGEP->getPointerOperand() != StartValue ||
955*5f757f3fSDimitry Andric         !UpperGEP->isInBounds())
956*5f757f3fSDimitry Andric       return;
957*5f757f3fSDimitry Andric 
958*5f757f3fSDimitry Andric     MapVector<Value *, APInt> UpperVariableOffsets;
959*5f757f3fSDimitry Andric     APInt UpperConstantOffset(StepOffset.getBitWidth(), 0);
960*5f757f3fSDimitry Andric     const DataLayout &DL = BB.getModule()->getDataLayout();
961*5f757f3fSDimitry Andric     if (!UpperGEP->collectOffset(DL, StepOffset.getBitWidth(),
962*5f757f3fSDimitry Andric                                  UpperVariableOffsets, UpperConstantOffset))
963*5f757f3fSDimitry Andric       return;
964*5f757f3fSDimitry Andric     // All variable offsets and the constant offset have to be a multiple of the
965*5f757f3fSDimitry Andric     // step.
966*5f757f3fSDimitry Andric     if (!UpperConstantOffset.urem(StepOffset).isZero() ||
967*5f757f3fSDimitry Andric         any_of(UpperVariableOffsets, [&StepOffset](const auto &P) {
968*5f757f3fSDimitry Andric           return !P.second.urem(StepOffset).isZero();
969*5f757f3fSDimitry Andric         }))
970*5f757f3fSDimitry Andric       return;
971*5f757f3fSDimitry Andric   }
972*5f757f3fSDimitry Andric 
973*5f757f3fSDimitry Andric   // AR may wrap. Add PN >= StartValue conditional on StartValue <= B which
974*5f757f3fSDimitry Andric   // guarantees that the loop exits before wrapping in combination with the
975*5f757f3fSDimitry Andric   // restrictions on B and the step above.
976*5f757f3fSDimitry Andric   if (!MonotonicallyIncreasing) {
977*5f757f3fSDimitry Andric     WorkList.push_back(FactOrCheck::getConditionFact(
978*5f757f3fSDimitry Andric         DTN, CmpInst::ICMP_UGE, PN, StartValue,
979*5f757f3fSDimitry Andric         ConditionTy(CmpInst::ICMP_ULE, StartValue, B)));
980*5f757f3fSDimitry Andric   }
981*5f757f3fSDimitry Andric   WorkList.push_back(FactOrCheck::getConditionFact(
982*5f757f3fSDimitry Andric       DTN, CmpInst::ICMP_ULT, PN, B,
983*5f757f3fSDimitry Andric       ConditionTy(CmpInst::ICMP_ULE, StartValue, B)));
984*5f757f3fSDimitry Andric }
985*5f757f3fSDimitry Andric 
98681ad6265SDimitry Andric void State::addInfoFor(BasicBlock &BB) {
987*5f757f3fSDimitry Andric   addInfoForInductions(BB);
988*5f757f3fSDimitry Andric 
989349cc55cSDimitry Andric   // True as long as long as the current instruction is guaranteed to execute.
990349cc55cSDimitry Andric   bool GuaranteedToExecute = true;
991bdd1243dSDimitry Andric   // Queue conditions and assumes.
992349cc55cSDimitry Andric   for (Instruction &I : BB) {
993bdd1243dSDimitry Andric     if (auto Cmp = dyn_cast<ICmpInst>(&I)) {
99406c3fb27SDimitry Andric       for (Use &U : Cmp->uses()) {
99506c3fb27SDimitry Andric         auto *UserI = getContextInstForUse(U);
99606c3fb27SDimitry Andric         auto *DTN = DT.getNode(UserI->getParent());
99706c3fb27SDimitry Andric         if (!DTN)
99806c3fb27SDimitry Andric           continue;
99906c3fb27SDimitry Andric         WorkList.push_back(FactOrCheck::getCheck(DTN, &U));
100006c3fb27SDimitry Andric       }
1001bdd1243dSDimitry Andric       continue;
1002bdd1243dSDimitry Andric     }
1003bdd1243dSDimitry Andric 
1004bdd1243dSDimitry Andric     if (match(&I, m_Intrinsic<Intrinsic::ssub_with_overflow>())) {
100506c3fb27SDimitry Andric       WorkList.push_back(
100606c3fb27SDimitry Andric           FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));
100706c3fb27SDimitry Andric       continue;
100806c3fb27SDimitry Andric     }
100906c3fb27SDimitry Andric 
101006c3fb27SDimitry Andric     if (isa<MinMaxIntrinsic>(&I)) {
1011*5f757f3fSDimitry Andric       WorkList.push_back(FactOrCheck::getInstFact(DT.getNode(&BB), &I));
1012bdd1243dSDimitry Andric       continue;
1013bdd1243dSDimitry Andric     }
1014bdd1243dSDimitry Andric 
1015*5f757f3fSDimitry Andric     Value *A, *B;
1016*5f757f3fSDimitry Andric     CmpInst::Predicate Pred;
1017349cc55cSDimitry Andric     // For now, just handle assumes with a single compare as condition.
1018*5f757f3fSDimitry Andric     if (match(&I, m_Intrinsic<Intrinsic::assume>(
1019*5f757f3fSDimitry Andric                       m_ICmp(Pred, m_Value(A), m_Value(B))))) {
1020349cc55cSDimitry Andric       if (GuaranteedToExecute) {
1021349cc55cSDimitry Andric         // The assume is guaranteed to execute when BB is entered, hence Cond
1022349cc55cSDimitry Andric         // holds on entry to BB.
1023*5f757f3fSDimitry Andric         WorkList.emplace_back(FactOrCheck::getConditionFact(
1024*5f757f3fSDimitry Andric             DT.getNode(I.getParent()), Pred, A, B));
1025349cc55cSDimitry Andric       } else {
1026bdd1243dSDimitry Andric         WorkList.emplace_back(
1027*5f757f3fSDimitry Andric             FactOrCheck::getInstFact(DT.getNode(I.getParent()), &I));
1028349cc55cSDimitry Andric       }
1029349cc55cSDimitry Andric     }
1030349cc55cSDimitry Andric     GuaranteedToExecute &= isGuaranteedToTransferExecutionToSuccessor(&I);
1031349cc55cSDimitry Andric   }
1032349cc55cSDimitry Andric 
1033*5f757f3fSDimitry Andric   if (auto *Switch = dyn_cast<SwitchInst>(BB.getTerminator())) {
1034*5f757f3fSDimitry Andric     for (auto &Case : Switch->cases()) {
1035*5f757f3fSDimitry Andric       BasicBlock *Succ = Case.getCaseSuccessor();
1036*5f757f3fSDimitry Andric       Value *V = Case.getCaseValue();
1037*5f757f3fSDimitry Andric       if (!canAddSuccessor(BB, Succ))
1038*5f757f3fSDimitry Andric         continue;
1039*5f757f3fSDimitry Andric       WorkList.emplace_back(FactOrCheck::getConditionFact(
1040*5f757f3fSDimitry Andric           DT.getNode(Succ), CmpInst::ICMP_EQ, Switch->getCondition(), V));
1041*5f757f3fSDimitry Andric     }
1042*5f757f3fSDimitry Andric     return;
1043*5f757f3fSDimitry Andric   }
1044*5f757f3fSDimitry Andric 
1045e8d8bef9SDimitry Andric   auto *Br = dyn_cast<BranchInst>(BB.getTerminator());
1046e8d8bef9SDimitry Andric   if (!Br || !Br->isConditional())
104781ad6265SDimitry Andric     return;
1048e8d8bef9SDimitry Andric 
1049bdd1243dSDimitry Andric   Value *Cond = Br->getCondition();
1050e8d8bef9SDimitry Andric 
1051bdd1243dSDimitry Andric   // If the condition is a chain of ORs/AND and the successor only has the
1052bdd1243dSDimitry Andric   // current block as predecessor, queue conditions for the successor.
1053bdd1243dSDimitry Andric   Value *Op0, *Op1;
1054bdd1243dSDimitry Andric   if (match(Cond, m_LogicalOr(m_Value(Op0), m_Value(Op1))) ||
1055bdd1243dSDimitry Andric       match(Cond, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {
1056bdd1243dSDimitry Andric     bool IsOr = match(Cond, m_LogicalOr());
1057bdd1243dSDimitry Andric     bool IsAnd = match(Cond, m_LogicalAnd());
1058bdd1243dSDimitry Andric     // If there's a select that matches both AND and OR, we need to commit to
1059bdd1243dSDimitry Andric     // one of the options. Arbitrarily pick OR.
1060bdd1243dSDimitry Andric     if (IsOr && IsAnd)
1061bdd1243dSDimitry Andric       IsAnd = false;
1062bdd1243dSDimitry Andric 
1063bdd1243dSDimitry Andric     BasicBlock *Successor = Br->getSuccessor(IsOr ? 1 : 0);
1064bdd1243dSDimitry Andric     if (canAddSuccessor(BB, Successor)) {
1065bdd1243dSDimitry Andric       SmallVector<Value *> CondWorkList;
1066bdd1243dSDimitry Andric       SmallPtrSet<Value *, 8> SeenCond;
1067bdd1243dSDimitry Andric       auto QueueValue = [&CondWorkList, &SeenCond](Value *V) {
1068bdd1243dSDimitry Andric         if (SeenCond.insert(V).second)
1069bdd1243dSDimitry Andric           CondWorkList.push_back(V);
1070bdd1243dSDimitry Andric       };
1071bdd1243dSDimitry Andric       QueueValue(Op1);
1072bdd1243dSDimitry Andric       QueueValue(Op0);
1073bdd1243dSDimitry Andric       while (!CondWorkList.empty()) {
1074bdd1243dSDimitry Andric         Value *Cur = CondWorkList.pop_back_val();
1075bdd1243dSDimitry Andric         if (auto *Cmp = dyn_cast<ICmpInst>(Cur)) {
1076*5f757f3fSDimitry Andric           WorkList.emplace_back(FactOrCheck::getConditionFact(
1077*5f757f3fSDimitry Andric               DT.getNode(Successor),
1078*5f757f3fSDimitry Andric               IsOr ? CmpInst::getInversePredicate(Cmp->getPredicate())
1079*5f757f3fSDimitry Andric                    : Cmp->getPredicate(),
1080*5f757f3fSDimitry Andric               Cmp->getOperand(0), Cmp->getOperand(1)));
1081bdd1243dSDimitry Andric           continue;
1082bdd1243dSDimitry Andric         }
1083bdd1243dSDimitry Andric         if (IsOr && match(Cur, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) {
1084bdd1243dSDimitry Andric           QueueValue(Op1);
1085bdd1243dSDimitry Andric           QueueValue(Op0);
1086bdd1243dSDimitry Andric           continue;
1087bdd1243dSDimitry Andric         }
1088bdd1243dSDimitry Andric         if (IsAnd && match(Cur, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {
1089bdd1243dSDimitry Andric           QueueValue(Op1);
1090bdd1243dSDimitry Andric           QueueValue(Op0);
1091bdd1243dSDimitry Andric           continue;
1092bdd1243dSDimitry Andric         }
1093bdd1243dSDimitry Andric       }
1094e8d8bef9SDimitry Andric     }
109581ad6265SDimitry Andric     return;
1096e8d8bef9SDimitry Andric   }
1097e8d8bef9SDimitry Andric 
109881ad6265SDimitry Andric   auto *CmpI = dyn_cast<ICmpInst>(Br->getCondition());
1099e8d8bef9SDimitry Andric   if (!CmpI)
110081ad6265SDimitry Andric     return;
110181ad6265SDimitry Andric   if (canAddSuccessor(BB, Br->getSuccessor(0)))
1102*5f757f3fSDimitry Andric     WorkList.emplace_back(FactOrCheck::getConditionFact(
1103*5f757f3fSDimitry Andric         DT.getNode(Br->getSuccessor(0)), CmpI->getPredicate(),
1104*5f757f3fSDimitry Andric         CmpI->getOperand(0), CmpI->getOperand(1)));
110581ad6265SDimitry Andric   if (canAddSuccessor(BB, Br->getSuccessor(1)))
1106*5f757f3fSDimitry Andric     WorkList.emplace_back(FactOrCheck::getConditionFact(
1107*5f757f3fSDimitry Andric         DT.getNode(Br->getSuccessor(1)),
1108*5f757f3fSDimitry Andric         CmpInst::getInversePredicate(CmpI->getPredicate()), CmpI->getOperand(0),
1109*5f757f3fSDimitry Andric         CmpI->getOperand(1)));
1110bdd1243dSDimitry Andric }
1111bdd1243dSDimitry Andric 
1112*5f757f3fSDimitry Andric #ifndef NDEBUG
1113*5f757f3fSDimitry Andric static void dumpUnpackedICmp(raw_ostream &OS, ICmpInst::Predicate Pred,
1114*5f757f3fSDimitry Andric                              Value *LHS, Value *RHS) {
1115*5f757f3fSDimitry Andric   OS << "icmp " << Pred << ' ';
1116*5f757f3fSDimitry Andric   LHS->printAsOperand(OS, /*PrintType=*/true);
1117*5f757f3fSDimitry Andric   OS << ", ";
1118*5f757f3fSDimitry Andric   RHS->printAsOperand(OS, /*PrintType=*/false);
1119*5f757f3fSDimitry Andric }
1120*5f757f3fSDimitry Andric #endif
1121*5f757f3fSDimitry Andric 
112206c3fb27SDimitry Andric namespace {
112306c3fb27SDimitry Andric /// Helper to keep track of a condition and if it should be treated as negated
112406c3fb27SDimitry Andric /// for reproducer construction.
112506c3fb27SDimitry Andric /// Pred == Predicate::BAD_ICMP_PREDICATE indicates that this entry is a
112606c3fb27SDimitry Andric /// placeholder to keep the ReproducerCondStack in sync with DFSInStack.
112706c3fb27SDimitry Andric struct ReproducerEntry {
112806c3fb27SDimitry Andric   ICmpInst::Predicate Pred;
112906c3fb27SDimitry Andric   Value *LHS;
113006c3fb27SDimitry Andric   Value *RHS;
113106c3fb27SDimitry Andric 
113206c3fb27SDimitry Andric   ReproducerEntry(ICmpInst::Predicate Pred, Value *LHS, Value *RHS)
113306c3fb27SDimitry Andric       : Pred(Pred), LHS(LHS), RHS(RHS) {}
113406c3fb27SDimitry Andric };
113506c3fb27SDimitry Andric } // namespace
113606c3fb27SDimitry Andric 
113706c3fb27SDimitry Andric /// Helper function to generate a reproducer function for simplifying \p Cond.
113806c3fb27SDimitry Andric /// The reproducer function contains a series of @llvm.assume calls, one for
113906c3fb27SDimitry Andric /// each condition in \p Stack. For each condition, the operand instruction are
114006c3fb27SDimitry Andric /// cloned until we reach operands that have an entry in \p Value2Index. Those
114106c3fb27SDimitry Andric /// will then be added as function arguments. \p DT is used to order cloned
114206c3fb27SDimitry Andric /// instructions. The reproducer function will get added to \p M, if it is
114306c3fb27SDimitry Andric /// non-null. Otherwise no reproducer function is generated.
114406c3fb27SDimitry Andric static void generateReproducer(CmpInst *Cond, Module *M,
114506c3fb27SDimitry Andric                                ArrayRef<ReproducerEntry> Stack,
114606c3fb27SDimitry Andric                                ConstraintInfo &Info, DominatorTree &DT) {
114706c3fb27SDimitry Andric   if (!M)
114806c3fb27SDimitry Andric     return;
114906c3fb27SDimitry Andric 
115006c3fb27SDimitry Andric   LLVMContext &Ctx = Cond->getContext();
115106c3fb27SDimitry Andric 
115206c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "Creating reproducer for " << *Cond << "\n");
115306c3fb27SDimitry Andric 
115406c3fb27SDimitry Andric   ValueToValueMapTy Old2New;
115506c3fb27SDimitry Andric   SmallVector<Value *> Args;
115606c3fb27SDimitry Andric   SmallPtrSet<Value *, 8> Seen;
115706c3fb27SDimitry Andric   // Traverse Cond and its operands recursively until we reach a value that's in
115806c3fb27SDimitry Andric   // Value2Index or not an instruction, or not a operation that
115906c3fb27SDimitry Andric   // ConstraintElimination can decompose. Such values will be considered as
116006c3fb27SDimitry Andric   // external inputs to the reproducer, they are collected and added as function
116106c3fb27SDimitry Andric   // arguments later.
116206c3fb27SDimitry Andric   auto CollectArguments = [&](ArrayRef<Value *> Ops, bool IsSigned) {
116306c3fb27SDimitry Andric     auto &Value2Index = Info.getValue2Index(IsSigned);
116406c3fb27SDimitry Andric     SmallVector<Value *, 4> WorkList(Ops);
116506c3fb27SDimitry Andric     while (!WorkList.empty()) {
116606c3fb27SDimitry Andric       Value *V = WorkList.pop_back_val();
116706c3fb27SDimitry Andric       if (!Seen.insert(V).second)
116806c3fb27SDimitry Andric         continue;
116906c3fb27SDimitry Andric       if (Old2New.find(V) != Old2New.end())
117006c3fb27SDimitry Andric         continue;
117106c3fb27SDimitry Andric       if (isa<Constant>(V))
117206c3fb27SDimitry Andric         continue;
117306c3fb27SDimitry Andric 
117406c3fb27SDimitry Andric       auto *I = dyn_cast<Instruction>(V);
117506c3fb27SDimitry Andric       if (Value2Index.contains(V) || !I ||
117606c3fb27SDimitry Andric           !isa<CmpInst, BinaryOperator, GEPOperator, CastInst>(V)) {
117706c3fb27SDimitry Andric         Old2New[V] = V;
117806c3fb27SDimitry Andric         Args.push_back(V);
117906c3fb27SDimitry Andric         LLVM_DEBUG(dbgs() << "  found external input " << *V << "\n");
118006c3fb27SDimitry Andric       } else {
118106c3fb27SDimitry Andric         append_range(WorkList, I->operands());
118206c3fb27SDimitry Andric       }
118306c3fb27SDimitry Andric     }
118406c3fb27SDimitry Andric   };
118506c3fb27SDimitry Andric 
118606c3fb27SDimitry Andric   for (auto &Entry : Stack)
118706c3fb27SDimitry Andric     if (Entry.Pred != ICmpInst::BAD_ICMP_PREDICATE)
118806c3fb27SDimitry Andric       CollectArguments({Entry.LHS, Entry.RHS}, ICmpInst::isSigned(Entry.Pred));
118906c3fb27SDimitry Andric   CollectArguments(Cond, ICmpInst::isSigned(Cond->getPredicate()));
119006c3fb27SDimitry Andric 
119106c3fb27SDimitry Andric   SmallVector<Type *> ParamTys;
119206c3fb27SDimitry Andric   for (auto *P : Args)
119306c3fb27SDimitry Andric     ParamTys.push_back(P->getType());
119406c3fb27SDimitry Andric 
119506c3fb27SDimitry Andric   FunctionType *FTy = FunctionType::get(Cond->getType(), ParamTys,
119606c3fb27SDimitry Andric                                         /*isVarArg=*/false);
119706c3fb27SDimitry Andric   Function *F = Function::Create(FTy, Function::ExternalLinkage,
119806c3fb27SDimitry Andric                                  Cond->getModule()->getName() +
119906c3fb27SDimitry Andric                                      Cond->getFunction()->getName() + "repro",
120006c3fb27SDimitry Andric                                  M);
120106c3fb27SDimitry Andric   // Add arguments to the reproducer function for each external value collected.
120206c3fb27SDimitry Andric   for (unsigned I = 0; I < Args.size(); ++I) {
120306c3fb27SDimitry Andric     F->getArg(I)->setName(Args[I]->getName());
120406c3fb27SDimitry Andric     Old2New[Args[I]] = F->getArg(I);
120506c3fb27SDimitry Andric   }
120606c3fb27SDimitry Andric 
120706c3fb27SDimitry Andric   BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F);
120806c3fb27SDimitry Andric   IRBuilder<> Builder(Entry);
120906c3fb27SDimitry Andric   Builder.CreateRet(Builder.getTrue());
121006c3fb27SDimitry Andric   Builder.SetInsertPoint(Entry->getTerminator());
121106c3fb27SDimitry Andric 
121206c3fb27SDimitry Andric   // Clone instructions in \p Ops and their operands recursively until reaching
121306c3fb27SDimitry Andric   // an value in Value2Index (external input to the reproducer). Update Old2New
121406c3fb27SDimitry Andric   // mapping for the original and cloned instructions. Sort instructions to
121506c3fb27SDimitry Andric   // clone by dominance, then insert the cloned instructions in the function.
121606c3fb27SDimitry Andric   auto CloneInstructions = [&](ArrayRef<Value *> Ops, bool IsSigned) {
121706c3fb27SDimitry Andric     SmallVector<Value *, 4> WorkList(Ops);
121806c3fb27SDimitry Andric     SmallVector<Instruction *> ToClone;
121906c3fb27SDimitry Andric     auto &Value2Index = Info.getValue2Index(IsSigned);
122006c3fb27SDimitry Andric     while (!WorkList.empty()) {
122106c3fb27SDimitry Andric       Value *V = WorkList.pop_back_val();
122206c3fb27SDimitry Andric       if (Old2New.find(V) != Old2New.end())
122306c3fb27SDimitry Andric         continue;
122406c3fb27SDimitry Andric 
122506c3fb27SDimitry Andric       auto *I = dyn_cast<Instruction>(V);
122606c3fb27SDimitry Andric       if (!Value2Index.contains(V) && I) {
122706c3fb27SDimitry Andric         Old2New[V] = nullptr;
122806c3fb27SDimitry Andric         ToClone.push_back(I);
122906c3fb27SDimitry Andric         append_range(WorkList, I->operands());
123006c3fb27SDimitry Andric       }
123106c3fb27SDimitry Andric     }
123206c3fb27SDimitry Andric 
123306c3fb27SDimitry Andric     sort(ToClone,
123406c3fb27SDimitry Andric          [&DT](Instruction *A, Instruction *B) { return DT.dominates(A, B); });
123506c3fb27SDimitry Andric     for (Instruction *I : ToClone) {
123606c3fb27SDimitry Andric       Instruction *Cloned = I->clone();
123706c3fb27SDimitry Andric       Old2New[I] = Cloned;
123806c3fb27SDimitry Andric       Old2New[I]->setName(I->getName());
123906c3fb27SDimitry Andric       Cloned->insertBefore(&*Builder.GetInsertPoint());
124006c3fb27SDimitry Andric       Cloned->dropUnknownNonDebugMetadata();
124106c3fb27SDimitry Andric       Cloned->setDebugLoc({});
124206c3fb27SDimitry Andric     }
124306c3fb27SDimitry Andric   };
124406c3fb27SDimitry Andric 
124506c3fb27SDimitry Andric   // Materialize the assumptions for the reproducer using the entries in Stack.
124606c3fb27SDimitry Andric   // That is, first clone the operands of the condition recursively until we
124706c3fb27SDimitry Andric   // reach an external input to the reproducer and add them to the reproducer
124806c3fb27SDimitry Andric   // function. Then add an ICmp for the condition (with the inverse predicate if
124906c3fb27SDimitry Andric   // the entry is negated) and an assert using the ICmp.
125006c3fb27SDimitry Andric   for (auto &Entry : Stack) {
125106c3fb27SDimitry Andric     if (Entry.Pred == ICmpInst::BAD_ICMP_PREDICATE)
125206c3fb27SDimitry Andric       continue;
125306c3fb27SDimitry Andric 
1254*5f757f3fSDimitry Andric     LLVM_DEBUG(dbgs() << "  Materializing assumption ";
1255*5f757f3fSDimitry Andric                dumpUnpackedICmp(dbgs(), Entry.Pred, Entry.LHS, Entry.RHS);
1256*5f757f3fSDimitry Andric                dbgs() << "\n");
125706c3fb27SDimitry Andric     CloneInstructions({Entry.LHS, Entry.RHS}, CmpInst::isSigned(Entry.Pred));
125806c3fb27SDimitry Andric 
125906c3fb27SDimitry Andric     auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS);
126006c3fb27SDimitry Andric     Builder.CreateAssumption(Cmp);
126106c3fb27SDimitry Andric   }
126206c3fb27SDimitry Andric 
126306c3fb27SDimitry Andric   // Finally, clone the condition to reproduce and remap instruction operands in
126406c3fb27SDimitry Andric   // the reproducer using Old2New.
126506c3fb27SDimitry Andric   CloneInstructions(Cond, CmpInst::isSigned(Cond->getPredicate()));
126606c3fb27SDimitry Andric   Entry->getTerminator()->setOperand(0, Cond);
126706c3fb27SDimitry Andric   remapInstructionsInBlocks({Entry}, Old2New);
126806c3fb27SDimitry Andric 
126906c3fb27SDimitry Andric   assert(!verifyFunction(*F, &dbgs()));
127006c3fb27SDimitry Andric }
127106c3fb27SDimitry Andric 
1272*5f757f3fSDimitry Andric static std::optional<bool> checkCondition(CmpInst::Predicate Pred, Value *A,
1273*5f757f3fSDimitry Andric                                           Value *B, Instruction *CheckInst,
1274*5f757f3fSDimitry Andric                                           ConstraintInfo &Info, unsigned NumIn,
1275*5f757f3fSDimitry Andric                                           unsigned NumOut,
127606c3fb27SDimitry Andric                                           Instruction *ContextInst) {
1277*5f757f3fSDimitry Andric   LLVM_DEBUG(dbgs() << "Checking " << *CheckInst << "\n");
1278bdd1243dSDimitry Andric 
1279bdd1243dSDimitry Andric   auto R = Info.getConstraintForSolving(Pred, A, B);
1280bdd1243dSDimitry Andric   if (R.empty() || !R.isValid(Info)){
1281bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "   failed to decompose condition\n");
128206c3fb27SDimitry Andric     return std::nullopt;
1283bdd1243dSDimitry Andric   }
1284bdd1243dSDimitry Andric 
1285bdd1243dSDimitry Andric   auto &CSToUse = Info.getCS(R.IsSigned);
1286bdd1243dSDimitry Andric 
1287bdd1243dSDimitry Andric   // If there was extra information collected during decomposition, apply
1288bdd1243dSDimitry Andric   // it now and remove it immediately once we are done with reasoning
1289bdd1243dSDimitry Andric   // about the constraint.
1290bdd1243dSDimitry Andric   for (auto &Row : R.ExtraInfo)
1291bdd1243dSDimitry Andric     CSToUse.addVariableRow(Row);
1292bdd1243dSDimitry Andric   auto InfoRestorer = make_scope_exit([&]() {
1293bdd1243dSDimitry Andric     for (unsigned I = 0; I < R.ExtraInfo.size(); ++I)
1294bdd1243dSDimitry Andric       CSToUse.popLastConstraint();
1295bdd1243dSDimitry Andric   });
1296bdd1243dSDimitry Andric 
129706c3fb27SDimitry Andric   if (auto ImpliedCondition = R.isImpliedBy(CSToUse)) {
1298bdd1243dSDimitry Andric     if (!DebugCounter::shouldExecute(EliminatedCounter))
129906c3fb27SDimitry Andric       return std::nullopt;
1300bdd1243dSDimitry Andric 
1301bdd1243dSDimitry Andric     LLVM_DEBUG({
1302*5f757f3fSDimitry Andric       dbgs() << "Condition ";
1303*5f757f3fSDimitry Andric       dumpUnpackedICmp(
1304*5f757f3fSDimitry Andric           dbgs(), *ImpliedCondition ? Pred : CmpInst::getInversePredicate(Pred),
1305*5f757f3fSDimitry Andric           A, B);
130606c3fb27SDimitry Andric       dbgs() << " implied by dominating constraints\n";
130706c3fb27SDimitry Andric       CSToUse.dump();
1308bdd1243dSDimitry Andric     });
130906c3fb27SDimitry Andric     return ImpliedCondition;
131006c3fb27SDimitry Andric   }
131106c3fb27SDimitry Andric 
131206c3fb27SDimitry Andric   return std::nullopt;
131306c3fb27SDimitry Andric }
131406c3fb27SDimitry Andric 
131506c3fb27SDimitry Andric static bool checkAndReplaceCondition(
131606c3fb27SDimitry Andric     CmpInst *Cmp, ConstraintInfo &Info, unsigned NumIn, unsigned NumOut,
131706c3fb27SDimitry Andric     Instruction *ContextInst, Module *ReproducerModule,
1318*5f757f3fSDimitry Andric     ArrayRef<ReproducerEntry> ReproducerCondStack, DominatorTree &DT,
1319*5f757f3fSDimitry Andric     SmallVectorImpl<Instruction *> &ToRemove) {
132006c3fb27SDimitry Andric   auto ReplaceCmpWithConstant = [&](CmpInst *Cmp, bool IsTrue) {
132106c3fb27SDimitry Andric     generateReproducer(Cmp, ReproducerModule, ReproducerCondStack, Info, DT);
132206c3fb27SDimitry Andric     Constant *ConstantC = ConstantInt::getBool(
132306c3fb27SDimitry Andric         CmpInst::makeCmpResultType(Cmp->getType()), IsTrue);
132406c3fb27SDimitry Andric     Cmp->replaceUsesWithIf(ConstantC, [&DT, NumIn, NumOut,
132506c3fb27SDimitry Andric                                        ContextInst](Use &U) {
132606c3fb27SDimitry Andric       auto *UserI = getContextInstForUse(U);
132706c3fb27SDimitry Andric       auto *DTN = DT.getNode(UserI->getParent());
132806c3fb27SDimitry Andric       if (!DTN || DTN->getDFSNumIn() < NumIn || DTN->getDFSNumOut() > NumOut)
132906c3fb27SDimitry Andric         return false;
133006c3fb27SDimitry Andric       if (UserI->getParent() == ContextInst->getParent() &&
133106c3fb27SDimitry Andric           UserI->comesBefore(ContextInst))
133206c3fb27SDimitry Andric         return false;
133306c3fb27SDimitry Andric 
1334bdd1243dSDimitry Andric       // Conditions in an assume trivially simplify to true. Skip uses
1335bdd1243dSDimitry Andric       // in assume calls to not destroy the available information.
1336bdd1243dSDimitry Andric       auto *II = dyn_cast<IntrinsicInst>(U.getUser());
1337bdd1243dSDimitry Andric       return !II || II->getIntrinsicID() != Intrinsic::assume;
1338bdd1243dSDimitry Andric     });
1339bdd1243dSDimitry Andric     NumCondsRemoved++;
1340*5f757f3fSDimitry Andric     if (Cmp->use_empty())
1341*5f757f3fSDimitry Andric       ToRemove.push_back(Cmp);
134206c3fb27SDimitry Andric     return true;
134306c3fb27SDimitry Andric   };
134406c3fb27SDimitry Andric 
1345*5f757f3fSDimitry Andric   if (auto ImpliedCondition = checkCondition(
1346*5f757f3fSDimitry Andric           Cmp->getPredicate(), Cmp->getOperand(0), Cmp->getOperand(1), Cmp,
1347*5f757f3fSDimitry Andric           Info, NumIn, NumOut, ContextInst))
134806c3fb27SDimitry Andric     return ReplaceCmpWithConstant(Cmp, *ImpliedCondition);
134906c3fb27SDimitry Andric   return false;
1350bdd1243dSDimitry Andric }
135106c3fb27SDimitry Andric 
135206c3fb27SDimitry Andric static void
135306c3fb27SDimitry Andric removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info,
135406c3fb27SDimitry Andric                      Module *ReproducerModule,
135506c3fb27SDimitry Andric                      SmallVectorImpl<ReproducerEntry> &ReproducerCondStack,
135606c3fb27SDimitry Andric                      SmallVectorImpl<StackEntry> &DFSInStack) {
135706c3fb27SDimitry Andric   Info.popLastConstraint(E.IsSigned);
135806c3fb27SDimitry Andric   // Remove variables in the system that went out of scope.
135906c3fb27SDimitry Andric   auto &Mapping = Info.getValue2Index(E.IsSigned);
136006c3fb27SDimitry Andric   for (Value *V : E.ValuesToRelease)
136106c3fb27SDimitry Andric     Mapping.erase(V);
136206c3fb27SDimitry Andric   Info.popLastNVariables(E.IsSigned, E.ValuesToRelease.size());
136306c3fb27SDimitry Andric   DFSInStack.pop_back();
136406c3fb27SDimitry Andric   if (ReproducerModule)
136506c3fb27SDimitry Andric     ReproducerCondStack.pop_back();
136606c3fb27SDimitry Andric }
136706c3fb27SDimitry Andric 
136806c3fb27SDimitry Andric /// Check if the first condition for an AND implies the second.
136906c3fb27SDimitry Andric static bool checkAndSecondOpImpliedByFirst(
137006c3fb27SDimitry Andric     FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule,
137106c3fb27SDimitry Andric     SmallVectorImpl<ReproducerEntry> &ReproducerCondStack,
137206c3fb27SDimitry Andric     SmallVectorImpl<StackEntry> &DFSInStack) {
1373*5f757f3fSDimitry Andric 
137406c3fb27SDimitry Andric   CmpInst::Predicate Pred;
137506c3fb27SDimitry Andric   Value *A, *B;
137606c3fb27SDimitry Andric   Instruction *And = CB.getContextInst();
137706c3fb27SDimitry Andric   if (!match(And->getOperand(0), m_ICmp(Pred, m_Value(A), m_Value(B))))
1378bdd1243dSDimitry Andric     return false;
1379bdd1243dSDimitry Andric 
138006c3fb27SDimitry Andric   // Optimistically add fact from first condition.
138106c3fb27SDimitry Andric   unsigned OldSize = DFSInStack.size();
138206c3fb27SDimitry Andric   Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
138306c3fb27SDimitry Andric   if (OldSize == DFSInStack.size())
138406c3fb27SDimitry Andric     return false;
138506c3fb27SDimitry Andric 
138606c3fb27SDimitry Andric   bool Changed = false;
138706c3fb27SDimitry Andric   // Check if the second condition can be simplified now.
1388*5f757f3fSDimitry Andric   ICmpInst *Cmp = cast<ICmpInst>(And->getOperand(1));
1389*5f757f3fSDimitry Andric   if (auto ImpliedCondition = checkCondition(
1390*5f757f3fSDimitry Andric           Cmp->getPredicate(), Cmp->getOperand(0), Cmp->getOperand(1), Cmp,
1391*5f757f3fSDimitry Andric           Info, CB.NumIn, CB.NumOut, CB.getContextInst())) {
139206c3fb27SDimitry Andric     And->setOperand(1, ConstantInt::getBool(And->getType(), *ImpliedCondition));
1393bdd1243dSDimitry Andric     Changed = true;
1394bdd1243dSDimitry Andric   }
139506c3fb27SDimitry Andric 
139606c3fb27SDimitry Andric   // Remove entries again.
139706c3fb27SDimitry Andric   while (OldSize < DFSInStack.size()) {
139806c3fb27SDimitry Andric     StackEntry E = DFSInStack.back();
139906c3fb27SDimitry Andric     removeEntryFromStack(E, Info, ReproducerModule, ReproducerCondStack,
140006c3fb27SDimitry Andric                          DFSInStack);
140106c3fb27SDimitry Andric   }
1402bdd1243dSDimitry Andric   return Changed;
1403e8d8bef9SDimitry Andric }
1404e8d8bef9SDimitry Andric 
140581ad6265SDimitry Andric void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B,
1406bdd1243dSDimitry Andric                              unsigned NumIn, unsigned NumOut,
140781ad6265SDimitry Andric                              SmallVectorImpl<StackEntry> &DFSInStack) {
140881ad6265SDimitry Andric   // If the constraint has a pre-condition, skip the constraint if it does not
140981ad6265SDimitry Andric   // hold.
1410bdd1243dSDimitry Andric   SmallVector<Value *> NewVariables;
1411bdd1243dSDimitry Andric   auto R = getConstraint(Pred, A, B, NewVariables);
141206c3fb27SDimitry Andric 
141306c3fb27SDimitry Andric   // TODO: Support non-equality for facts as well.
141406c3fb27SDimitry Andric   if (!R.isValid(*this) || R.isNe())
141581ad6265SDimitry Andric     return;
141681ad6265SDimitry Andric 
1417*5f757f3fSDimitry Andric   LLVM_DEBUG(dbgs() << "Adding '"; dumpUnpackedICmp(dbgs(), Pred, A, B);
1418*5f757f3fSDimitry Andric              dbgs() << "'\n");
141981ad6265SDimitry Andric   bool Added = false;
142081ad6265SDimitry Andric   auto &CSToUse = getCS(R.IsSigned);
142181ad6265SDimitry Andric   if (R.Coefficients.empty())
142281ad6265SDimitry Andric     return;
142381ad6265SDimitry Andric 
142481ad6265SDimitry Andric   Added |= CSToUse.addVariableRowFill(R.Coefficients);
142581ad6265SDimitry Andric 
1426bdd1243dSDimitry Andric   // If R has been added to the system, add the new variables and queue it for
1427bdd1243dSDimitry Andric   // removal once it goes out-of-scope.
142881ad6265SDimitry Andric   if (Added) {
142981ad6265SDimitry Andric     SmallVector<Value *, 2> ValuesToRelease;
1430bdd1243dSDimitry Andric     auto &Value2Index = getValue2Index(R.IsSigned);
1431bdd1243dSDimitry Andric     for (Value *V : NewVariables) {
1432bdd1243dSDimitry Andric       Value2Index.insert({V, Value2Index.size() + 1});
1433bdd1243dSDimitry Andric       ValuesToRelease.push_back(V);
143481ad6265SDimitry Andric     }
143581ad6265SDimitry Andric 
143681ad6265SDimitry Andric     LLVM_DEBUG({
143781ad6265SDimitry Andric       dbgs() << "  constraint: ";
143806c3fb27SDimitry Andric       dumpConstraint(R.Coefficients, getValue2Index(R.IsSigned));
1439bdd1243dSDimitry Andric       dbgs() << "\n";
144081ad6265SDimitry Andric     });
144181ad6265SDimitry Andric 
1442bdd1243dSDimitry Andric     DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,
1443bdd1243dSDimitry Andric                             std::move(ValuesToRelease));
144481ad6265SDimitry Andric 
144506c3fb27SDimitry Andric     if (R.isEq()) {
144681ad6265SDimitry Andric       // Also add the inverted constraint for equality constraints.
144781ad6265SDimitry Andric       for (auto &Coeff : R.Coefficients)
144881ad6265SDimitry Andric         Coeff *= -1;
144981ad6265SDimitry Andric       CSToUse.addVariableRowFill(R.Coefficients);
145081ad6265SDimitry Andric 
1451bdd1243dSDimitry Andric       DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,
145281ad6265SDimitry Andric                               SmallVector<Value *, 2>());
145381ad6265SDimitry Andric     }
145481ad6265SDimitry Andric   }
145581ad6265SDimitry Andric }
145681ad6265SDimitry Andric 
1457bdd1243dSDimitry Andric static bool replaceSubOverflowUses(IntrinsicInst *II, Value *A, Value *B,
1458bdd1243dSDimitry Andric                                    SmallVectorImpl<Instruction *> &ToRemove) {
1459bdd1243dSDimitry Andric   bool Changed = false;
1460bdd1243dSDimitry Andric   IRBuilder<> Builder(II->getParent(), II->getIterator());
1461bdd1243dSDimitry Andric   Value *Sub = nullptr;
1462bdd1243dSDimitry Andric   for (User *U : make_early_inc_range(II->users())) {
1463bdd1243dSDimitry Andric     if (match(U, m_ExtractValue<0>(m_Value()))) {
1464bdd1243dSDimitry Andric       if (!Sub)
1465bdd1243dSDimitry Andric         Sub = Builder.CreateSub(A, B);
1466bdd1243dSDimitry Andric       U->replaceAllUsesWith(Sub);
1467bdd1243dSDimitry Andric       Changed = true;
1468bdd1243dSDimitry Andric     } else if (match(U, m_ExtractValue<1>(m_Value()))) {
1469bdd1243dSDimitry Andric       U->replaceAllUsesWith(Builder.getFalse());
1470bdd1243dSDimitry Andric       Changed = true;
1471bdd1243dSDimitry Andric     } else
1472bdd1243dSDimitry Andric       continue;
1473bdd1243dSDimitry Andric 
1474bdd1243dSDimitry Andric     if (U->use_empty()) {
1475bdd1243dSDimitry Andric       auto *I = cast<Instruction>(U);
1476bdd1243dSDimitry Andric       ToRemove.push_back(I);
1477bdd1243dSDimitry Andric       I->setOperand(0, PoisonValue::get(II->getType()));
1478bdd1243dSDimitry Andric       Changed = true;
1479bdd1243dSDimitry Andric     }
1480bdd1243dSDimitry Andric   }
1481bdd1243dSDimitry Andric 
1482bdd1243dSDimitry Andric   if (II->use_empty()) {
1483bdd1243dSDimitry Andric     II->eraseFromParent();
1484bdd1243dSDimitry Andric     Changed = true;
1485bdd1243dSDimitry Andric   }
1486bdd1243dSDimitry Andric   return Changed;
1487bdd1243dSDimitry Andric }
1488bdd1243dSDimitry Andric 
1489bdd1243dSDimitry Andric static bool
149081ad6265SDimitry Andric tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
149181ad6265SDimitry Andric                           SmallVectorImpl<Instruction *> &ToRemove) {
149281ad6265SDimitry Andric   auto DoesConditionHold = [](CmpInst::Predicate Pred, Value *A, Value *B,
149381ad6265SDimitry Andric                               ConstraintInfo &Info) {
1494bdd1243dSDimitry Andric     auto R = Info.getConstraintForSolving(Pred, A, B);
1495bdd1243dSDimitry Andric     if (R.size() < 2 || !R.isValid(Info))
149681ad6265SDimitry Andric       return false;
149781ad6265SDimitry Andric 
1498bdd1243dSDimitry Andric     auto &CSToUse = Info.getCS(R.IsSigned);
149981ad6265SDimitry Andric     return CSToUse.isConditionImplied(R.Coefficients);
150081ad6265SDimitry Andric   };
150181ad6265SDimitry Andric 
1502bdd1243dSDimitry Andric   bool Changed = false;
150381ad6265SDimitry Andric   if (II->getIntrinsicID() == Intrinsic::ssub_with_overflow) {
150481ad6265SDimitry Andric     // If A s>= B && B s>= 0, ssub.with.overflow(a, b) should not overflow and
150581ad6265SDimitry Andric     // can be simplified to a regular sub.
150681ad6265SDimitry Andric     Value *A = II->getArgOperand(0);
150781ad6265SDimitry Andric     Value *B = II->getArgOperand(1);
150881ad6265SDimitry Andric     if (!DoesConditionHold(CmpInst::ICMP_SGE, A, B, Info) ||
150981ad6265SDimitry Andric         !DoesConditionHold(CmpInst::ICMP_SGE, B,
151081ad6265SDimitry Andric                            ConstantInt::get(A->getType(), 0), Info))
1511bdd1243dSDimitry Andric       return false;
1512bdd1243dSDimitry Andric     Changed = replaceSubOverflowUses(II, A, B, ToRemove);
151381ad6265SDimitry Andric   }
1514bdd1243dSDimitry Andric   return Changed;
151581ad6265SDimitry Andric }
151681ad6265SDimitry Andric 
1517*5f757f3fSDimitry Andric static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
1518*5f757f3fSDimitry Andric                                  ScalarEvolution &SE,
151906c3fb27SDimitry Andric                                  OptimizationRemarkEmitter &ORE) {
152081ad6265SDimitry Andric   bool Changed = false;
152181ad6265SDimitry Andric   DT.updateDFSNumbers();
152206c3fb27SDimitry Andric   SmallVector<Value *> FunctionArgs;
152306c3fb27SDimitry Andric   for (Value &Arg : F.args())
152406c3fb27SDimitry Andric     FunctionArgs.push_back(&Arg);
152506c3fb27SDimitry Andric   ConstraintInfo Info(F.getParent()->getDataLayout(), FunctionArgs);
1526*5f757f3fSDimitry Andric   State S(DT, LI, SE);
152706c3fb27SDimitry Andric   std::unique_ptr<Module> ReproducerModule(
152806c3fb27SDimitry Andric       DumpReproducers ? new Module(F.getName(), F.getContext()) : nullptr);
152981ad6265SDimitry Andric 
153081ad6265SDimitry Andric   // First, collect conditions implied by branches and blocks with their
153181ad6265SDimitry Andric   // Dominator DFS in and out numbers.
153281ad6265SDimitry Andric   for (BasicBlock &BB : F) {
153381ad6265SDimitry Andric     if (!DT.getNode(&BB))
153481ad6265SDimitry Andric       continue;
153581ad6265SDimitry Andric     S.addInfoFor(BB);
153681ad6265SDimitry Andric   }
153781ad6265SDimitry Andric 
1538bdd1243dSDimitry Andric   // Next, sort worklist by dominance, so that dominating conditions to check
1539bdd1243dSDimitry Andric   // and facts come before conditions and facts dominated by them. If a
1540bdd1243dSDimitry Andric   // condition to check and a fact have the same numbers, conditional facts come
1541bdd1243dSDimitry Andric   // first. Assume facts and checks are ordered according to their relative
1542bdd1243dSDimitry Andric   // order in the containing basic block. Also make sure conditions with
1543bdd1243dSDimitry Andric   // constant operands come before conditions without constant operands. This
1544bdd1243dSDimitry Andric   // increases the effectiveness of the current signed <-> unsigned fact
1545bdd1243dSDimitry Andric   // transfer logic.
1546bdd1243dSDimitry Andric   stable_sort(S.WorkList, [](const FactOrCheck &A, const FactOrCheck &B) {
1547bdd1243dSDimitry Andric     auto HasNoConstOp = [](const FactOrCheck &B) {
1548*5f757f3fSDimitry Andric       Value *V0 = B.isConditionFact() ? B.Cond.Op0 : B.Inst->getOperand(0);
1549*5f757f3fSDimitry Andric       Value *V1 = B.isConditionFact() ? B.Cond.Op1 : B.Inst->getOperand(1);
1550*5f757f3fSDimitry Andric       return !isa<ConstantInt>(V0) && !isa<ConstantInt>(V1);
1551bdd1243dSDimitry Andric     };
1552bdd1243dSDimitry Andric     // If both entries have the same In numbers, conditional facts come first.
1553bdd1243dSDimitry Andric     // Otherwise use the relative order in the basic block.
1554bdd1243dSDimitry Andric     if (A.NumIn == B.NumIn) {
1555bdd1243dSDimitry Andric       if (A.isConditionFact() && B.isConditionFact()) {
1556bdd1243dSDimitry Andric         bool NoConstOpA = HasNoConstOp(A);
1557bdd1243dSDimitry Andric         bool NoConstOpB = HasNoConstOp(B);
1558bdd1243dSDimitry Andric         return NoConstOpA < NoConstOpB;
1559bdd1243dSDimitry Andric       }
1560bdd1243dSDimitry Andric       if (A.isConditionFact())
1561bdd1243dSDimitry Andric         return true;
1562bdd1243dSDimitry Andric       if (B.isConditionFact())
1563bdd1243dSDimitry Andric         return false;
156406c3fb27SDimitry Andric       auto *InstA = A.getContextInst();
156506c3fb27SDimitry Andric       auto *InstB = B.getContextInst();
156606c3fb27SDimitry Andric       return InstA->comesBefore(InstB);
1567bdd1243dSDimitry Andric     }
1568bdd1243dSDimitry Andric     return A.NumIn < B.NumIn;
1569e8d8bef9SDimitry Andric   });
1570e8d8bef9SDimitry Andric 
157181ad6265SDimitry Andric   SmallVector<Instruction *> ToRemove;
157281ad6265SDimitry Andric 
1573e8d8bef9SDimitry Andric   // Finally, process ordered worklist and eliminate implied conditions.
1574e8d8bef9SDimitry Andric   SmallVector<StackEntry, 16> DFSInStack;
157506c3fb27SDimitry Andric   SmallVector<ReproducerEntry> ReproducerCondStack;
1576bdd1243dSDimitry Andric   for (FactOrCheck &CB : S.WorkList) {
1577e8d8bef9SDimitry Andric     // First, pop entries from the stack that are out-of-scope for CB. Remove
1578e8d8bef9SDimitry Andric     // the corresponding entry from the constraint system.
1579e8d8bef9SDimitry Andric     while (!DFSInStack.empty()) {
1580e8d8bef9SDimitry Andric       auto &E = DFSInStack.back();
1581e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "Top of stack : " << E.NumIn << " " << E.NumOut
1582e8d8bef9SDimitry Andric                         << "\n");
1583e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "CB: " << CB.NumIn << " " << CB.NumOut << "\n");
1584e8d8bef9SDimitry Andric       assert(E.NumIn <= CB.NumIn);
1585e8d8bef9SDimitry Andric       if (CB.NumOut <= E.NumOut)
1586e8d8bef9SDimitry Andric         break;
158781ad6265SDimitry Andric       LLVM_DEBUG({
158881ad6265SDimitry Andric         dbgs() << "Removing ";
158906c3fb27SDimitry Andric         dumpConstraint(Info.getCS(E.IsSigned).getLastConstraint(),
159081ad6265SDimitry Andric                        Info.getValue2Index(E.IsSigned));
159181ad6265SDimitry Andric         dbgs() << "\n";
159281ad6265SDimitry Andric       });
159306c3fb27SDimitry Andric       removeEntryFromStack(E, Info, ReproducerModule.get(), ReproducerCondStack,
159406c3fb27SDimitry Andric                            DFSInStack);
1595e8d8bef9SDimitry Andric     }
1596e8d8bef9SDimitry Andric 
159706c3fb27SDimitry Andric     LLVM_DEBUG(dbgs() << "Processing ");
1598e8d8bef9SDimitry Andric 
1599e8d8bef9SDimitry Andric     // For a block, check if any CmpInsts become known based on the current set
1600e8d8bef9SDimitry Andric     // of constraints.
160106c3fb27SDimitry Andric     if (CB.isCheck()) {
160206c3fb27SDimitry Andric       Instruction *Inst = CB.getInstructionToSimplify();
160306c3fb27SDimitry Andric       if (!Inst)
160406c3fb27SDimitry Andric         continue;
160506c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "condition to simplify: " << *Inst << "\n");
160606c3fb27SDimitry Andric       if (auto *II = dyn_cast<WithOverflowInst>(Inst)) {
1607bdd1243dSDimitry Andric         Changed |= tryToSimplifyOverflowMath(II, Info, ToRemove);
160806c3fb27SDimitry Andric       } else if (auto *Cmp = dyn_cast<ICmpInst>(Inst)) {
160906c3fb27SDimitry Andric         bool Simplified = checkAndReplaceCondition(
161006c3fb27SDimitry Andric             Cmp, Info, CB.NumIn, CB.NumOut, CB.getContextInst(),
1611*5f757f3fSDimitry Andric             ReproducerModule.get(), ReproducerCondStack, S.DT, ToRemove);
161206c3fb27SDimitry Andric         if (!Simplified && match(CB.getContextInst(),
161306c3fb27SDimitry Andric                                  m_LogicalAnd(m_Value(), m_Specific(Inst)))) {
161406c3fb27SDimitry Andric           Simplified =
161506c3fb27SDimitry Andric               checkAndSecondOpImpliedByFirst(CB, Info, ReproducerModule.get(),
161606c3fb27SDimitry Andric                                              ReproducerCondStack, DFSInStack);
161706c3fb27SDimitry Andric         }
161806c3fb27SDimitry Andric         Changed |= Simplified;
1619e8d8bef9SDimitry Andric       }
1620e8d8bef9SDimitry Andric       continue;
1621e8d8bef9SDimitry Andric     }
1622e8d8bef9SDimitry Andric 
162306c3fb27SDimitry Andric     auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) {
1624*5f757f3fSDimitry Andric       LLVM_DEBUG(dbgs() << "fact to add to the system: ";
1625*5f757f3fSDimitry Andric                  dumpUnpackedICmp(dbgs(), Pred, A, B); dbgs() << "\n");
1626bdd1243dSDimitry Andric       if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) {
1627bdd1243dSDimitry Andric         LLVM_DEBUG(
1628bdd1243dSDimitry Andric             dbgs()
1629bdd1243dSDimitry Andric             << "Skip adding constraint because system has too many rows.\n");
163006c3fb27SDimitry Andric         return;
163106c3fb27SDimitry Andric       }
163206c3fb27SDimitry Andric 
163306c3fb27SDimitry Andric       Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
163406c3fb27SDimitry Andric       if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size())
163506c3fb27SDimitry Andric         ReproducerCondStack.emplace_back(Pred, A, B);
163606c3fb27SDimitry Andric 
163706c3fb27SDimitry Andric       Info.transferToOtherSystem(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
163806c3fb27SDimitry Andric       if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) {
163906c3fb27SDimitry Andric         // Add dummy entries to ReproducerCondStack to keep it in sync with
164006c3fb27SDimitry Andric         // DFSInStack.
164106c3fb27SDimitry Andric         for (unsigned I = 0,
164206c3fb27SDimitry Andric                       E = (DFSInStack.size() - ReproducerCondStack.size());
164306c3fb27SDimitry Andric              I < E; ++I) {
164406c3fb27SDimitry Andric           ReproducerCondStack.emplace_back(ICmpInst::BAD_ICMP_PREDICATE,
164506c3fb27SDimitry Andric                                            nullptr, nullptr);
164606c3fb27SDimitry Andric         }
164706c3fb27SDimitry Andric       }
164806c3fb27SDimitry Andric     };
164906c3fb27SDimitry Andric 
165006c3fb27SDimitry Andric     ICmpInst::Predicate Pred;
1651*5f757f3fSDimitry Andric     if (!CB.isConditionFact()) {
165206c3fb27SDimitry Andric       if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {
165306c3fb27SDimitry Andric         Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
165406c3fb27SDimitry Andric         AddFact(Pred, MinMax, MinMax->getLHS());
165506c3fb27SDimitry Andric         AddFact(Pred, MinMax, MinMax->getRHS());
1656bdd1243dSDimitry Andric         continue;
1657bdd1243dSDimitry Andric       }
1658e8d8bef9SDimitry Andric     }
1659*5f757f3fSDimitry Andric 
1660*5f757f3fSDimitry Andric     Value *A = nullptr, *B = nullptr;
1661*5f757f3fSDimitry Andric     if (CB.isConditionFact()) {
1662*5f757f3fSDimitry Andric       Pred = CB.Cond.Pred;
1663*5f757f3fSDimitry Andric       A = CB.Cond.Op0;
1664*5f757f3fSDimitry Andric       B = CB.Cond.Op1;
1665*5f757f3fSDimitry Andric       if (CB.DoesHold.Pred != CmpInst::BAD_ICMP_PREDICATE &&
1666*5f757f3fSDimitry Andric           !Info.doesHold(CB.DoesHold.Pred, CB.DoesHold.Op0, CB.DoesHold.Op1))
1667*5f757f3fSDimitry Andric         continue;
1668*5f757f3fSDimitry Andric     } else {
1669*5f757f3fSDimitry Andric       bool Matched = match(CB.Inst, m_Intrinsic<Intrinsic::assume>(
1670*5f757f3fSDimitry Andric                                         m_ICmp(Pred, m_Value(A), m_Value(B))));
1671*5f757f3fSDimitry Andric       (void)Matched;
1672*5f757f3fSDimitry Andric       assert(Matched && "Must have an assume intrinsic with a icmp operand");
1673*5f757f3fSDimitry Andric     }
1674*5f757f3fSDimitry Andric     AddFact(Pred, A, B);
1675fe6060f1SDimitry Andric   }
1676e8d8bef9SDimitry Andric 
167706c3fb27SDimitry Andric   if (ReproducerModule && !ReproducerModule->functions().empty()) {
167806c3fb27SDimitry Andric     std::string S;
167906c3fb27SDimitry Andric     raw_string_ostream StringS(S);
168006c3fb27SDimitry Andric     ReproducerModule->print(StringS, nullptr);
168106c3fb27SDimitry Andric     StringS.flush();
168206c3fb27SDimitry Andric     OptimizationRemark Rem(DEBUG_TYPE, "Reproducer", &F);
168306c3fb27SDimitry Andric     Rem << ore::NV("module") << S;
168406c3fb27SDimitry Andric     ORE.emit(Rem);
168506c3fb27SDimitry Andric   }
168606c3fb27SDimitry Andric 
168781ad6265SDimitry Andric #ifndef NDEBUG
168881ad6265SDimitry Andric   unsigned SignedEntries =
168981ad6265SDimitry Andric       count_if(DFSInStack, [](const StackEntry &E) { return E.IsSigned; });
169081ad6265SDimitry Andric   assert(Info.getCS(false).size() == DFSInStack.size() - SignedEntries &&
1691fe6060f1SDimitry Andric          "updates to CS and DFSInStack are out of sync");
169281ad6265SDimitry Andric   assert(Info.getCS(true).size() == SignedEntries &&
169381ad6265SDimitry Andric          "updates to CS and DFSInStack are out of sync");
169481ad6265SDimitry Andric #endif
169581ad6265SDimitry Andric 
169681ad6265SDimitry Andric   for (Instruction *I : ToRemove)
169781ad6265SDimitry Andric     I->eraseFromParent();
1698e8d8bef9SDimitry Andric   return Changed;
1699e8d8bef9SDimitry Andric }
1700e8d8bef9SDimitry Andric 
1701e8d8bef9SDimitry Andric PreservedAnalyses ConstraintEliminationPass::run(Function &F,
1702e8d8bef9SDimitry Andric                                                  FunctionAnalysisManager &AM) {
1703e8d8bef9SDimitry Andric   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
1704*5f757f3fSDimitry Andric   auto &LI = AM.getResult<LoopAnalysis>(F);
1705*5f757f3fSDimitry Andric   auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
170606c3fb27SDimitry Andric   auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
1707*5f757f3fSDimitry Andric   if (!eliminateConstraints(F, DT, LI, SE, ORE))
1708e8d8bef9SDimitry Andric     return PreservedAnalyses::all();
1709e8d8bef9SDimitry Andric 
1710e8d8bef9SDimitry Andric   PreservedAnalyses PA;
1711e8d8bef9SDimitry Andric   PA.preserve<DominatorTreeAnalysis>();
1712*5f757f3fSDimitry Andric   PA.preserve<LoopAnalysis>();
1713*5f757f3fSDimitry Andric   PA.preserve<ScalarEvolutionAnalysis>();
1714e8d8bef9SDimitry Andric   PA.preserveSet<CFGAnalyses>();
1715e8d8bef9SDimitry Andric   return PA;
1716e8d8bef9SDimitry Andric }
1717