1e8d8bef9SDimitry Andric //===-- ConstraintElimination.cpp - Eliminate conds using constraints. ----===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric // 9e8d8bef9SDimitry Andric // Eliminate conditions based on constraints collected from dominating 10e8d8bef9SDimitry Andric // conditions. 11e8d8bef9SDimitry Andric // 12e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 13e8d8bef9SDimitry Andric 14e8d8bef9SDimitry Andric #include "llvm/Transforms/Scalar/ConstraintElimination.h" 15e8d8bef9SDimitry Andric #include "llvm/ADT/STLExtras.h" 16fe6060f1SDimitry Andric #include "llvm/ADT/ScopeExit.h" 17e8d8bef9SDimitry Andric #include "llvm/ADT/SmallVector.h" 18e8d8bef9SDimitry Andric #include "llvm/ADT/Statistic.h" 19e8d8bef9SDimitry Andric #include "llvm/Analysis/ConstraintSystem.h" 20e8d8bef9SDimitry Andric #include "llvm/Analysis/GlobalsModRef.h" 2106c3fb27SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h" 22349cc55cSDimitry Andric #include "llvm/Analysis/ValueTracking.h" 23bdd1243dSDimitry Andric #include "llvm/IR/DataLayout.h" 24e8d8bef9SDimitry Andric #include "llvm/IR/Dominators.h" 25e8d8bef9SDimitry Andric #include "llvm/IR/Function.h" 26bdd1243dSDimitry Andric #include "llvm/IR/GetElementPtrTypeIterator.h" 2781ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h" 28e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h" 29e8d8bef9SDimitry Andric #include "llvm/IR/PatternMatch.h" 3006c3fb27SDimitry Andric #include "llvm/IR/Verifier.h" 31e8d8bef9SDimitry Andric #include "llvm/Pass.h" 32bdd1243dSDimitry Andric #include "llvm/Support/CommandLine.h" 33e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h" 34e8d8bef9SDimitry Andric #include "llvm/Support/DebugCounter.h" 3506c3fb27SDimitry Andric #include "llvm/Support/KnownBits.h" 3681ad6265SDimitry Andric #include "llvm/Support/MathExtras.h" 3706c3fb27SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h" 3806c3fb27SDimitry Andric #include "llvm/Transforms/Utils/ValueMapper.h" 39e8d8bef9SDimitry Andric 40bdd1243dSDimitry Andric #include <cmath> 4106c3fb27SDimitry Andric #include <optional> 42fe6060f1SDimitry Andric #include <string> 43fe6060f1SDimitry Andric 44e8d8bef9SDimitry Andric using namespace llvm; 45e8d8bef9SDimitry Andric using namespace PatternMatch; 46e8d8bef9SDimitry Andric 47e8d8bef9SDimitry Andric #define DEBUG_TYPE "constraint-elimination" 48e8d8bef9SDimitry Andric 49e8d8bef9SDimitry Andric STATISTIC(NumCondsRemoved, "Number of instructions removed"); 50e8d8bef9SDimitry Andric DEBUG_COUNTER(EliminatedCounter, "conds-eliminated", 51e8d8bef9SDimitry Andric "Controls which conditions are eliminated"); 52e8d8bef9SDimitry Andric 53bdd1243dSDimitry Andric static cl::opt<unsigned> 54bdd1243dSDimitry Andric MaxRows("constraint-elimination-max-rows", cl::init(500), cl::Hidden, 55bdd1243dSDimitry Andric cl::desc("Maximum number of rows to keep in constraint system")); 56bdd1243dSDimitry Andric 5706c3fb27SDimitry Andric static cl::opt<bool> DumpReproducers( 5806c3fb27SDimitry Andric "constraint-elimination-dump-reproducers", cl::init(false), cl::Hidden, 5906c3fb27SDimitry Andric cl::desc("Dump IR to reproduce successful transformations.")); 6006c3fb27SDimitry Andric 61e8d8bef9SDimitry Andric static int64_t MaxConstraintValue = std::numeric_limits<int64_t>::max(); 6281ad6265SDimitry Andric static int64_t MinSignedConstraintValue = std::numeric_limits<int64_t>::min(); 63e8d8bef9SDimitry Andric 64bdd1243dSDimitry Andric // A helper to multiply 2 signed integers where overflowing is allowed. 65bdd1243dSDimitry Andric static int64_t multiplyWithOverflow(int64_t A, int64_t B) { 66bdd1243dSDimitry Andric int64_t Result; 67bdd1243dSDimitry Andric MulOverflow(A, B, Result); 68bdd1243dSDimitry Andric return Result; 69bdd1243dSDimitry Andric } 70bdd1243dSDimitry Andric 71bdd1243dSDimitry Andric // A helper to add 2 signed integers where overflowing is allowed. 72bdd1243dSDimitry Andric static int64_t addWithOverflow(int64_t A, int64_t B) { 73bdd1243dSDimitry Andric int64_t Result; 74bdd1243dSDimitry Andric AddOverflow(A, B, Result); 75bdd1243dSDimitry Andric return Result; 76bdd1243dSDimitry Andric } 77bdd1243dSDimitry Andric 7806c3fb27SDimitry Andric static Instruction *getContextInstForUse(Use &U) { 7906c3fb27SDimitry Andric Instruction *UserI = cast<Instruction>(U.getUser()); 8006c3fb27SDimitry Andric if (auto *Phi = dyn_cast<PHINode>(UserI)) 8106c3fb27SDimitry Andric UserI = Phi->getIncomingBlock(U)->getTerminator(); 8206c3fb27SDimitry Andric return UserI; 8306c3fb27SDimitry Andric } 8406c3fb27SDimitry Andric 8504eeddc0SDimitry Andric namespace { 8606c3fb27SDimitry Andric /// Represents either 8706c3fb27SDimitry Andric /// * a condition that holds on entry to a block (=conditional fact) 8806c3fb27SDimitry Andric /// * an assume (=assume fact) 8906c3fb27SDimitry Andric /// * a use of a compare instruction to simplify. 9006c3fb27SDimitry Andric /// It also tracks the Dominator DFS in and out numbers for each entry. 9106c3fb27SDimitry Andric struct FactOrCheck { 9206c3fb27SDimitry Andric union { 9306c3fb27SDimitry Andric Instruction *Inst; 9406c3fb27SDimitry Andric Use *U; 9506c3fb27SDimitry Andric }; 9606c3fb27SDimitry Andric unsigned NumIn; 9706c3fb27SDimitry Andric unsigned NumOut; 9806c3fb27SDimitry Andric bool HasInst; 9906c3fb27SDimitry Andric bool Not; 10006c3fb27SDimitry Andric 10106c3fb27SDimitry Andric FactOrCheck(DomTreeNode *DTN, Instruction *Inst, bool Not) 10206c3fb27SDimitry Andric : Inst(Inst), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), 10306c3fb27SDimitry Andric HasInst(true), Not(Not) {} 10406c3fb27SDimitry Andric 10506c3fb27SDimitry Andric FactOrCheck(DomTreeNode *DTN, Use *U) 10606c3fb27SDimitry Andric : U(U), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), 10706c3fb27SDimitry Andric HasInst(false), Not(false) {} 10806c3fb27SDimitry Andric 10906c3fb27SDimitry Andric static FactOrCheck getFact(DomTreeNode *DTN, Instruction *Inst, 11006c3fb27SDimitry Andric bool Not = false) { 11106c3fb27SDimitry Andric return FactOrCheck(DTN, Inst, Not); 11206c3fb27SDimitry Andric } 11306c3fb27SDimitry Andric 11406c3fb27SDimitry Andric static FactOrCheck getCheck(DomTreeNode *DTN, Use *U) { 11506c3fb27SDimitry Andric return FactOrCheck(DTN, U); 11606c3fb27SDimitry Andric } 11706c3fb27SDimitry Andric 11806c3fb27SDimitry Andric static FactOrCheck getCheck(DomTreeNode *DTN, CallInst *CI) { 11906c3fb27SDimitry Andric return FactOrCheck(DTN, CI, false); 12006c3fb27SDimitry Andric } 12106c3fb27SDimitry Andric 12206c3fb27SDimitry Andric bool isCheck() const { 12306c3fb27SDimitry Andric return !HasInst || 12406c3fb27SDimitry Andric match(Inst, m_Intrinsic<Intrinsic::ssub_with_overflow>()); 12506c3fb27SDimitry Andric } 12606c3fb27SDimitry Andric 12706c3fb27SDimitry Andric Instruction *getContextInst() const { 12806c3fb27SDimitry Andric if (HasInst) 12906c3fb27SDimitry Andric return Inst; 13006c3fb27SDimitry Andric return getContextInstForUse(*U); 13106c3fb27SDimitry Andric } 13206c3fb27SDimitry Andric Instruction *getInstructionToSimplify() const { 13306c3fb27SDimitry Andric assert(isCheck()); 13406c3fb27SDimitry Andric if (HasInst) 13506c3fb27SDimitry Andric return Inst; 13606c3fb27SDimitry Andric // The use may have been simplified to a constant already. 13706c3fb27SDimitry Andric return dyn_cast<Instruction>(*U); 13806c3fb27SDimitry Andric } 13906c3fb27SDimitry Andric bool isConditionFact() const { return !isCheck() && isa<CmpInst>(Inst); } 14006c3fb27SDimitry Andric }; 14106c3fb27SDimitry Andric 14206c3fb27SDimitry Andric /// Keep state required to build worklist. 14306c3fb27SDimitry Andric struct State { 14406c3fb27SDimitry Andric DominatorTree &DT; 14506c3fb27SDimitry Andric SmallVector<FactOrCheck, 64> WorkList; 14606c3fb27SDimitry Andric 14706c3fb27SDimitry Andric State(DominatorTree &DT) : DT(DT) {} 14806c3fb27SDimitry Andric 14906c3fb27SDimitry Andric /// Process block \p BB and add known facts to work-list. 15006c3fb27SDimitry Andric void addInfoFor(BasicBlock &BB); 15106c3fb27SDimitry Andric 15206c3fb27SDimitry Andric /// Returns true if we can add a known condition from BB to its successor 15306c3fb27SDimitry Andric /// block Succ. 15406c3fb27SDimitry Andric bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ) const { 15506c3fb27SDimitry Andric return DT.dominates(BasicBlockEdge(&BB, Succ), Succ); 15606c3fb27SDimitry Andric } 15706c3fb27SDimitry Andric }; 15804eeddc0SDimitry Andric 15981ad6265SDimitry Andric class ConstraintInfo; 16004eeddc0SDimitry Andric 16181ad6265SDimitry Andric struct StackEntry { 16281ad6265SDimitry Andric unsigned NumIn; 16381ad6265SDimitry Andric unsigned NumOut; 16481ad6265SDimitry Andric bool IsSigned = false; 16581ad6265SDimitry Andric /// Variables that can be removed from the system once the stack entry gets 16681ad6265SDimitry Andric /// removed. 16781ad6265SDimitry Andric SmallVector<Value *, 2> ValuesToRelease; 16881ad6265SDimitry Andric 169bdd1243dSDimitry Andric StackEntry(unsigned NumIn, unsigned NumOut, bool IsSigned, 17081ad6265SDimitry Andric SmallVector<Value *, 2> ValuesToRelease) 171bdd1243dSDimitry Andric : NumIn(NumIn), NumOut(NumOut), IsSigned(IsSigned), 17281ad6265SDimitry Andric ValuesToRelease(ValuesToRelease) {} 17304eeddc0SDimitry Andric }; 17404eeddc0SDimitry Andric 17581ad6265SDimitry Andric /// Struct to express a pre-condition of the form %Op0 Pred %Op1. 17681ad6265SDimitry Andric struct PreconditionTy { 17781ad6265SDimitry Andric CmpInst::Predicate Pred; 17881ad6265SDimitry Andric Value *Op0; 17981ad6265SDimitry Andric Value *Op1; 18004eeddc0SDimitry Andric 18181ad6265SDimitry Andric PreconditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1) 18281ad6265SDimitry Andric : Pred(Pred), Op0(Op0), Op1(Op1) {} 18381ad6265SDimitry Andric }; 18404eeddc0SDimitry Andric 18581ad6265SDimitry Andric struct ConstraintTy { 18681ad6265SDimitry Andric SmallVector<int64_t, 8> Coefficients; 18781ad6265SDimitry Andric SmallVector<PreconditionTy, 2> Preconditions; 18804eeddc0SDimitry Andric 189bdd1243dSDimitry Andric SmallVector<SmallVector<int64_t, 8>> ExtraInfo; 190bdd1243dSDimitry Andric 19181ad6265SDimitry Andric bool IsSigned = false; 19204eeddc0SDimitry Andric 19381ad6265SDimitry Andric ConstraintTy() = default; 19404eeddc0SDimitry Andric 19506c3fb27SDimitry Andric ConstraintTy(SmallVector<int64_t, 8> Coefficients, bool IsSigned, bool IsEq, 19606c3fb27SDimitry Andric bool IsNe) 19706c3fb27SDimitry Andric : Coefficients(Coefficients), IsSigned(IsSigned), IsEq(IsEq), IsNe(IsNe) { 19806c3fb27SDimitry Andric } 19981ad6265SDimitry Andric 20081ad6265SDimitry Andric unsigned size() const { return Coefficients.size(); } 20181ad6265SDimitry Andric 20281ad6265SDimitry Andric unsigned empty() const { return Coefficients.empty(); } 20304eeddc0SDimitry Andric 20481ad6265SDimitry Andric /// Returns true if all preconditions for this list of constraints are 20581ad6265SDimitry Andric /// satisfied given \p CS and the corresponding \p Value2Index mapping. 20681ad6265SDimitry Andric bool isValid(const ConstraintInfo &Info) const; 20706c3fb27SDimitry Andric 20806c3fb27SDimitry Andric bool isEq() const { return IsEq; } 20906c3fb27SDimitry Andric 21006c3fb27SDimitry Andric bool isNe() const { return IsNe; } 21106c3fb27SDimitry Andric 21206c3fb27SDimitry Andric /// Check if the current constraint is implied by the given ConstraintSystem. 21306c3fb27SDimitry Andric /// 21406c3fb27SDimitry Andric /// \return true or false if the constraint is proven to be respectively true, 21506c3fb27SDimitry Andric /// or false. When the constraint cannot be proven to be either true or false, 21606c3fb27SDimitry Andric /// std::nullopt is returned. 21706c3fb27SDimitry Andric std::optional<bool> isImpliedBy(const ConstraintSystem &CS) const; 21806c3fb27SDimitry Andric 21906c3fb27SDimitry Andric private: 22006c3fb27SDimitry Andric bool IsEq = false; 22106c3fb27SDimitry Andric bool IsNe = false; 22281ad6265SDimitry Andric }; 22381ad6265SDimitry Andric 22481ad6265SDimitry Andric /// Wrapper encapsulating separate constraint systems and corresponding value 22581ad6265SDimitry Andric /// mappings for both unsigned and signed information. Facts are added to and 22681ad6265SDimitry Andric /// conditions are checked against the corresponding system depending on the 22781ad6265SDimitry Andric /// signed-ness of their predicates. While the information is kept separate 22881ad6265SDimitry Andric /// based on signed-ness, certain conditions can be transferred between the two 22981ad6265SDimitry Andric /// systems. 23081ad6265SDimitry Andric class ConstraintInfo { 23181ad6265SDimitry Andric 23281ad6265SDimitry Andric ConstraintSystem UnsignedCS; 23381ad6265SDimitry Andric ConstraintSystem SignedCS; 23481ad6265SDimitry Andric 235bdd1243dSDimitry Andric const DataLayout &DL; 236bdd1243dSDimitry Andric 23781ad6265SDimitry Andric public: 23806c3fb27SDimitry Andric ConstraintInfo(const DataLayout &DL, ArrayRef<Value *> FunctionArgs) 23906c3fb27SDimitry Andric : UnsignedCS(FunctionArgs), SignedCS(FunctionArgs), DL(DL) {} 240bdd1243dSDimitry Andric 24181ad6265SDimitry Andric DenseMap<Value *, unsigned> &getValue2Index(bool Signed) { 24206c3fb27SDimitry Andric return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index(); 24381ad6265SDimitry Andric } 24481ad6265SDimitry Andric const DenseMap<Value *, unsigned> &getValue2Index(bool Signed) const { 24506c3fb27SDimitry Andric return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index(); 24681ad6265SDimitry Andric } 24781ad6265SDimitry Andric 24881ad6265SDimitry Andric ConstraintSystem &getCS(bool Signed) { 24981ad6265SDimitry Andric return Signed ? SignedCS : UnsignedCS; 25081ad6265SDimitry Andric } 25181ad6265SDimitry Andric const ConstraintSystem &getCS(bool Signed) const { 25281ad6265SDimitry Andric return Signed ? SignedCS : UnsignedCS; 25381ad6265SDimitry Andric } 25481ad6265SDimitry Andric 25581ad6265SDimitry Andric void popLastConstraint(bool Signed) { getCS(Signed).popLastConstraint(); } 25681ad6265SDimitry Andric void popLastNVariables(bool Signed, unsigned N) { 25781ad6265SDimitry Andric getCS(Signed).popLastNVariables(N); 25881ad6265SDimitry Andric } 25981ad6265SDimitry Andric 26081ad6265SDimitry Andric bool doesHold(CmpInst::Predicate Pred, Value *A, Value *B) const; 26181ad6265SDimitry Andric 262bdd1243dSDimitry Andric void addFact(CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn, 263bdd1243dSDimitry Andric unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack); 26481ad6265SDimitry Andric 26581ad6265SDimitry Andric /// Turn a comparison of the form \p Op0 \p Pred \p Op1 into a vector of 26681ad6265SDimitry Andric /// constraints, using indices from the corresponding constraint system. 267bdd1243dSDimitry Andric /// New variables that need to be added to the system are collected in 268bdd1243dSDimitry Andric /// \p NewVariables. 26981ad6265SDimitry Andric ConstraintTy getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1, 270bdd1243dSDimitry Andric SmallVectorImpl<Value *> &NewVariables) const; 27181ad6265SDimitry Andric 272bdd1243dSDimitry Andric /// Turns a comparison of the form \p Op0 \p Pred \p Op1 into a vector of 273bdd1243dSDimitry Andric /// constraints using getConstraint. Returns an empty constraint if the result 274bdd1243dSDimitry Andric /// cannot be used to query the existing constraint system, e.g. because it 275bdd1243dSDimitry Andric /// would require adding new variables. Also tries to convert signed 276bdd1243dSDimitry Andric /// predicates to unsigned ones if possible to allow using the unsigned system 277bdd1243dSDimitry Andric /// which increases the effectiveness of the signed <-> unsigned transfer 278bdd1243dSDimitry Andric /// logic. 279bdd1243dSDimitry Andric ConstraintTy getConstraintForSolving(CmpInst::Predicate Pred, Value *Op0, 280bdd1243dSDimitry Andric Value *Op1) const; 28181ad6265SDimitry Andric 28281ad6265SDimitry Andric /// Try to add information from \p A \p Pred \p B to the unsigned/signed 28381ad6265SDimitry Andric /// system if \p Pred is signed/unsigned. 28481ad6265SDimitry Andric void transferToOtherSystem(CmpInst::Predicate Pred, Value *A, Value *B, 285bdd1243dSDimitry Andric unsigned NumIn, unsigned NumOut, 28681ad6265SDimitry Andric SmallVectorImpl<StackEntry> &DFSInStack); 28704eeddc0SDimitry Andric }; 28804eeddc0SDimitry Andric 289bdd1243dSDimitry Andric /// Represents a (Coefficient * Variable) entry after IR decomposition. 290bdd1243dSDimitry Andric struct DecompEntry { 291bdd1243dSDimitry Andric int64_t Coefficient; 292bdd1243dSDimitry Andric Value *Variable; 293bdd1243dSDimitry Andric /// True if the variable is known positive in the current constraint. 294bdd1243dSDimitry Andric bool IsKnownNonNegative; 295bdd1243dSDimitry Andric 296bdd1243dSDimitry Andric DecompEntry(int64_t Coefficient, Value *Variable, 297bdd1243dSDimitry Andric bool IsKnownNonNegative = false) 298bdd1243dSDimitry Andric : Coefficient(Coefficient), Variable(Variable), 299bdd1243dSDimitry Andric IsKnownNonNegative(IsKnownNonNegative) {} 300bdd1243dSDimitry Andric }; 301bdd1243dSDimitry Andric 302bdd1243dSDimitry Andric /// Represents an Offset + Coefficient1 * Variable1 + ... decomposition. 303bdd1243dSDimitry Andric struct Decomposition { 304bdd1243dSDimitry Andric int64_t Offset = 0; 305bdd1243dSDimitry Andric SmallVector<DecompEntry, 3> Vars; 306bdd1243dSDimitry Andric 307bdd1243dSDimitry Andric Decomposition(int64_t Offset) : Offset(Offset) {} 308bdd1243dSDimitry Andric Decomposition(Value *V, bool IsKnownNonNegative = false) { 309bdd1243dSDimitry Andric Vars.emplace_back(1, V, IsKnownNonNegative); 310bdd1243dSDimitry Andric } 311bdd1243dSDimitry Andric Decomposition(int64_t Offset, ArrayRef<DecompEntry> Vars) 312bdd1243dSDimitry Andric : Offset(Offset), Vars(Vars) {} 313bdd1243dSDimitry Andric 314bdd1243dSDimitry Andric void add(int64_t OtherOffset) { 315bdd1243dSDimitry Andric Offset = addWithOverflow(Offset, OtherOffset); 316bdd1243dSDimitry Andric } 317bdd1243dSDimitry Andric 318bdd1243dSDimitry Andric void add(const Decomposition &Other) { 319bdd1243dSDimitry Andric add(Other.Offset); 320bdd1243dSDimitry Andric append_range(Vars, Other.Vars); 321bdd1243dSDimitry Andric } 322bdd1243dSDimitry Andric 323bdd1243dSDimitry Andric void mul(int64_t Factor) { 324bdd1243dSDimitry Andric Offset = multiplyWithOverflow(Offset, Factor); 325bdd1243dSDimitry Andric for (auto &Var : Vars) 326bdd1243dSDimitry Andric Var.Coefficient = multiplyWithOverflow(Var.Coefficient, Factor); 327bdd1243dSDimitry Andric } 328bdd1243dSDimitry Andric }; 329bdd1243dSDimitry Andric 33004eeddc0SDimitry Andric } // namespace 33104eeddc0SDimitry Andric 332bdd1243dSDimitry Andric static Decomposition decompose(Value *V, 333bdd1243dSDimitry Andric SmallVectorImpl<PreconditionTy> &Preconditions, 334bdd1243dSDimitry Andric bool IsSigned, const DataLayout &DL); 33581ad6265SDimitry Andric 336bdd1243dSDimitry Andric static bool canUseSExt(ConstantInt *CI) { 33781ad6265SDimitry Andric const APInt &Val = CI->getValue(); 33881ad6265SDimitry Andric return Val.sgt(MinSignedConstraintValue) && Val.slt(MaxConstraintValue); 339bdd1243dSDimitry Andric } 340bdd1243dSDimitry Andric 341bdd1243dSDimitry Andric static Decomposition 34206c3fb27SDimitry Andric decomposeGEP(GEPOperator &GEP, SmallVectorImpl<PreconditionTy> &Preconditions, 34306c3fb27SDimitry Andric bool IsSigned, const DataLayout &DL) { 344bdd1243dSDimitry Andric // Do not reason about pointers where the index size is larger than 64 bits, 345bdd1243dSDimitry Andric // as the coefficients used to encode constraints are 64 bit integers. 346bdd1243dSDimitry Andric if (DL.getIndexTypeSizeInBits(GEP.getPointerOperand()->getType()) > 64) 347bdd1243dSDimitry Andric return &GEP; 348bdd1243dSDimitry Andric 349bdd1243dSDimitry Andric if (!GEP.isInBounds()) 350bdd1243dSDimitry Andric return &GEP; 351bdd1243dSDimitry Andric 352bdd1243dSDimitry Andric assert(!IsSigned && "The logic below only supports decomposition for " 353bdd1243dSDimitry Andric "unsinged predicates at the moment."); 354bdd1243dSDimitry Andric Type *PtrTy = GEP.getType()->getScalarType(); 355bdd1243dSDimitry Andric unsigned BitWidth = DL.getIndexTypeSizeInBits(PtrTy); 356bdd1243dSDimitry Andric MapVector<Value *, APInt> VariableOffsets; 357bdd1243dSDimitry Andric APInt ConstantOffset(BitWidth, 0); 358bdd1243dSDimitry Andric if (!GEP.collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset)) 359bdd1243dSDimitry Andric return &GEP; 360bdd1243dSDimitry Andric 361bdd1243dSDimitry Andric // Handle the (gep (gep ....), C) case by incrementing the constant 362bdd1243dSDimitry Andric // coefficient of the inner GEP, if C is a constant. 36306c3fb27SDimitry Andric auto *InnerGEP = dyn_cast<GEPOperator>(GEP.getPointerOperand()); 364bdd1243dSDimitry Andric if (VariableOffsets.empty() && InnerGEP && InnerGEP->getNumOperands() == 2) { 365bdd1243dSDimitry Andric auto Result = decompose(InnerGEP, Preconditions, IsSigned, DL); 366bdd1243dSDimitry Andric Result.add(ConstantOffset.getSExtValue()); 367bdd1243dSDimitry Andric 368bdd1243dSDimitry Andric if (ConstantOffset.isNegative()) { 369bdd1243dSDimitry Andric unsigned Scale = DL.getTypeAllocSize(InnerGEP->getResultElementType()); 370bdd1243dSDimitry Andric int64_t ConstantOffsetI = ConstantOffset.getSExtValue(); 371bdd1243dSDimitry Andric if (ConstantOffsetI % Scale != 0) 372bdd1243dSDimitry Andric return &GEP; 373bdd1243dSDimitry Andric // Add pre-condition ensuring the GEP is increasing monotonically and 374bdd1243dSDimitry Andric // can be de-composed. 375bdd1243dSDimitry Andric // Both sides are normalized by being divided by Scale. 376bdd1243dSDimitry Andric Preconditions.emplace_back( 377bdd1243dSDimitry Andric CmpInst::ICMP_SGE, InnerGEP->getOperand(1), 378bdd1243dSDimitry Andric ConstantInt::get(InnerGEP->getOperand(1)->getType(), 379bdd1243dSDimitry Andric -1 * (ConstantOffsetI / Scale))); 380bdd1243dSDimitry Andric } 381bdd1243dSDimitry Andric return Result; 382bdd1243dSDimitry Andric } 383bdd1243dSDimitry Andric 384bdd1243dSDimitry Andric Decomposition Result(ConstantOffset.getSExtValue(), 385bdd1243dSDimitry Andric DecompEntry(1, GEP.getPointerOperand())); 386bdd1243dSDimitry Andric for (auto [Index, Scale] : VariableOffsets) { 387bdd1243dSDimitry Andric auto IdxResult = decompose(Index, Preconditions, IsSigned, DL); 388bdd1243dSDimitry Andric IdxResult.mul(Scale.getSExtValue()); 389bdd1243dSDimitry Andric Result.add(IdxResult); 390bdd1243dSDimitry Andric 391bdd1243dSDimitry Andric // If Op0 is signed non-negative, the GEP is increasing monotonically and 392bdd1243dSDimitry Andric // can be de-composed. 393bdd1243dSDimitry Andric if (!isKnownNonNegative(Index, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1)) 394bdd1243dSDimitry Andric Preconditions.emplace_back(CmpInst::ICMP_SGE, Index, 395bdd1243dSDimitry Andric ConstantInt::get(Index->getType(), 0)); 396bdd1243dSDimitry Andric } 397bdd1243dSDimitry Andric return Result; 398bdd1243dSDimitry Andric } 399bdd1243dSDimitry Andric 400bdd1243dSDimitry Andric // Decomposes \p V into a constant offset + list of pairs { Coefficient, 401bdd1243dSDimitry Andric // Variable } where Coefficient * Variable. The sum of the constant offset and 402bdd1243dSDimitry Andric // pairs equals \p V. 403bdd1243dSDimitry Andric static Decomposition decompose(Value *V, 404bdd1243dSDimitry Andric SmallVectorImpl<PreconditionTy> &Preconditions, 405bdd1243dSDimitry Andric bool IsSigned, const DataLayout &DL) { 406bdd1243dSDimitry Andric 407bdd1243dSDimitry Andric auto MergeResults = [&Preconditions, IsSigned, &DL](Value *A, Value *B, 408bdd1243dSDimitry Andric bool IsSignedB) { 409bdd1243dSDimitry Andric auto ResA = decompose(A, Preconditions, IsSigned, DL); 410bdd1243dSDimitry Andric auto ResB = decompose(B, Preconditions, IsSignedB, DL); 411bdd1243dSDimitry Andric ResA.add(ResB); 412bdd1243dSDimitry Andric return ResA; 41381ad6265SDimitry Andric }; 414bdd1243dSDimitry Andric 415*b121cb00SDimitry Andric Type *Ty = V->getType()->getScalarType(); 416*b121cb00SDimitry Andric if (Ty->isPointerTy() && !IsSigned) { 417*b121cb00SDimitry Andric if (auto *GEP = dyn_cast<GEPOperator>(V)) 418*b121cb00SDimitry Andric return decomposeGEP(*GEP, Preconditions, IsSigned, DL); 419*b121cb00SDimitry Andric return V; 420*b121cb00SDimitry Andric } 421*b121cb00SDimitry Andric 422*b121cb00SDimitry Andric // Don't handle integers > 64 bit. Our coefficients are 64-bit large, so 423*b121cb00SDimitry Andric // coefficient add/mul may wrap, while the operation in the full bit width 424*b121cb00SDimitry Andric // would not. 425*b121cb00SDimitry Andric if (!Ty->isIntegerTy() || Ty->getIntegerBitWidth() > 64) 426*b121cb00SDimitry Andric return V; 427*b121cb00SDimitry Andric 42881ad6265SDimitry Andric // Decompose \p V used with a signed predicate. 42981ad6265SDimitry Andric if (IsSigned) { 430e8d8bef9SDimitry Andric if (auto *CI = dyn_cast<ConstantInt>(V)) { 431bdd1243dSDimitry Andric if (canUseSExt(CI)) 432bdd1243dSDimitry Andric return CI->getSExtValue(); 433e8d8bef9SDimitry Andric } 434bdd1243dSDimitry Andric Value *Op0; 435bdd1243dSDimitry Andric Value *Op1; 436bdd1243dSDimitry Andric if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) 437bdd1243dSDimitry Andric return MergeResults(Op0, Op1, IsSigned); 43881ad6265SDimitry Andric 43906c3fb27SDimitry Andric ConstantInt *CI; 4408a4dda33SDimitry Andric if (match(V, m_NSWMul(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI)) { 44106c3fb27SDimitry Andric auto Result = decompose(Op0, Preconditions, IsSigned, DL); 44206c3fb27SDimitry Andric Result.mul(CI->getSExtValue()); 44306c3fb27SDimitry Andric return Result; 44406c3fb27SDimitry Andric } 44506c3fb27SDimitry Andric 446bdd1243dSDimitry Andric return V; 44781ad6265SDimitry Andric } 44881ad6265SDimitry Andric 44981ad6265SDimitry Andric if (auto *CI = dyn_cast<ConstantInt>(V)) { 45081ad6265SDimitry Andric if (CI->uge(MaxConstraintValue)) 451bdd1243dSDimitry Andric return V; 452bdd1243dSDimitry Andric return int64_t(CI->getZExtValue()); 453fe6060f1SDimitry Andric } 454fe6060f1SDimitry Andric 455e8d8bef9SDimitry Andric Value *Op0; 456bdd1243dSDimitry Andric bool IsKnownNonNegative = false; 457bdd1243dSDimitry Andric if (match(V, m_ZExt(m_Value(Op0)))) { 458bdd1243dSDimitry Andric IsKnownNonNegative = true; 459fe6060f1SDimitry Andric V = Op0; 460bdd1243dSDimitry Andric } 461fe6060f1SDimitry Andric 462e8d8bef9SDimitry Andric Value *Op1; 463e8d8bef9SDimitry Andric ConstantInt *CI; 464bdd1243dSDimitry Andric if (match(V, m_NUWAdd(m_Value(Op0), m_Value(Op1)))) { 465bdd1243dSDimitry Andric return MergeResults(Op0, Op1, IsSigned); 466bdd1243dSDimitry Andric } 467bdd1243dSDimitry Andric if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) { 468bdd1243dSDimitry Andric if (!isKnownNonNegative(Op0, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1)) 469bdd1243dSDimitry Andric Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0, 470bdd1243dSDimitry Andric ConstantInt::get(Op0->getType(), 0)); 471bdd1243dSDimitry Andric if (!isKnownNonNegative(Op1, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1)) 472bdd1243dSDimitry Andric Preconditions.emplace_back(CmpInst::ICMP_SGE, Op1, 473bdd1243dSDimitry Andric ConstantInt::get(Op1->getType(), 0)); 474bdd1243dSDimitry Andric 475bdd1243dSDimitry Andric return MergeResults(Op0, Op1, IsSigned); 476bdd1243dSDimitry Andric } 477bdd1243dSDimitry Andric 47881ad6265SDimitry Andric if (match(V, m_Add(m_Value(Op0), m_ConstantInt(CI))) && CI->isNegative() && 479bdd1243dSDimitry Andric canUseSExt(CI)) { 48081ad6265SDimitry Andric Preconditions.emplace_back( 48181ad6265SDimitry Andric CmpInst::ICMP_UGE, Op0, 48281ad6265SDimitry Andric ConstantInt::get(Op0->getType(), CI->getSExtValue() * -1)); 483bdd1243dSDimitry Andric return MergeResults(Op0, CI, true); 48481ad6265SDimitry Andric } 485e8d8bef9SDimitry Andric 48606c3fb27SDimitry Andric // Decompose or as an add if there are no common bits between the operands. 48706c3fb27SDimitry Andric if (match(V, m_Or(m_Value(Op0), m_ConstantInt(CI))) && 48806c3fb27SDimitry Andric haveNoCommonBitsSet(Op0, CI, DL)) { 48906c3fb27SDimitry Andric return MergeResults(Op0, CI, IsSigned); 49006c3fb27SDimitry Andric } 49106c3fb27SDimitry Andric 492bdd1243dSDimitry Andric if (match(V, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI)) { 49306c3fb27SDimitry Andric if (CI->getSExtValue() < 0 || CI->getSExtValue() >= 64) 49406c3fb27SDimitry Andric return {V, IsKnownNonNegative}; 495bdd1243dSDimitry Andric auto Result = decompose(Op1, Preconditions, IsSigned, DL); 49606c3fb27SDimitry Andric Result.mul(int64_t{1} << CI->getSExtValue()); 497bdd1243dSDimitry Andric return Result; 498bdd1243dSDimitry Andric } 499bdd1243dSDimitry Andric 500bdd1243dSDimitry Andric if (match(V, m_NUWMul(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI) && 501bdd1243dSDimitry Andric (!CI->isNegative())) { 502bdd1243dSDimitry Andric auto Result = decompose(Op1, Preconditions, IsSigned, DL); 503bdd1243dSDimitry Andric Result.mul(CI->getSExtValue()); 504bdd1243dSDimitry Andric return Result; 505bdd1243dSDimitry Andric } 506bdd1243dSDimitry Andric 507bdd1243dSDimitry Andric if (match(V, m_NUWSub(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI)) 508bdd1243dSDimitry Andric return {-1 * CI->getSExtValue(), {{1, Op0}}}; 509e8d8bef9SDimitry Andric if (match(V, m_NUWSub(m_Value(Op0), m_Value(Op1)))) 510bdd1243dSDimitry Andric return {0, {{1, Op0}, {-1, Op1}}}; 511e8d8bef9SDimitry Andric 512bdd1243dSDimitry Andric return {V, IsKnownNonNegative}; 513e8d8bef9SDimitry Andric } 514e8d8bef9SDimitry Andric 51581ad6265SDimitry Andric ConstraintTy 51681ad6265SDimitry Andric ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1, 517bdd1243dSDimitry Andric SmallVectorImpl<Value *> &NewVariables) const { 518bdd1243dSDimitry Andric assert(NewVariables.empty() && "NewVariables must be empty when passed in"); 51981ad6265SDimitry Andric bool IsEq = false; 52006c3fb27SDimitry Andric bool IsNe = false; 52106c3fb27SDimitry Andric 52281ad6265SDimitry Andric // Try to convert Pred to one of ULE/SLT/SLE/SLT. 52381ad6265SDimitry Andric switch (Pred) { 52481ad6265SDimitry Andric case CmpInst::ICMP_UGT: 52581ad6265SDimitry Andric case CmpInst::ICMP_UGE: 52681ad6265SDimitry Andric case CmpInst::ICMP_SGT: 52781ad6265SDimitry Andric case CmpInst::ICMP_SGE: { 52881ad6265SDimitry Andric Pred = CmpInst::getSwappedPredicate(Pred); 52981ad6265SDimitry Andric std::swap(Op0, Op1); 53081ad6265SDimitry Andric break; 53181ad6265SDimitry Andric } 53281ad6265SDimitry Andric case CmpInst::ICMP_EQ: 53381ad6265SDimitry Andric if (match(Op1, m_Zero())) { 53481ad6265SDimitry Andric Pred = CmpInst::ICMP_ULE; 53581ad6265SDimitry Andric } else { 53681ad6265SDimitry Andric IsEq = true; 53781ad6265SDimitry Andric Pred = CmpInst::ICMP_ULE; 53881ad6265SDimitry Andric } 53981ad6265SDimitry Andric break; 54081ad6265SDimitry Andric case CmpInst::ICMP_NE: 54106c3fb27SDimitry Andric if (match(Op1, m_Zero())) { 54281ad6265SDimitry Andric Pred = CmpInst::getSwappedPredicate(CmpInst::ICMP_UGT); 54381ad6265SDimitry Andric std::swap(Op0, Op1); 54406c3fb27SDimitry Andric } else { 54506c3fb27SDimitry Andric IsNe = true; 54606c3fb27SDimitry Andric Pred = CmpInst::ICMP_ULE; 54706c3fb27SDimitry Andric } 54881ad6265SDimitry Andric break; 54981ad6265SDimitry Andric default: 55081ad6265SDimitry Andric break; 55181ad6265SDimitry Andric } 55281ad6265SDimitry Andric 55381ad6265SDimitry Andric if (Pred != CmpInst::ICMP_ULE && Pred != CmpInst::ICMP_ULT && 55481ad6265SDimitry Andric Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SLT) 55581ad6265SDimitry Andric return {}; 55681ad6265SDimitry Andric 55781ad6265SDimitry Andric SmallVector<PreconditionTy, 4> Preconditions; 55881ad6265SDimitry Andric bool IsSigned = CmpInst::isSigned(Pred); 55981ad6265SDimitry Andric auto &Value2Index = getValue2Index(IsSigned); 56081ad6265SDimitry Andric auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(), 561bdd1243dSDimitry Andric Preconditions, IsSigned, DL); 56281ad6265SDimitry Andric auto BDec = decompose(Op1->stripPointerCastsSameRepresentation(), 563bdd1243dSDimitry Andric Preconditions, IsSigned, DL); 564bdd1243dSDimitry Andric int64_t Offset1 = ADec.Offset; 565bdd1243dSDimitry Andric int64_t Offset2 = BDec.Offset; 56681ad6265SDimitry Andric Offset1 *= -1; 56781ad6265SDimitry Andric 568bdd1243dSDimitry Andric auto &VariablesA = ADec.Vars; 569bdd1243dSDimitry Andric auto &VariablesB = BDec.Vars; 570e8d8bef9SDimitry Andric 571bdd1243dSDimitry Andric // First try to look up \p V in Value2Index and NewVariables. Otherwise add a 572bdd1243dSDimitry Andric // new entry to NewVariables. 573bdd1243dSDimitry Andric DenseMap<Value *, unsigned> NewIndexMap; 574bdd1243dSDimitry Andric auto GetOrAddIndex = [&Value2Index, &NewVariables, 575bdd1243dSDimitry Andric &NewIndexMap](Value *V) -> unsigned { 576fe6060f1SDimitry Andric auto V2I = Value2Index.find(V); 577fe6060f1SDimitry Andric if (V2I != Value2Index.end()) 578fe6060f1SDimitry Andric return V2I->second; 579fe6060f1SDimitry Andric auto Insert = 580bdd1243dSDimitry Andric NewIndexMap.insert({V, Value2Index.size() + NewVariables.size() + 1}); 581bdd1243dSDimitry Andric if (Insert.second) 582bdd1243dSDimitry Andric NewVariables.push_back(V); 583fe6060f1SDimitry Andric return Insert.first->second; 584e8d8bef9SDimitry Andric }; 585e8d8bef9SDimitry Andric 586bdd1243dSDimitry Andric // Make sure all variables have entries in Value2Index or NewVariables. 587bdd1243dSDimitry Andric for (const auto &KV : concat<DecompEntry>(VariablesA, VariablesB)) 588bdd1243dSDimitry Andric GetOrAddIndex(KV.Variable); 589e8d8bef9SDimitry Andric 590e8d8bef9SDimitry Andric // Build result constraint, by first adding all coefficients from A and then 591e8d8bef9SDimitry Andric // subtracting all coefficients from B. 59281ad6265SDimitry Andric ConstraintTy Res( 593bdd1243dSDimitry Andric SmallVector<int64_t, 8>(Value2Index.size() + NewVariables.size() + 1, 0), 59406c3fb27SDimitry Andric IsSigned, IsEq, IsNe); 595bdd1243dSDimitry Andric // Collect variables that are known to be positive in all uses in the 596bdd1243dSDimitry Andric // constraint. 597bdd1243dSDimitry Andric DenseMap<Value *, bool> KnownNonNegativeVariables; 59881ad6265SDimitry Andric auto &R = Res.Coefficients; 599bdd1243dSDimitry Andric for (const auto &KV : VariablesA) { 600bdd1243dSDimitry Andric R[GetOrAddIndex(KV.Variable)] += KV.Coefficient; 601bdd1243dSDimitry Andric auto I = 602bdd1243dSDimitry Andric KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative}); 603bdd1243dSDimitry Andric I.first->second &= KV.IsKnownNonNegative; 604bdd1243dSDimitry Andric } 605e8d8bef9SDimitry Andric 606bdd1243dSDimitry Andric for (const auto &KV : VariablesB) { 60706c3fb27SDimitry Andric if (SubOverflow(R[GetOrAddIndex(KV.Variable)], KV.Coefficient, 60806c3fb27SDimitry Andric R[GetOrAddIndex(KV.Variable)])) 60906c3fb27SDimitry Andric return {}; 610bdd1243dSDimitry Andric auto I = 611bdd1243dSDimitry Andric KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative}); 612bdd1243dSDimitry Andric I.first->second &= KV.IsKnownNonNegative; 613bdd1243dSDimitry Andric } 614e8d8bef9SDimitry Andric 61581ad6265SDimitry Andric int64_t OffsetSum; 61681ad6265SDimitry Andric if (AddOverflow(Offset1, Offset2, OffsetSum)) 61781ad6265SDimitry Andric return {}; 61881ad6265SDimitry Andric if (Pred == (IsSigned ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT)) 61981ad6265SDimitry Andric if (AddOverflow(OffsetSum, int64_t(-1), OffsetSum)) 62081ad6265SDimitry Andric return {}; 62181ad6265SDimitry Andric R[0] = OffsetSum; 62281ad6265SDimitry Andric Res.Preconditions = std::move(Preconditions); 623bdd1243dSDimitry Andric 624bdd1243dSDimitry Andric // Remove any (Coefficient, Variable) entry where the Coefficient is 0 for new 625bdd1243dSDimitry Andric // variables. 626bdd1243dSDimitry Andric while (!NewVariables.empty()) { 627bdd1243dSDimitry Andric int64_t Last = R.back(); 628bdd1243dSDimitry Andric if (Last != 0) 629bdd1243dSDimitry Andric break; 630bdd1243dSDimitry Andric R.pop_back(); 631bdd1243dSDimitry Andric Value *RemovedV = NewVariables.pop_back_val(); 632bdd1243dSDimitry Andric NewIndexMap.erase(RemovedV); 633bdd1243dSDimitry Andric } 634bdd1243dSDimitry Andric 635bdd1243dSDimitry Andric // Add extra constraints for variables that are known positive. 636bdd1243dSDimitry Andric for (auto &KV : KnownNonNegativeVariables) { 63706c3fb27SDimitry Andric if (!KV.second || 63806c3fb27SDimitry Andric (!Value2Index.contains(KV.first) && !NewIndexMap.contains(KV.first))) 639bdd1243dSDimitry Andric continue; 640bdd1243dSDimitry Andric SmallVector<int64_t, 8> C(Value2Index.size() + NewVariables.size() + 1, 0); 641bdd1243dSDimitry Andric C[GetOrAddIndex(KV.first)] = -1; 642bdd1243dSDimitry Andric Res.ExtraInfo.push_back(C); 643bdd1243dSDimitry Andric } 64481ad6265SDimitry Andric return Res; 645e8d8bef9SDimitry Andric } 646e8d8bef9SDimitry Andric 647bdd1243dSDimitry Andric ConstraintTy ConstraintInfo::getConstraintForSolving(CmpInst::Predicate Pred, 648bdd1243dSDimitry Andric Value *Op0, 649bdd1243dSDimitry Andric Value *Op1) const { 650bdd1243dSDimitry Andric // If both operands are known to be non-negative, change signed predicates to 651bdd1243dSDimitry Andric // unsigned ones. This increases the reasoning effectiveness in combination 652bdd1243dSDimitry Andric // with the signed <-> unsigned transfer logic. 653bdd1243dSDimitry Andric if (CmpInst::isSigned(Pred) && 654bdd1243dSDimitry Andric isKnownNonNegative(Op0, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1) && 655bdd1243dSDimitry Andric isKnownNonNegative(Op1, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1)) 656bdd1243dSDimitry Andric Pred = CmpInst::getUnsignedPredicate(Pred); 657bdd1243dSDimitry Andric 658bdd1243dSDimitry Andric SmallVector<Value *> NewVariables; 659bdd1243dSDimitry Andric ConstraintTy R = getConstraint(Pred, Op0, Op1, NewVariables); 66006c3fb27SDimitry Andric if (!NewVariables.empty()) 661bdd1243dSDimitry Andric return {}; 662bdd1243dSDimitry Andric return R; 663bdd1243dSDimitry Andric } 664bdd1243dSDimitry Andric 66581ad6265SDimitry Andric bool ConstraintTy::isValid(const ConstraintInfo &Info) const { 66681ad6265SDimitry Andric return Coefficients.size() > 0 && 66781ad6265SDimitry Andric all_of(Preconditions, [&Info](const PreconditionTy &C) { 66881ad6265SDimitry Andric return Info.doesHold(C.Pred, C.Op0, C.Op1); 66981ad6265SDimitry Andric }); 67081ad6265SDimitry Andric } 67181ad6265SDimitry Andric 67206c3fb27SDimitry Andric std::optional<bool> 67306c3fb27SDimitry Andric ConstraintTy::isImpliedBy(const ConstraintSystem &CS) const { 67406c3fb27SDimitry Andric bool IsConditionImplied = CS.isConditionImplied(Coefficients); 67506c3fb27SDimitry Andric 67606c3fb27SDimitry Andric if (IsEq || IsNe) { 67706c3fb27SDimitry Andric auto NegatedOrEqual = ConstraintSystem::negateOrEqual(Coefficients); 67806c3fb27SDimitry Andric bool IsNegatedOrEqualImplied = 67906c3fb27SDimitry Andric !NegatedOrEqual.empty() && CS.isConditionImplied(NegatedOrEqual); 68006c3fb27SDimitry Andric 68106c3fb27SDimitry Andric // In order to check that `%a == %b` is true (equality), both conditions `%a 68206c3fb27SDimitry Andric // >= %b` and `%a <= %b` must hold true. When checking for equality (`IsEq` 68306c3fb27SDimitry Andric // is true), we return true if they both hold, false in the other cases. 68406c3fb27SDimitry Andric if (IsConditionImplied && IsNegatedOrEqualImplied) 68506c3fb27SDimitry Andric return IsEq; 68606c3fb27SDimitry Andric 68706c3fb27SDimitry Andric auto Negated = ConstraintSystem::negate(Coefficients); 68806c3fb27SDimitry Andric bool IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated); 68906c3fb27SDimitry Andric 69006c3fb27SDimitry Andric auto StrictLessThan = ConstraintSystem::toStrictLessThan(Coefficients); 69106c3fb27SDimitry Andric bool IsStrictLessThanImplied = 69206c3fb27SDimitry Andric !StrictLessThan.empty() && CS.isConditionImplied(StrictLessThan); 69306c3fb27SDimitry Andric 69406c3fb27SDimitry Andric // In order to check that `%a != %b` is true (non-equality), either 69506c3fb27SDimitry Andric // condition `%a > %b` or `%a < %b` must hold true. When checking for 69606c3fb27SDimitry Andric // non-equality (`IsNe` is true), we return true if one of the two holds, 69706c3fb27SDimitry Andric // false in the other cases. 69806c3fb27SDimitry Andric if (IsNegatedImplied || IsStrictLessThanImplied) 69906c3fb27SDimitry Andric return IsNe; 70006c3fb27SDimitry Andric 70106c3fb27SDimitry Andric return std::nullopt; 70206c3fb27SDimitry Andric } 70306c3fb27SDimitry Andric 70406c3fb27SDimitry Andric if (IsConditionImplied) 70506c3fb27SDimitry Andric return true; 70606c3fb27SDimitry Andric 70706c3fb27SDimitry Andric auto Negated = ConstraintSystem::negate(Coefficients); 70806c3fb27SDimitry Andric auto IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated); 70906c3fb27SDimitry Andric if (IsNegatedImplied) 71006c3fb27SDimitry Andric return false; 71106c3fb27SDimitry Andric 71206c3fb27SDimitry Andric // Neither the condition nor its negated holds, did not prove anything. 71306c3fb27SDimitry Andric return std::nullopt; 71406c3fb27SDimitry Andric } 71506c3fb27SDimitry Andric 71681ad6265SDimitry Andric bool ConstraintInfo::doesHold(CmpInst::Predicate Pred, Value *A, 71781ad6265SDimitry Andric Value *B) const { 718bdd1243dSDimitry Andric auto R = getConstraintForSolving(Pred, A, B); 71906c3fb27SDimitry Andric return R.isValid(*this) && 720bdd1243dSDimitry Andric getCS(R.IsSigned).isConditionImplied(R.Coefficients); 72181ad6265SDimitry Andric } 72281ad6265SDimitry Andric 72381ad6265SDimitry Andric void ConstraintInfo::transferToOtherSystem( 724bdd1243dSDimitry Andric CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn, 72581ad6265SDimitry Andric unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack) { 72681ad6265SDimitry Andric // Check if we can combine facts from the signed and unsigned systems to 72781ad6265SDimitry Andric // derive additional facts. 72881ad6265SDimitry Andric if (!A->getType()->isIntegerTy()) 72981ad6265SDimitry Andric return; 73081ad6265SDimitry Andric // FIXME: This currently depends on the order we add facts. Ideally we 73181ad6265SDimitry Andric // would first add all known facts and only then try to add additional 73281ad6265SDimitry Andric // facts. 73381ad6265SDimitry Andric switch (Pred) { 73481ad6265SDimitry Andric default: 73581ad6265SDimitry Andric break; 73681ad6265SDimitry Andric case CmpInst::ICMP_ULT: 73781ad6265SDimitry Andric // If B is a signed positive constant, A >=s 0 and A <s B. 73881ad6265SDimitry Andric if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0))) { 739bdd1243dSDimitry Andric addFact(CmpInst::ICMP_SGE, A, ConstantInt::get(B->getType(), 0), NumIn, 740bdd1243dSDimitry Andric NumOut, DFSInStack); 741bdd1243dSDimitry Andric addFact(CmpInst::ICMP_SLT, A, B, NumIn, NumOut, DFSInStack); 74281ad6265SDimitry Andric } 74381ad6265SDimitry Andric break; 74481ad6265SDimitry Andric case CmpInst::ICMP_SLT: 74581ad6265SDimitry Andric if (doesHold(CmpInst::ICMP_SGE, A, ConstantInt::get(B->getType(), 0))) 746bdd1243dSDimitry Andric addFact(CmpInst::ICMP_ULT, A, B, NumIn, NumOut, DFSInStack); 74781ad6265SDimitry Andric break; 74806c3fb27SDimitry Andric case CmpInst::ICMP_SGT: { 74981ad6265SDimitry Andric if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), -1))) 750bdd1243dSDimitry Andric addFact(CmpInst::ICMP_UGE, A, ConstantInt::get(B->getType(), 0), NumIn, 751bdd1243dSDimitry Andric NumOut, DFSInStack); 75206c3fb27SDimitry Andric if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0))) 75306c3fb27SDimitry Andric addFact(CmpInst::ICMP_UGT, A, B, NumIn, NumOut, DFSInStack); 75406c3fb27SDimitry Andric 75581ad6265SDimitry Andric break; 75606c3fb27SDimitry Andric } 75781ad6265SDimitry Andric case CmpInst::ICMP_SGE: 75881ad6265SDimitry Andric if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0))) { 759bdd1243dSDimitry Andric addFact(CmpInst::ICMP_UGE, A, B, NumIn, NumOut, DFSInStack); 76081ad6265SDimitry Andric } 76181ad6265SDimitry Andric break; 76281ad6265SDimitry Andric } 763e8d8bef9SDimitry Andric } 764e8d8bef9SDimitry Andric 765fe6060f1SDimitry Andric #ifndef NDEBUG 76681ad6265SDimitry Andric 76706c3fb27SDimitry Andric static void dumpConstraint(ArrayRef<int64_t> C, 76806c3fb27SDimitry Andric const DenseMap<Value *, unsigned> &Value2Index) { 76906c3fb27SDimitry Andric ConstraintSystem CS(Value2Index); 77081ad6265SDimitry Andric CS.addVariableRowFill(C); 77106c3fb27SDimitry Andric CS.dump(); 77281ad6265SDimitry Andric } 773fe6060f1SDimitry Andric #endif 774fe6060f1SDimitry Andric 77581ad6265SDimitry Andric void State::addInfoFor(BasicBlock &BB) { 776349cc55cSDimitry Andric // True as long as long as the current instruction is guaranteed to execute. 777349cc55cSDimitry Andric bool GuaranteedToExecute = true; 778bdd1243dSDimitry Andric // Queue conditions and assumes. 779349cc55cSDimitry Andric for (Instruction &I : BB) { 780bdd1243dSDimitry Andric if (auto Cmp = dyn_cast<ICmpInst>(&I)) { 78106c3fb27SDimitry Andric for (Use &U : Cmp->uses()) { 78206c3fb27SDimitry Andric auto *UserI = getContextInstForUse(U); 78306c3fb27SDimitry Andric auto *DTN = DT.getNode(UserI->getParent()); 78406c3fb27SDimitry Andric if (!DTN) 78506c3fb27SDimitry Andric continue; 78606c3fb27SDimitry Andric WorkList.push_back(FactOrCheck::getCheck(DTN, &U)); 78706c3fb27SDimitry Andric } 788bdd1243dSDimitry Andric continue; 789bdd1243dSDimitry Andric } 790bdd1243dSDimitry Andric 791bdd1243dSDimitry Andric if (match(&I, m_Intrinsic<Intrinsic::ssub_with_overflow>())) { 79206c3fb27SDimitry Andric WorkList.push_back( 79306c3fb27SDimitry Andric FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I))); 79406c3fb27SDimitry Andric continue; 79506c3fb27SDimitry Andric } 79606c3fb27SDimitry Andric 79706c3fb27SDimitry Andric if (isa<MinMaxIntrinsic>(&I)) { 79806c3fb27SDimitry Andric WorkList.push_back(FactOrCheck::getFact(DT.getNode(&BB), &I)); 799bdd1243dSDimitry Andric continue; 800bdd1243dSDimitry Andric } 801bdd1243dSDimitry Andric 802349cc55cSDimitry Andric Value *Cond; 803349cc55cSDimitry Andric // For now, just handle assumes with a single compare as condition. 804349cc55cSDimitry Andric if (match(&I, m_Intrinsic<Intrinsic::assume>(m_Value(Cond))) && 80581ad6265SDimitry Andric isa<ICmpInst>(Cond)) { 806349cc55cSDimitry Andric if (GuaranteedToExecute) { 807349cc55cSDimitry Andric // The assume is guaranteed to execute when BB is entered, hence Cond 808349cc55cSDimitry Andric // holds on entry to BB. 809bdd1243dSDimitry Andric WorkList.emplace_back(FactOrCheck::getFact(DT.getNode(I.getParent()), 810bdd1243dSDimitry Andric cast<Instruction>(Cond))); 811349cc55cSDimitry Andric } else { 812bdd1243dSDimitry Andric WorkList.emplace_back( 813bdd1243dSDimitry Andric FactOrCheck::getFact(DT.getNode(I.getParent()), &I)); 814349cc55cSDimitry Andric } 815349cc55cSDimitry Andric } 816349cc55cSDimitry Andric GuaranteedToExecute &= isGuaranteedToTransferExecutionToSuccessor(&I); 817349cc55cSDimitry Andric } 818349cc55cSDimitry Andric 819e8d8bef9SDimitry Andric auto *Br = dyn_cast<BranchInst>(BB.getTerminator()); 820e8d8bef9SDimitry Andric if (!Br || !Br->isConditional()) 82181ad6265SDimitry Andric return; 822e8d8bef9SDimitry Andric 823bdd1243dSDimitry Andric Value *Cond = Br->getCondition(); 824e8d8bef9SDimitry Andric 825bdd1243dSDimitry Andric // If the condition is a chain of ORs/AND and the successor only has the 826bdd1243dSDimitry Andric // current block as predecessor, queue conditions for the successor. 827bdd1243dSDimitry Andric Value *Op0, *Op1; 828bdd1243dSDimitry Andric if (match(Cond, m_LogicalOr(m_Value(Op0), m_Value(Op1))) || 829bdd1243dSDimitry Andric match(Cond, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) { 830bdd1243dSDimitry Andric bool IsOr = match(Cond, m_LogicalOr()); 831bdd1243dSDimitry Andric bool IsAnd = match(Cond, m_LogicalAnd()); 832bdd1243dSDimitry Andric // If there's a select that matches both AND and OR, we need to commit to 833bdd1243dSDimitry Andric // one of the options. Arbitrarily pick OR. 834bdd1243dSDimitry Andric if (IsOr && IsAnd) 835bdd1243dSDimitry Andric IsAnd = false; 836bdd1243dSDimitry Andric 837bdd1243dSDimitry Andric BasicBlock *Successor = Br->getSuccessor(IsOr ? 1 : 0); 838bdd1243dSDimitry Andric if (canAddSuccessor(BB, Successor)) { 839bdd1243dSDimitry Andric SmallVector<Value *> CondWorkList; 840bdd1243dSDimitry Andric SmallPtrSet<Value *, 8> SeenCond; 841bdd1243dSDimitry Andric auto QueueValue = [&CondWorkList, &SeenCond](Value *V) { 842bdd1243dSDimitry Andric if (SeenCond.insert(V).second) 843bdd1243dSDimitry Andric CondWorkList.push_back(V); 844bdd1243dSDimitry Andric }; 845bdd1243dSDimitry Andric QueueValue(Op1); 846bdd1243dSDimitry Andric QueueValue(Op0); 847bdd1243dSDimitry Andric while (!CondWorkList.empty()) { 848bdd1243dSDimitry Andric Value *Cur = CondWorkList.pop_back_val(); 849bdd1243dSDimitry Andric if (auto *Cmp = dyn_cast<ICmpInst>(Cur)) { 850bdd1243dSDimitry Andric WorkList.emplace_back( 851bdd1243dSDimitry Andric FactOrCheck::getFact(DT.getNode(Successor), Cmp, IsOr)); 852bdd1243dSDimitry Andric continue; 853bdd1243dSDimitry Andric } 854bdd1243dSDimitry Andric if (IsOr && match(Cur, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) { 855bdd1243dSDimitry Andric QueueValue(Op1); 856bdd1243dSDimitry Andric QueueValue(Op0); 857bdd1243dSDimitry Andric continue; 858bdd1243dSDimitry Andric } 859bdd1243dSDimitry Andric if (IsAnd && match(Cur, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) { 860bdd1243dSDimitry Andric QueueValue(Op1); 861bdd1243dSDimitry Andric QueueValue(Op0); 862bdd1243dSDimitry Andric continue; 863bdd1243dSDimitry Andric } 864bdd1243dSDimitry Andric } 865e8d8bef9SDimitry Andric } 86681ad6265SDimitry Andric return; 867e8d8bef9SDimitry Andric } 868e8d8bef9SDimitry Andric 86981ad6265SDimitry Andric auto *CmpI = dyn_cast<ICmpInst>(Br->getCondition()); 870e8d8bef9SDimitry Andric if (!CmpI) 87181ad6265SDimitry Andric return; 87281ad6265SDimitry Andric if (canAddSuccessor(BB, Br->getSuccessor(0))) 873bdd1243dSDimitry Andric WorkList.emplace_back( 874bdd1243dSDimitry Andric FactOrCheck::getFact(DT.getNode(Br->getSuccessor(0)), CmpI)); 87581ad6265SDimitry Andric if (canAddSuccessor(BB, Br->getSuccessor(1))) 876bdd1243dSDimitry Andric WorkList.emplace_back( 877bdd1243dSDimitry Andric FactOrCheck::getFact(DT.getNode(Br->getSuccessor(1)), CmpI, true)); 878bdd1243dSDimitry Andric } 879bdd1243dSDimitry Andric 88006c3fb27SDimitry Andric namespace { 88106c3fb27SDimitry Andric /// Helper to keep track of a condition and if it should be treated as negated 88206c3fb27SDimitry Andric /// for reproducer construction. 88306c3fb27SDimitry Andric /// Pred == Predicate::BAD_ICMP_PREDICATE indicates that this entry is a 88406c3fb27SDimitry Andric /// placeholder to keep the ReproducerCondStack in sync with DFSInStack. 88506c3fb27SDimitry Andric struct ReproducerEntry { 88606c3fb27SDimitry Andric ICmpInst::Predicate Pred; 88706c3fb27SDimitry Andric Value *LHS; 88806c3fb27SDimitry Andric Value *RHS; 88906c3fb27SDimitry Andric 89006c3fb27SDimitry Andric ReproducerEntry(ICmpInst::Predicate Pred, Value *LHS, Value *RHS) 89106c3fb27SDimitry Andric : Pred(Pred), LHS(LHS), RHS(RHS) {} 89206c3fb27SDimitry Andric }; 89306c3fb27SDimitry Andric } // namespace 89406c3fb27SDimitry Andric 89506c3fb27SDimitry Andric /// Helper function to generate a reproducer function for simplifying \p Cond. 89606c3fb27SDimitry Andric /// The reproducer function contains a series of @llvm.assume calls, one for 89706c3fb27SDimitry Andric /// each condition in \p Stack. For each condition, the operand instruction are 89806c3fb27SDimitry Andric /// cloned until we reach operands that have an entry in \p Value2Index. Those 89906c3fb27SDimitry Andric /// will then be added as function arguments. \p DT is used to order cloned 90006c3fb27SDimitry Andric /// instructions. The reproducer function will get added to \p M, if it is 90106c3fb27SDimitry Andric /// non-null. Otherwise no reproducer function is generated. 90206c3fb27SDimitry Andric static void generateReproducer(CmpInst *Cond, Module *M, 90306c3fb27SDimitry Andric ArrayRef<ReproducerEntry> Stack, 90406c3fb27SDimitry Andric ConstraintInfo &Info, DominatorTree &DT) { 90506c3fb27SDimitry Andric if (!M) 90606c3fb27SDimitry Andric return; 90706c3fb27SDimitry Andric 90806c3fb27SDimitry Andric LLVMContext &Ctx = Cond->getContext(); 90906c3fb27SDimitry Andric 91006c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Creating reproducer for " << *Cond << "\n"); 91106c3fb27SDimitry Andric 91206c3fb27SDimitry Andric ValueToValueMapTy Old2New; 91306c3fb27SDimitry Andric SmallVector<Value *> Args; 91406c3fb27SDimitry Andric SmallPtrSet<Value *, 8> Seen; 91506c3fb27SDimitry Andric // Traverse Cond and its operands recursively until we reach a value that's in 91606c3fb27SDimitry Andric // Value2Index or not an instruction, or not a operation that 91706c3fb27SDimitry Andric // ConstraintElimination can decompose. Such values will be considered as 91806c3fb27SDimitry Andric // external inputs to the reproducer, they are collected and added as function 91906c3fb27SDimitry Andric // arguments later. 92006c3fb27SDimitry Andric auto CollectArguments = [&](ArrayRef<Value *> Ops, bool IsSigned) { 92106c3fb27SDimitry Andric auto &Value2Index = Info.getValue2Index(IsSigned); 92206c3fb27SDimitry Andric SmallVector<Value *, 4> WorkList(Ops); 92306c3fb27SDimitry Andric while (!WorkList.empty()) { 92406c3fb27SDimitry Andric Value *V = WorkList.pop_back_val(); 92506c3fb27SDimitry Andric if (!Seen.insert(V).second) 92606c3fb27SDimitry Andric continue; 92706c3fb27SDimitry Andric if (Old2New.find(V) != Old2New.end()) 92806c3fb27SDimitry Andric continue; 92906c3fb27SDimitry Andric if (isa<Constant>(V)) 93006c3fb27SDimitry Andric continue; 93106c3fb27SDimitry Andric 93206c3fb27SDimitry Andric auto *I = dyn_cast<Instruction>(V); 93306c3fb27SDimitry Andric if (Value2Index.contains(V) || !I || 93406c3fb27SDimitry Andric !isa<CmpInst, BinaryOperator, GEPOperator, CastInst>(V)) { 93506c3fb27SDimitry Andric Old2New[V] = V; 93606c3fb27SDimitry Andric Args.push_back(V); 93706c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << " found external input " << *V << "\n"); 93806c3fb27SDimitry Andric } else { 93906c3fb27SDimitry Andric append_range(WorkList, I->operands()); 94006c3fb27SDimitry Andric } 94106c3fb27SDimitry Andric } 94206c3fb27SDimitry Andric }; 94306c3fb27SDimitry Andric 94406c3fb27SDimitry Andric for (auto &Entry : Stack) 94506c3fb27SDimitry Andric if (Entry.Pred != ICmpInst::BAD_ICMP_PREDICATE) 94606c3fb27SDimitry Andric CollectArguments({Entry.LHS, Entry.RHS}, ICmpInst::isSigned(Entry.Pred)); 94706c3fb27SDimitry Andric CollectArguments(Cond, ICmpInst::isSigned(Cond->getPredicate())); 94806c3fb27SDimitry Andric 94906c3fb27SDimitry Andric SmallVector<Type *> ParamTys; 95006c3fb27SDimitry Andric for (auto *P : Args) 95106c3fb27SDimitry Andric ParamTys.push_back(P->getType()); 95206c3fb27SDimitry Andric 95306c3fb27SDimitry Andric FunctionType *FTy = FunctionType::get(Cond->getType(), ParamTys, 95406c3fb27SDimitry Andric /*isVarArg=*/false); 95506c3fb27SDimitry Andric Function *F = Function::Create(FTy, Function::ExternalLinkage, 95606c3fb27SDimitry Andric Cond->getModule()->getName() + 95706c3fb27SDimitry Andric Cond->getFunction()->getName() + "repro", 95806c3fb27SDimitry Andric M); 95906c3fb27SDimitry Andric // Add arguments to the reproducer function for each external value collected. 96006c3fb27SDimitry Andric for (unsigned I = 0; I < Args.size(); ++I) { 96106c3fb27SDimitry Andric F->getArg(I)->setName(Args[I]->getName()); 96206c3fb27SDimitry Andric Old2New[Args[I]] = F->getArg(I); 96306c3fb27SDimitry Andric } 96406c3fb27SDimitry Andric 96506c3fb27SDimitry Andric BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F); 96606c3fb27SDimitry Andric IRBuilder<> Builder(Entry); 96706c3fb27SDimitry Andric Builder.CreateRet(Builder.getTrue()); 96806c3fb27SDimitry Andric Builder.SetInsertPoint(Entry->getTerminator()); 96906c3fb27SDimitry Andric 97006c3fb27SDimitry Andric // Clone instructions in \p Ops and their operands recursively until reaching 97106c3fb27SDimitry Andric // an value in Value2Index (external input to the reproducer). Update Old2New 97206c3fb27SDimitry Andric // mapping for the original and cloned instructions. Sort instructions to 97306c3fb27SDimitry Andric // clone by dominance, then insert the cloned instructions in the function. 97406c3fb27SDimitry Andric auto CloneInstructions = [&](ArrayRef<Value *> Ops, bool IsSigned) { 97506c3fb27SDimitry Andric SmallVector<Value *, 4> WorkList(Ops); 97606c3fb27SDimitry Andric SmallVector<Instruction *> ToClone; 97706c3fb27SDimitry Andric auto &Value2Index = Info.getValue2Index(IsSigned); 97806c3fb27SDimitry Andric while (!WorkList.empty()) { 97906c3fb27SDimitry Andric Value *V = WorkList.pop_back_val(); 98006c3fb27SDimitry Andric if (Old2New.find(V) != Old2New.end()) 98106c3fb27SDimitry Andric continue; 98206c3fb27SDimitry Andric 98306c3fb27SDimitry Andric auto *I = dyn_cast<Instruction>(V); 98406c3fb27SDimitry Andric if (!Value2Index.contains(V) && I) { 98506c3fb27SDimitry Andric Old2New[V] = nullptr; 98606c3fb27SDimitry Andric ToClone.push_back(I); 98706c3fb27SDimitry Andric append_range(WorkList, I->operands()); 98806c3fb27SDimitry Andric } 98906c3fb27SDimitry Andric } 99006c3fb27SDimitry Andric 99106c3fb27SDimitry Andric sort(ToClone, 99206c3fb27SDimitry Andric [&DT](Instruction *A, Instruction *B) { return DT.dominates(A, B); }); 99306c3fb27SDimitry Andric for (Instruction *I : ToClone) { 99406c3fb27SDimitry Andric Instruction *Cloned = I->clone(); 99506c3fb27SDimitry Andric Old2New[I] = Cloned; 99606c3fb27SDimitry Andric Old2New[I]->setName(I->getName()); 99706c3fb27SDimitry Andric Cloned->insertBefore(&*Builder.GetInsertPoint()); 99806c3fb27SDimitry Andric Cloned->dropUnknownNonDebugMetadata(); 99906c3fb27SDimitry Andric Cloned->setDebugLoc({}); 100006c3fb27SDimitry Andric } 100106c3fb27SDimitry Andric }; 100206c3fb27SDimitry Andric 100306c3fb27SDimitry Andric // Materialize the assumptions for the reproducer using the entries in Stack. 100406c3fb27SDimitry Andric // That is, first clone the operands of the condition recursively until we 100506c3fb27SDimitry Andric // reach an external input to the reproducer and add them to the reproducer 100606c3fb27SDimitry Andric // function. Then add an ICmp for the condition (with the inverse predicate if 100706c3fb27SDimitry Andric // the entry is negated) and an assert using the ICmp. 100806c3fb27SDimitry Andric for (auto &Entry : Stack) { 100906c3fb27SDimitry Andric if (Entry.Pred == ICmpInst::BAD_ICMP_PREDICATE) 101006c3fb27SDimitry Andric continue; 101106c3fb27SDimitry Andric 101206c3fb27SDimitry Andric LLVM_DEBUG( 101306c3fb27SDimitry Andric dbgs() << " Materializing assumption icmp " << Entry.Pred << ' '; 101406c3fb27SDimitry Andric Entry.LHS->printAsOperand(dbgs(), /*PrintType=*/true); dbgs() << ", "; 101506c3fb27SDimitry Andric Entry.RHS->printAsOperand(dbgs(), /*PrintType=*/false); dbgs() << "\n"); 101606c3fb27SDimitry Andric CloneInstructions({Entry.LHS, Entry.RHS}, CmpInst::isSigned(Entry.Pred)); 101706c3fb27SDimitry Andric 101806c3fb27SDimitry Andric auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS); 101906c3fb27SDimitry Andric Builder.CreateAssumption(Cmp); 102006c3fb27SDimitry Andric } 102106c3fb27SDimitry Andric 102206c3fb27SDimitry Andric // Finally, clone the condition to reproduce and remap instruction operands in 102306c3fb27SDimitry Andric // the reproducer using Old2New. 102406c3fb27SDimitry Andric CloneInstructions(Cond, CmpInst::isSigned(Cond->getPredicate())); 102506c3fb27SDimitry Andric Entry->getTerminator()->setOperand(0, Cond); 102606c3fb27SDimitry Andric remapInstructionsInBlocks({Entry}, Old2New); 102706c3fb27SDimitry Andric 102806c3fb27SDimitry Andric assert(!verifyFunction(*F, &dbgs())); 102906c3fb27SDimitry Andric } 103006c3fb27SDimitry Andric 103106c3fb27SDimitry Andric static std::optional<bool> checkCondition(CmpInst *Cmp, ConstraintInfo &Info, 103206c3fb27SDimitry Andric unsigned NumIn, unsigned NumOut, 103306c3fb27SDimitry Andric Instruction *ContextInst) { 1034bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Checking " << *Cmp << "\n"); 1035bdd1243dSDimitry Andric 1036bdd1243dSDimitry Andric CmpInst::Predicate Pred = Cmp->getPredicate(); 1037bdd1243dSDimitry Andric Value *A = Cmp->getOperand(0); 1038bdd1243dSDimitry Andric Value *B = Cmp->getOperand(1); 1039bdd1243dSDimitry Andric 1040bdd1243dSDimitry Andric auto R = Info.getConstraintForSolving(Pred, A, B); 1041bdd1243dSDimitry Andric if (R.empty() || !R.isValid(Info)){ 1042bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << " failed to decompose condition\n"); 104306c3fb27SDimitry Andric return std::nullopt; 1044bdd1243dSDimitry Andric } 1045bdd1243dSDimitry Andric 1046bdd1243dSDimitry Andric auto &CSToUse = Info.getCS(R.IsSigned); 1047bdd1243dSDimitry Andric 1048bdd1243dSDimitry Andric // If there was extra information collected during decomposition, apply 1049bdd1243dSDimitry Andric // it now and remove it immediately once we are done with reasoning 1050bdd1243dSDimitry Andric // about the constraint. 1051bdd1243dSDimitry Andric for (auto &Row : R.ExtraInfo) 1052bdd1243dSDimitry Andric CSToUse.addVariableRow(Row); 1053bdd1243dSDimitry Andric auto InfoRestorer = make_scope_exit([&]() { 1054bdd1243dSDimitry Andric for (unsigned I = 0; I < R.ExtraInfo.size(); ++I) 1055bdd1243dSDimitry Andric CSToUse.popLastConstraint(); 1056bdd1243dSDimitry Andric }); 1057bdd1243dSDimitry Andric 105806c3fb27SDimitry Andric if (auto ImpliedCondition = R.isImpliedBy(CSToUse)) { 1059bdd1243dSDimitry Andric if (!DebugCounter::shouldExecute(EliminatedCounter)) 106006c3fb27SDimitry Andric return std::nullopt; 1061bdd1243dSDimitry Andric 1062bdd1243dSDimitry Andric LLVM_DEBUG({ 106306c3fb27SDimitry Andric if (*ImpliedCondition) { 106406c3fb27SDimitry Andric dbgs() << "Condition " << *Cmp; 106506c3fb27SDimitry Andric } else { 106606c3fb27SDimitry Andric auto InversePred = Cmp->getInversePredicate(); 106706c3fb27SDimitry Andric dbgs() << "Condition " << CmpInst::getPredicateName(InversePred) << " " 106806c3fb27SDimitry Andric << *A << ", " << *B; 106906c3fb27SDimitry Andric } 107006c3fb27SDimitry Andric dbgs() << " implied by dominating constraints\n"; 107106c3fb27SDimitry Andric CSToUse.dump(); 1072bdd1243dSDimitry Andric }); 107306c3fb27SDimitry Andric return ImpliedCondition; 107406c3fb27SDimitry Andric } 107506c3fb27SDimitry Andric 107606c3fb27SDimitry Andric return std::nullopt; 107706c3fb27SDimitry Andric } 107806c3fb27SDimitry Andric 107906c3fb27SDimitry Andric static bool checkAndReplaceCondition( 108006c3fb27SDimitry Andric CmpInst *Cmp, ConstraintInfo &Info, unsigned NumIn, unsigned NumOut, 108106c3fb27SDimitry Andric Instruction *ContextInst, Module *ReproducerModule, 108206c3fb27SDimitry Andric ArrayRef<ReproducerEntry> ReproducerCondStack, DominatorTree &DT) { 108306c3fb27SDimitry Andric auto ReplaceCmpWithConstant = [&](CmpInst *Cmp, bool IsTrue) { 108406c3fb27SDimitry Andric generateReproducer(Cmp, ReproducerModule, ReproducerCondStack, Info, DT); 108506c3fb27SDimitry Andric Constant *ConstantC = ConstantInt::getBool( 108606c3fb27SDimitry Andric CmpInst::makeCmpResultType(Cmp->getType()), IsTrue); 108706c3fb27SDimitry Andric Cmp->replaceUsesWithIf(ConstantC, [&DT, NumIn, NumOut, 108806c3fb27SDimitry Andric ContextInst](Use &U) { 108906c3fb27SDimitry Andric auto *UserI = getContextInstForUse(U); 109006c3fb27SDimitry Andric auto *DTN = DT.getNode(UserI->getParent()); 109106c3fb27SDimitry Andric if (!DTN || DTN->getDFSNumIn() < NumIn || DTN->getDFSNumOut() > NumOut) 109206c3fb27SDimitry Andric return false; 109306c3fb27SDimitry Andric if (UserI->getParent() == ContextInst->getParent() && 109406c3fb27SDimitry Andric UserI->comesBefore(ContextInst)) 109506c3fb27SDimitry Andric return false; 109606c3fb27SDimitry Andric 1097bdd1243dSDimitry Andric // Conditions in an assume trivially simplify to true. Skip uses 1098bdd1243dSDimitry Andric // in assume calls to not destroy the available information. 1099bdd1243dSDimitry Andric auto *II = dyn_cast<IntrinsicInst>(U.getUser()); 1100bdd1243dSDimitry Andric return !II || II->getIntrinsicID() != Intrinsic::assume; 1101bdd1243dSDimitry Andric }); 1102bdd1243dSDimitry Andric NumCondsRemoved++; 110306c3fb27SDimitry Andric return true; 110406c3fb27SDimitry Andric }; 110506c3fb27SDimitry Andric 110606c3fb27SDimitry Andric if (auto ImpliedCondition = 110706c3fb27SDimitry Andric checkCondition(Cmp, Info, NumIn, NumOut, ContextInst)) 110806c3fb27SDimitry Andric return ReplaceCmpWithConstant(Cmp, *ImpliedCondition); 110906c3fb27SDimitry Andric return false; 1110bdd1243dSDimitry Andric } 111106c3fb27SDimitry Andric 111206c3fb27SDimitry Andric static void 111306c3fb27SDimitry Andric removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info, 111406c3fb27SDimitry Andric Module *ReproducerModule, 111506c3fb27SDimitry Andric SmallVectorImpl<ReproducerEntry> &ReproducerCondStack, 111606c3fb27SDimitry Andric SmallVectorImpl<StackEntry> &DFSInStack) { 111706c3fb27SDimitry Andric Info.popLastConstraint(E.IsSigned); 111806c3fb27SDimitry Andric // Remove variables in the system that went out of scope. 111906c3fb27SDimitry Andric auto &Mapping = Info.getValue2Index(E.IsSigned); 112006c3fb27SDimitry Andric for (Value *V : E.ValuesToRelease) 112106c3fb27SDimitry Andric Mapping.erase(V); 112206c3fb27SDimitry Andric Info.popLastNVariables(E.IsSigned, E.ValuesToRelease.size()); 112306c3fb27SDimitry Andric DFSInStack.pop_back(); 112406c3fb27SDimitry Andric if (ReproducerModule) 112506c3fb27SDimitry Andric ReproducerCondStack.pop_back(); 112606c3fb27SDimitry Andric } 112706c3fb27SDimitry Andric 112806c3fb27SDimitry Andric /// Check if the first condition for an AND implies the second. 112906c3fb27SDimitry Andric static bool checkAndSecondOpImpliedByFirst( 113006c3fb27SDimitry Andric FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule, 113106c3fb27SDimitry Andric SmallVectorImpl<ReproducerEntry> &ReproducerCondStack, 113206c3fb27SDimitry Andric SmallVectorImpl<StackEntry> &DFSInStack) { 113306c3fb27SDimitry Andric CmpInst::Predicate Pred; 113406c3fb27SDimitry Andric Value *A, *B; 113506c3fb27SDimitry Andric Instruction *And = CB.getContextInst(); 113606c3fb27SDimitry Andric if (!match(And->getOperand(0), m_ICmp(Pred, m_Value(A), m_Value(B)))) 1137bdd1243dSDimitry Andric return false; 1138bdd1243dSDimitry Andric 113906c3fb27SDimitry Andric // Optimistically add fact from first condition. 114006c3fb27SDimitry Andric unsigned OldSize = DFSInStack.size(); 114106c3fb27SDimitry Andric Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack); 114206c3fb27SDimitry Andric if (OldSize == DFSInStack.size()) 114306c3fb27SDimitry Andric return false; 114406c3fb27SDimitry Andric 114506c3fb27SDimitry Andric bool Changed = false; 114606c3fb27SDimitry Andric // Check if the second condition can be simplified now. 114706c3fb27SDimitry Andric if (auto ImpliedCondition = 114806c3fb27SDimitry Andric checkCondition(cast<ICmpInst>(And->getOperand(1)), Info, CB.NumIn, 114906c3fb27SDimitry Andric CB.NumOut, CB.getContextInst())) { 115006c3fb27SDimitry Andric And->setOperand(1, ConstantInt::getBool(And->getType(), *ImpliedCondition)); 1151bdd1243dSDimitry Andric Changed = true; 1152bdd1243dSDimitry Andric } 115306c3fb27SDimitry Andric 115406c3fb27SDimitry Andric // Remove entries again. 115506c3fb27SDimitry Andric while (OldSize < DFSInStack.size()) { 115606c3fb27SDimitry Andric StackEntry E = DFSInStack.back(); 115706c3fb27SDimitry Andric removeEntryFromStack(E, Info, ReproducerModule, ReproducerCondStack, 115806c3fb27SDimitry Andric DFSInStack); 115906c3fb27SDimitry Andric } 1160bdd1243dSDimitry Andric return Changed; 1161e8d8bef9SDimitry Andric } 1162e8d8bef9SDimitry Andric 116381ad6265SDimitry Andric void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B, 1164bdd1243dSDimitry Andric unsigned NumIn, unsigned NumOut, 116581ad6265SDimitry Andric SmallVectorImpl<StackEntry> &DFSInStack) { 116681ad6265SDimitry Andric // If the constraint has a pre-condition, skip the constraint if it does not 116781ad6265SDimitry Andric // hold. 1168bdd1243dSDimitry Andric SmallVector<Value *> NewVariables; 1169bdd1243dSDimitry Andric auto R = getConstraint(Pred, A, B, NewVariables); 117006c3fb27SDimitry Andric 117106c3fb27SDimitry Andric // TODO: Support non-equality for facts as well. 117206c3fb27SDimitry Andric if (!R.isValid(*this) || R.isNe()) 117381ad6265SDimitry Andric return; 117481ad6265SDimitry Andric 117506c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Adding '" << Pred << " "; 1176bdd1243dSDimitry Andric A->printAsOperand(dbgs(), false); dbgs() << ", "; 1177bdd1243dSDimitry Andric B->printAsOperand(dbgs(), false); dbgs() << "'\n"); 117881ad6265SDimitry Andric bool Added = false; 117981ad6265SDimitry Andric auto &CSToUse = getCS(R.IsSigned); 118081ad6265SDimitry Andric if (R.Coefficients.empty()) 118181ad6265SDimitry Andric return; 118281ad6265SDimitry Andric 118381ad6265SDimitry Andric Added |= CSToUse.addVariableRowFill(R.Coefficients); 118481ad6265SDimitry Andric 1185bdd1243dSDimitry Andric // If R has been added to the system, add the new variables and queue it for 1186bdd1243dSDimitry Andric // removal once it goes out-of-scope. 118781ad6265SDimitry Andric if (Added) { 118881ad6265SDimitry Andric SmallVector<Value *, 2> ValuesToRelease; 1189bdd1243dSDimitry Andric auto &Value2Index = getValue2Index(R.IsSigned); 1190bdd1243dSDimitry Andric for (Value *V : NewVariables) { 1191bdd1243dSDimitry Andric Value2Index.insert({V, Value2Index.size() + 1}); 1192bdd1243dSDimitry Andric ValuesToRelease.push_back(V); 119381ad6265SDimitry Andric } 119481ad6265SDimitry Andric 119581ad6265SDimitry Andric LLVM_DEBUG({ 119681ad6265SDimitry Andric dbgs() << " constraint: "; 119706c3fb27SDimitry Andric dumpConstraint(R.Coefficients, getValue2Index(R.IsSigned)); 1198bdd1243dSDimitry Andric dbgs() << "\n"; 119981ad6265SDimitry Andric }); 120081ad6265SDimitry Andric 1201bdd1243dSDimitry Andric DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned, 1202bdd1243dSDimitry Andric std::move(ValuesToRelease)); 120381ad6265SDimitry Andric 120406c3fb27SDimitry Andric if (R.isEq()) { 120581ad6265SDimitry Andric // Also add the inverted constraint for equality constraints. 120681ad6265SDimitry Andric for (auto &Coeff : R.Coefficients) 120781ad6265SDimitry Andric Coeff *= -1; 120881ad6265SDimitry Andric CSToUse.addVariableRowFill(R.Coefficients); 120981ad6265SDimitry Andric 1210bdd1243dSDimitry Andric DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned, 121181ad6265SDimitry Andric SmallVector<Value *, 2>()); 121281ad6265SDimitry Andric } 121381ad6265SDimitry Andric } 121481ad6265SDimitry Andric } 121581ad6265SDimitry Andric 1216bdd1243dSDimitry Andric static bool replaceSubOverflowUses(IntrinsicInst *II, Value *A, Value *B, 1217bdd1243dSDimitry Andric SmallVectorImpl<Instruction *> &ToRemove) { 1218bdd1243dSDimitry Andric bool Changed = false; 1219bdd1243dSDimitry Andric IRBuilder<> Builder(II->getParent(), II->getIterator()); 1220bdd1243dSDimitry Andric Value *Sub = nullptr; 1221bdd1243dSDimitry Andric for (User *U : make_early_inc_range(II->users())) { 1222bdd1243dSDimitry Andric if (match(U, m_ExtractValue<0>(m_Value()))) { 1223bdd1243dSDimitry Andric if (!Sub) 1224bdd1243dSDimitry Andric Sub = Builder.CreateSub(A, B); 1225bdd1243dSDimitry Andric U->replaceAllUsesWith(Sub); 1226bdd1243dSDimitry Andric Changed = true; 1227bdd1243dSDimitry Andric } else if (match(U, m_ExtractValue<1>(m_Value()))) { 1228bdd1243dSDimitry Andric U->replaceAllUsesWith(Builder.getFalse()); 1229bdd1243dSDimitry Andric Changed = true; 1230bdd1243dSDimitry Andric } else 1231bdd1243dSDimitry Andric continue; 1232bdd1243dSDimitry Andric 1233bdd1243dSDimitry Andric if (U->use_empty()) { 1234bdd1243dSDimitry Andric auto *I = cast<Instruction>(U); 1235bdd1243dSDimitry Andric ToRemove.push_back(I); 1236bdd1243dSDimitry Andric I->setOperand(0, PoisonValue::get(II->getType())); 1237bdd1243dSDimitry Andric Changed = true; 1238bdd1243dSDimitry Andric } 1239bdd1243dSDimitry Andric } 1240bdd1243dSDimitry Andric 1241bdd1243dSDimitry Andric if (II->use_empty()) { 1242bdd1243dSDimitry Andric II->eraseFromParent(); 1243bdd1243dSDimitry Andric Changed = true; 1244bdd1243dSDimitry Andric } 1245bdd1243dSDimitry Andric return Changed; 1246bdd1243dSDimitry Andric } 1247bdd1243dSDimitry Andric 1248bdd1243dSDimitry Andric static bool 124981ad6265SDimitry Andric tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info, 125081ad6265SDimitry Andric SmallVectorImpl<Instruction *> &ToRemove) { 125181ad6265SDimitry Andric auto DoesConditionHold = [](CmpInst::Predicate Pred, Value *A, Value *B, 125281ad6265SDimitry Andric ConstraintInfo &Info) { 1253bdd1243dSDimitry Andric auto R = Info.getConstraintForSolving(Pred, A, B); 1254bdd1243dSDimitry Andric if (R.size() < 2 || !R.isValid(Info)) 125581ad6265SDimitry Andric return false; 125681ad6265SDimitry Andric 1257bdd1243dSDimitry Andric auto &CSToUse = Info.getCS(R.IsSigned); 125881ad6265SDimitry Andric return CSToUse.isConditionImplied(R.Coefficients); 125981ad6265SDimitry Andric }; 126081ad6265SDimitry Andric 1261bdd1243dSDimitry Andric bool Changed = false; 126281ad6265SDimitry Andric if (II->getIntrinsicID() == Intrinsic::ssub_with_overflow) { 126381ad6265SDimitry Andric // If A s>= B && B s>= 0, ssub.with.overflow(a, b) should not overflow and 126481ad6265SDimitry Andric // can be simplified to a regular sub. 126581ad6265SDimitry Andric Value *A = II->getArgOperand(0); 126681ad6265SDimitry Andric Value *B = II->getArgOperand(1); 126781ad6265SDimitry Andric if (!DoesConditionHold(CmpInst::ICMP_SGE, A, B, Info) || 126881ad6265SDimitry Andric !DoesConditionHold(CmpInst::ICMP_SGE, B, 126981ad6265SDimitry Andric ConstantInt::get(A->getType(), 0), Info)) 1270bdd1243dSDimitry Andric return false; 1271bdd1243dSDimitry Andric Changed = replaceSubOverflowUses(II, A, B, ToRemove); 127281ad6265SDimitry Andric } 1273bdd1243dSDimitry Andric return Changed; 127481ad6265SDimitry Andric } 127581ad6265SDimitry Andric 127606c3fb27SDimitry Andric static bool eliminateConstraints(Function &F, DominatorTree &DT, 127706c3fb27SDimitry Andric OptimizationRemarkEmitter &ORE) { 127881ad6265SDimitry Andric bool Changed = false; 127981ad6265SDimitry Andric DT.updateDFSNumbers(); 128006c3fb27SDimitry Andric SmallVector<Value *> FunctionArgs; 128106c3fb27SDimitry Andric for (Value &Arg : F.args()) 128206c3fb27SDimitry Andric FunctionArgs.push_back(&Arg); 128306c3fb27SDimitry Andric ConstraintInfo Info(F.getParent()->getDataLayout(), FunctionArgs); 128481ad6265SDimitry Andric State S(DT); 128506c3fb27SDimitry Andric std::unique_ptr<Module> ReproducerModule( 128606c3fb27SDimitry Andric DumpReproducers ? new Module(F.getName(), F.getContext()) : nullptr); 128781ad6265SDimitry Andric 128881ad6265SDimitry Andric // First, collect conditions implied by branches and blocks with their 128981ad6265SDimitry Andric // Dominator DFS in and out numbers. 129081ad6265SDimitry Andric for (BasicBlock &BB : F) { 129181ad6265SDimitry Andric if (!DT.getNode(&BB)) 129281ad6265SDimitry Andric continue; 129381ad6265SDimitry Andric S.addInfoFor(BB); 129481ad6265SDimitry Andric } 129581ad6265SDimitry Andric 1296bdd1243dSDimitry Andric // Next, sort worklist by dominance, so that dominating conditions to check 1297bdd1243dSDimitry Andric // and facts come before conditions and facts dominated by them. If a 1298bdd1243dSDimitry Andric // condition to check and a fact have the same numbers, conditional facts come 1299bdd1243dSDimitry Andric // first. Assume facts and checks are ordered according to their relative 1300bdd1243dSDimitry Andric // order in the containing basic block. Also make sure conditions with 1301bdd1243dSDimitry Andric // constant operands come before conditions without constant operands. This 1302bdd1243dSDimitry Andric // increases the effectiveness of the current signed <-> unsigned fact 1303bdd1243dSDimitry Andric // transfer logic. 1304bdd1243dSDimitry Andric stable_sort(S.WorkList, [](const FactOrCheck &A, const FactOrCheck &B) { 1305bdd1243dSDimitry Andric auto HasNoConstOp = [](const FactOrCheck &B) { 1306bdd1243dSDimitry Andric return !isa<ConstantInt>(B.Inst->getOperand(0)) && 1307bdd1243dSDimitry Andric !isa<ConstantInt>(B.Inst->getOperand(1)); 1308bdd1243dSDimitry Andric }; 1309bdd1243dSDimitry Andric // If both entries have the same In numbers, conditional facts come first. 1310bdd1243dSDimitry Andric // Otherwise use the relative order in the basic block. 1311bdd1243dSDimitry Andric if (A.NumIn == B.NumIn) { 1312bdd1243dSDimitry Andric if (A.isConditionFact() && B.isConditionFact()) { 1313bdd1243dSDimitry Andric bool NoConstOpA = HasNoConstOp(A); 1314bdd1243dSDimitry Andric bool NoConstOpB = HasNoConstOp(B); 1315bdd1243dSDimitry Andric return NoConstOpA < NoConstOpB; 1316bdd1243dSDimitry Andric } 1317bdd1243dSDimitry Andric if (A.isConditionFact()) 1318bdd1243dSDimitry Andric return true; 1319bdd1243dSDimitry Andric if (B.isConditionFact()) 1320bdd1243dSDimitry Andric return false; 132106c3fb27SDimitry Andric auto *InstA = A.getContextInst(); 132206c3fb27SDimitry Andric auto *InstB = B.getContextInst(); 132306c3fb27SDimitry Andric return InstA->comesBefore(InstB); 1324bdd1243dSDimitry Andric } 1325bdd1243dSDimitry Andric return A.NumIn < B.NumIn; 1326e8d8bef9SDimitry Andric }); 1327e8d8bef9SDimitry Andric 132881ad6265SDimitry Andric SmallVector<Instruction *> ToRemove; 132981ad6265SDimitry Andric 1330e8d8bef9SDimitry Andric // Finally, process ordered worklist and eliminate implied conditions. 1331e8d8bef9SDimitry Andric SmallVector<StackEntry, 16> DFSInStack; 133206c3fb27SDimitry Andric SmallVector<ReproducerEntry> ReproducerCondStack; 1333bdd1243dSDimitry Andric for (FactOrCheck &CB : S.WorkList) { 1334e8d8bef9SDimitry Andric // First, pop entries from the stack that are out-of-scope for CB. Remove 1335e8d8bef9SDimitry Andric // the corresponding entry from the constraint system. 1336e8d8bef9SDimitry Andric while (!DFSInStack.empty()) { 1337e8d8bef9SDimitry Andric auto &E = DFSInStack.back(); 1338e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "Top of stack : " << E.NumIn << " " << E.NumOut 1339e8d8bef9SDimitry Andric << "\n"); 1340e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "CB: " << CB.NumIn << " " << CB.NumOut << "\n"); 1341e8d8bef9SDimitry Andric assert(E.NumIn <= CB.NumIn); 1342e8d8bef9SDimitry Andric if (CB.NumOut <= E.NumOut) 1343e8d8bef9SDimitry Andric break; 134481ad6265SDimitry Andric LLVM_DEBUG({ 134581ad6265SDimitry Andric dbgs() << "Removing "; 134606c3fb27SDimitry Andric dumpConstraint(Info.getCS(E.IsSigned).getLastConstraint(), 134781ad6265SDimitry Andric Info.getValue2Index(E.IsSigned)); 134881ad6265SDimitry Andric dbgs() << "\n"; 134981ad6265SDimitry Andric }); 135006c3fb27SDimitry Andric removeEntryFromStack(E, Info, ReproducerModule.get(), ReproducerCondStack, 135106c3fb27SDimitry Andric DFSInStack); 1352e8d8bef9SDimitry Andric } 1353e8d8bef9SDimitry Andric 135406c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Processing "); 1355e8d8bef9SDimitry Andric 1356e8d8bef9SDimitry Andric // For a block, check if any CmpInsts become known based on the current set 1357e8d8bef9SDimitry Andric // of constraints. 135806c3fb27SDimitry Andric if (CB.isCheck()) { 135906c3fb27SDimitry Andric Instruction *Inst = CB.getInstructionToSimplify(); 136006c3fb27SDimitry Andric if (!Inst) 136106c3fb27SDimitry Andric continue; 136206c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "condition to simplify: " << *Inst << "\n"); 136306c3fb27SDimitry Andric if (auto *II = dyn_cast<WithOverflowInst>(Inst)) { 1364bdd1243dSDimitry Andric Changed |= tryToSimplifyOverflowMath(II, Info, ToRemove); 136506c3fb27SDimitry Andric } else if (auto *Cmp = dyn_cast<ICmpInst>(Inst)) { 136606c3fb27SDimitry Andric bool Simplified = checkAndReplaceCondition( 136706c3fb27SDimitry Andric Cmp, Info, CB.NumIn, CB.NumOut, CB.getContextInst(), 136806c3fb27SDimitry Andric ReproducerModule.get(), ReproducerCondStack, S.DT); 136906c3fb27SDimitry Andric if (!Simplified && match(CB.getContextInst(), 137006c3fb27SDimitry Andric m_LogicalAnd(m_Value(), m_Specific(Inst)))) { 137106c3fb27SDimitry Andric Simplified = 137206c3fb27SDimitry Andric checkAndSecondOpImpliedByFirst(CB, Info, ReproducerModule.get(), 137306c3fb27SDimitry Andric ReproducerCondStack, DFSInStack); 137406c3fb27SDimitry Andric } 137506c3fb27SDimitry Andric Changed |= Simplified; 1376e8d8bef9SDimitry Andric } 1377e8d8bef9SDimitry Andric continue; 1378e8d8bef9SDimitry Andric } 1379e8d8bef9SDimitry Andric 138006c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "fact to add to the system: " << *CB.Inst << "\n"); 138106c3fb27SDimitry Andric auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) { 1382bdd1243dSDimitry Andric if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) { 1383bdd1243dSDimitry Andric LLVM_DEBUG( 1384bdd1243dSDimitry Andric dbgs() 1385bdd1243dSDimitry Andric << "Skip adding constraint because system has too many rows.\n"); 138606c3fb27SDimitry Andric return; 138706c3fb27SDimitry Andric } 138806c3fb27SDimitry Andric 138906c3fb27SDimitry Andric Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack); 139006c3fb27SDimitry Andric if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) 139106c3fb27SDimitry Andric ReproducerCondStack.emplace_back(Pred, A, B); 139206c3fb27SDimitry Andric 139306c3fb27SDimitry Andric Info.transferToOtherSystem(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack); 139406c3fb27SDimitry Andric if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) { 139506c3fb27SDimitry Andric // Add dummy entries to ReproducerCondStack to keep it in sync with 139606c3fb27SDimitry Andric // DFSInStack. 139706c3fb27SDimitry Andric for (unsigned I = 0, 139806c3fb27SDimitry Andric E = (DFSInStack.size() - ReproducerCondStack.size()); 139906c3fb27SDimitry Andric I < E; ++I) { 140006c3fb27SDimitry Andric ReproducerCondStack.emplace_back(ICmpInst::BAD_ICMP_PREDICATE, 140106c3fb27SDimitry Andric nullptr, nullptr); 140206c3fb27SDimitry Andric } 140306c3fb27SDimitry Andric } 140406c3fb27SDimitry Andric }; 140506c3fb27SDimitry Andric 140606c3fb27SDimitry Andric ICmpInst::Predicate Pred; 140706c3fb27SDimitry Andric if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) { 140806c3fb27SDimitry Andric Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate()); 140906c3fb27SDimitry Andric AddFact(Pred, MinMax, MinMax->getLHS()); 141006c3fb27SDimitry Andric AddFact(Pred, MinMax, MinMax->getRHS()); 1411bdd1243dSDimitry Andric continue; 1412bdd1243dSDimitry Andric } 1413bdd1243dSDimitry Andric 141406c3fb27SDimitry Andric Value *A, *B; 141506c3fb27SDimitry Andric Value *Cmp = CB.Inst; 141606c3fb27SDimitry Andric match(Cmp, m_Intrinsic<Intrinsic::assume>(m_Value(Cmp))); 141706c3fb27SDimitry Andric if (match(Cmp, m_ICmp(Pred, m_Value(A), m_Value(B)))) { 1418bdd1243dSDimitry Andric // Use the inverse predicate if required. 1419bdd1243dSDimitry Andric if (CB.Not) 1420bdd1243dSDimitry Andric Pred = CmpInst::getInversePredicate(Pred); 1421bdd1243dSDimitry Andric 142206c3fb27SDimitry Andric AddFact(Pred, A, B); 1423e8d8bef9SDimitry Andric } 1424fe6060f1SDimitry Andric } 1425e8d8bef9SDimitry Andric 142606c3fb27SDimitry Andric if (ReproducerModule && !ReproducerModule->functions().empty()) { 142706c3fb27SDimitry Andric std::string S; 142806c3fb27SDimitry Andric raw_string_ostream StringS(S); 142906c3fb27SDimitry Andric ReproducerModule->print(StringS, nullptr); 143006c3fb27SDimitry Andric StringS.flush(); 143106c3fb27SDimitry Andric OptimizationRemark Rem(DEBUG_TYPE, "Reproducer", &F); 143206c3fb27SDimitry Andric Rem << ore::NV("module") << S; 143306c3fb27SDimitry Andric ORE.emit(Rem); 143406c3fb27SDimitry Andric } 143506c3fb27SDimitry Andric 143681ad6265SDimitry Andric #ifndef NDEBUG 143781ad6265SDimitry Andric unsigned SignedEntries = 143881ad6265SDimitry Andric count_if(DFSInStack, [](const StackEntry &E) { return E.IsSigned; }); 143981ad6265SDimitry Andric assert(Info.getCS(false).size() == DFSInStack.size() - SignedEntries && 1440fe6060f1SDimitry Andric "updates to CS and DFSInStack are out of sync"); 144181ad6265SDimitry Andric assert(Info.getCS(true).size() == SignedEntries && 144281ad6265SDimitry Andric "updates to CS and DFSInStack are out of sync"); 144381ad6265SDimitry Andric #endif 144481ad6265SDimitry Andric 144581ad6265SDimitry Andric for (Instruction *I : ToRemove) 144681ad6265SDimitry Andric I->eraseFromParent(); 1447e8d8bef9SDimitry Andric return Changed; 1448e8d8bef9SDimitry Andric } 1449e8d8bef9SDimitry Andric 1450e8d8bef9SDimitry Andric PreservedAnalyses ConstraintEliminationPass::run(Function &F, 1451e8d8bef9SDimitry Andric FunctionAnalysisManager &AM) { 1452e8d8bef9SDimitry Andric auto &DT = AM.getResult<DominatorTreeAnalysis>(F); 145306c3fb27SDimitry Andric auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F); 145406c3fb27SDimitry Andric if (!eliminateConstraints(F, DT, ORE)) 1455e8d8bef9SDimitry Andric return PreservedAnalyses::all(); 1456e8d8bef9SDimitry Andric 1457e8d8bef9SDimitry Andric PreservedAnalyses PA; 1458e8d8bef9SDimitry Andric PA.preserve<DominatorTreeAnalysis>(); 1459e8d8bef9SDimitry Andric PA.preserveSet<CFGAnalyses>(); 1460e8d8bef9SDimitry Andric return PA; 1461e8d8bef9SDimitry Andric } 1462