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