1e8d8bef9SDimitry Andric //===-- ConstraintElimination.cpp - Eliminate conds using constraints. ----===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric // 9e8d8bef9SDimitry Andric // Eliminate conditions based on constraints collected from dominating 10e8d8bef9SDimitry Andric // conditions. 11e8d8bef9SDimitry Andric // 12e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 13e8d8bef9SDimitry Andric 14e8d8bef9SDimitry Andric #include "llvm/Transforms/Scalar/ConstraintElimination.h" 15e8d8bef9SDimitry Andric #include "llvm/ADT/STLExtras.h" 16fe6060f1SDimitry Andric #include "llvm/ADT/ScopeExit.h" 17e8d8bef9SDimitry Andric #include "llvm/ADT/SmallVector.h" 18e8d8bef9SDimitry Andric #include "llvm/ADT/Statistic.h" 19e8d8bef9SDimitry Andric #include "llvm/Analysis/ConstraintSystem.h" 20e8d8bef9SDimitry Andric #include "llvm/Analysis/GlobalsModRef.h" 21*06c3fb27SDimitry 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" 30*06c3fb27SDimitry 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" 35*06c3fb27SDimitry Andric #include "llvm/Support/KnownBits.h" 3681ad6265SDimitry Andric #include "llvm/Support/MathExtras.h" 37*06c3fb27SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h" 38*06c3fb27SDimitry Andric #include "llvm/Transforms/Utils/ValueMapper.h" 39e8d8bef9SDimitry Andric 40bdd1243dSDimitry Andric #include <cmath> 41*06c3fb27SDimitry 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 57*06c3fb27SDimitry Andric static cl::opt<bool> DumpReproducers( 58*06c3fb27SDimitry Andric "constraint-elimination-dump-reproducers", cl::init(false), cl::Hidden, 59*06c3fb27SDimitry Andric cl::desc("Dump IR to reproduce successful transformations.")); 60*06c3fb27SDimitry 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 78*06c3fb27SDimitry Andric static Instruction *getContextInstForUse(Use &U) { 79*06c3fb27SDimitry Andric Instruction *UserI = cast<Instruction>(U.getUser()); 80*06c3fb27SDimitry Andric if (auto *Phi = dyn_cast<PHINode>(UserI)) 81*06c3fb27SDimitry Andric UserI = Phi->getIncomingBlock(U)->getTerminator(); 82*06c3fb27SDimitry Andric return UserI; 83*06c3fb27SDimitry Andric } 84*06c3fb27SDimitry Andric 8504eeddc0SDimitry Andric namespace { 86*06c3fb27SDimitry Andric /// Represents either 87*06c3fb27SDimitry Andric /// * a condition that holds on entry to a block (=conditional fact) 88*06c3fb27SDimitry Andric /// * an assume (=assume fact) 89*06c3fb27SDimitry Andric /// * a use of a compare instruction to simplify. 90*06c3fb27SDimitry Andric /// It also tracks the Dominator DFS in and out numbers for each entry. 91*06c3fb27SDimitry Andric struct FactOrCheck { 92*06c3fb27SDimitry Andric union { 93*06c3fb27SDimitry Andric Instruction *Inst; 94*06c3fb27SDimitry Andric Use *U; 95*06c3fb27SDimitry Andric }; 96*06c3fb27SDimitry Andric unsigned NumIn; 97*06c3fb27SDimitry Andric unsigned NumOut; 98*06c3fb27SDimitry Andric bool HasInst; 99*06c3fb27SDimitry Andric bool Not; 100*06c3fb27SDimitry Andric 101*06c3fb27SDimitry Andric FactOrCheck(DomTreeNode *DTN, Instruction *Inst, bool Not) 102*06c3fb27SDimitry Andric : Inst(Inst), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), 103*06c3fb27SDimitry Andric HasInst(true), Not(Not) {} 104*06c3fb27SDimitry Andric 105*06c3fb27SDimitry Andric FactOrCheck(DomTreeNode *DTN, Use *U) 106*06c3fb27SDimitry Andric : U(U), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), 107*06c3fb27SDimitry Andric HasInst(false), Not(false) {} 108*06c3fb27SDimitry Andric 109*06c3fb27SDimitry Andric static FactOrCheck getFact(DomTreeNode *DTN, Instruction *Inst, 110*06c3fb27SDimitry Andric bool Not = false) { 111*06c3fb27SDimitry Andric return FactOrCheck(DTN, Inst, Not); 112*06c3fb27SDimitry Andric } 113*06c3fb27SDimitry Andric 114*06c3fb27SDimitry Andric static FactOrCheck getCheck(DomTreeNode *DTN, Use *U) { 115*06c3fb27SDimitry Andric return FactOrCheck(DTN, U); 116*06c3fb27SDimitry Andric } 117*06c3fb27SDimitry Andric 118*06c3fb27SDimitry Andric static FactOrCheck getCheck(DomTreeNode *DTN, CallInst *CI) { 119*06c3fb27SDimitry Andric return FactOrCheck(DTN, CI, false); 120*06c3fb27SDimitry Andric } 121*06c3fb27SDimitry Andric 122*06c3fb27SDimitry Andric bool isCheck() const { 123*06c3fb27SDimitry Andric return !HasInst || 124*06c3fb27SDimitry Andric match(Inst, m_Intrinsic<Intrinsic::ssub_with_overflow>()); 125*06c3fb27SDimitry Andric } 126*06c3fb27SDimitry Andric 127*06c3fb27SDimitry Andric Instruction *getContextInst() const { 128*06c3fb27SDimitry Andric if (HasInst) 129*06c3fb27SDimitry Andric return Inst; 130*06c3fb27SDimitry Andric return getContextInstForUse(*U); 131*06c3fb27SDimitry Andric } 132*06c3fb27SDimitry Andric Instruction *getInstructionToSimplify() const { 133*06c3fb27SDimitry Andric assert(isCheck()); 134*06c3fb27SDimitry Andric if (HasInst) 135*06c3fb27SDimitry Andric return Inst; 136*06c3fb27SDimitry Andric // The use may have been simplified to a constant already. 137*06c3fb27SDimitry Andric return dyn_cast<Instruction>(*U); 138*06c3fb27SDimitry Andric } 139*06c3fb27SDimitry Andric bool isConditionFact() const { return !isCheck() && isa<CmpInst>(Inst); } 140*06c3fb27SDimitry Andric }; 141*06c3fb27SDimitry Andric 142*06c3fb27SDimitry Andric /// Keep state required to build worklist. 143*06c3fb27SDimitry Andric struct State { 144*06c3fb27SDimitry Andric DominatorTree &DT; 145*06c3fb27SDimitry Andric SmallVector<FactOrCheck, 64> WorkList; 146*06c3fb27SDimitry Andric 147*06c3fb27SDimitry Andric State(DominatorTree &DT) : DT(DT) {} 148*06c3fb27SDimitry Andric 149*06c3fb27SDimitry Andric /// Process block \p BB and add known facts to work-list. 150*06c3fb27SDimitry Andric void addInfoFor(BasicBlock &BB); 151*06c3fb27SDimitry Andric 152*06c3fb27SDimitry Andric /// Returns true if we can add a known condition from BB to its successor 153*06c3fb27SDimitry Andric /// block Succ. 154*06c3fb27SDimitry Andric bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ) const { 155*06c3fb27SDimitry Andric return DT.dominates(BasicBlockEdge(&BB, Succ), Succ); 156*06c3fb27SDimitry Andric } 157*06c3fb27SDimitry 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 195*06c3fb27SDimitry Andric ConstraintTy(SmallVector<int64_t, 8> Coefficients, bool IsSigned, bool IsEq, 196*06c3fb27SDimitry Andric bool IsNe) 197*06c3fb27SDimitry Andric : Coefficients(Coefficients), IsSigned(IsSigned), IsEq(IsEq), IsNe(IsNe) { 198*06c3fb27SDimitry 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; 207*06c3fb27SDimitry Andric 208*06c3fb27SDimitry Andric bool isEq() const { return IsEq; } 209*06c3fb27SDimitry Andric 210*06c3fb27SDimitry Andric bool isNe() const { return IsNe; } 211*06c3fb27SDimitry Andric 212*06c3fb27SDimitry Andric /// Check if the current constraint is implied by the given ConstraintSystem. 213*06c3fb27SDimitry Andric /// 214*06c3fb27SDimitry Andric /// \return true or false if the constraint is proven to be respectively true, 215*06c3fb27SDimitry Andric /// or false. When the constraint cannot be proven to be either true or false, 216*06c3fb27SDimitry Andric /// std::nullopt is returned. 217*06c3fb27SDimitry Andric std::optional<bool> isImpliedBy(const ConstraintSystem &CS) const; 218*06c3fb27SDimitry Andric 219*06c3fb27SDimitry Andric private: 220*06c3fb27SDimitry Andric bool IsEq = false; 221*06c3fb27SDimitry 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: 238*06c3fb27SDimitry Andric ConstraintInfo(const DataLayout &DL, ArrayRef<Value *> FunctionArgs) 239*06c3fb27SDimitry Andric : UnsignedCS(FunctionArgs), SignedCS(FunctionArgs), DL(DL) {} 240bdd1243dSDimitry Andric 24181ad6265SDimitry Andric DenseMap<Value *, unsigned> &getValue2Index(bool Signed) { 242*06c3fb27SDimitry Andric return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index(); 24381ad6265SDimitry Andric } 24481ad6265SDimitry Andric const DenseMap<Value *, unsigned> &getValue2Index(bool Signed) const { 245*06c3fb27SDimitry 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 342*06c3fb27SDimitry Andric decomposeGEP(GEPOperator &GEP, SmallVectorImpl<PreconditionTy> &Preconditions, 343*06c3fb27SDimitry 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. 363*06c3fb27SDimitry 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 426*06c3fb27SDimitry Andric ConstantInt *CI; 427*06c3fb27SDimitry Andric if (match(V, m_NSWMul(m_Value(Op0), m_ConstantInt(CI)))) { 428*06c3fb27SDimitry Andric auto Result = decompose(Op0, Preconditions, IsSigned, DL); 429*06c3fb27SDimitry Andric Result.mul(CI->getSExtValue()); 430*06c3fb27SDimitry Andric return Result; 431*06c3fb27SDimitry Andric } 432*06c3fb27SDimitry 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 442*06c3fb27SDimitry 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 476*06c3fb27SDimitry Andric // Decompose or as an add if there are no common bits between the operands. 477*06c3fb27SDimitry Andric if (match(V, m_Or(m_Value(Op0), m_ConstantInt(CI))) && 478*06c3fb27SDimitry Andric haveNoCommonBitsSet(Op0, CI, DL)) { 479*06c3fb27SDimitry Andric return MergeResults(Op0, CI, IsSigned); 480*06c3fb27SDimitry Andric } 481*06c3fb27SDimitry Andric 482bdd1243dSDimitry Andric if (match(V, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI)) { 483*06c3fb27SDimitry Andric if (CI->getSExtValue() < 0 || CI->getSExtValue() >= 64) 484*06c3fb27SDimitry Andric return {V, IsKnownNonNegative}; 485bdd1243dSDimitry Andric auto Result = decompose(Op1, Preconditions, IsSigned, DL); 486*06c3fb27SDimitry 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; 510*06c3fb27SDimitry Andric bool IsNe = false; 511*06c3fb27SDimitry 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: 531*06c3fb27SDimitry Andric if (match(Op1, m_Zero())) { 53281ad6265SDimitry Andric Pred = CmpInst::getSwappedPredicate(CmpInst::ICMP_UGT); 53381ad6265SDimitry Andric std::swap(Op0, Op1); 534*06c3fb27SDimitry Andric } else { 535*06c3fb27SDimitry Andric IsNe = true; 536*06c3fb27SDimitry Andric Pred = CmpInst::ICMP_ULE; 537*06c3fb27SDimitry 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), 584*06c3fb27SDimitry 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) { 597*06c3fb27SDimitry Andric if (SubOverflow(R[GetOrAddIndex(KV.Variable)], KV.Coefficient, 598*06c3fb27SDimitry Andric R[GetOrAddIndex(KV.Variable)])) 599*06c3fb27SDimitry 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) { 627*06c3fb27SDimitry Andric if (!KV.second || 628*06c3fb27SDimitry 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); 650*06c3fb27SDimitry 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 662*06c3fb27SDimitry Andric std::optional<bool> 663*06c3fb27SDimitry Andric ConstraintTy::isImpliedBy(const ConstraintSystem &CS) const { 664*06c3fb27SDimitry Andric bool IsConditionImplied = CS.isConditionImplied(Coefficients); 665*06c3fb27SDimitry Andric 666*06c3fb27SDimitry Andric if (IsEq || IsNe) { 667*06c3fb27SDimitry Andric auto NegatedOrEqual = ConstraintSystem::negateOrEqual(Coefficients); 668*06c3fb27SDimitry Andric bool IsNegatedOrEqualImplied = 669*06c3fb27SDimitry Andric !NegatedOrEqual.empty() && CS.isConditionImplied(NegatedOrEqual); 670*06c3fb27SDimitry Andric 671*06c3fb27SDimitry Andric // In order to check that `%a == %b` is true (equality), both conditions `%a 672*06c3fb27SDimitry Andric // >= %b` and `%a <= %b` must hold true. When checking for equality (`IsEq` 673*06c3fb27SDimitry Andric // is true), we return true if they both hold, false in the other cases. 674*06c3fb27SDimitry Andric if (IsConditionImplied && IsNegatedOrEqualImplied) 675*06c3fb27SDimitry Andric return IsEq; 676*06c3fb27SDimitry Andric 677*06c3fb27SDimitry Andric auto Negated = ConstraintSystem::negate(Coefficients); 678*06c3fb27SDimitry Andric bool IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated); 679*06c3fb27SDimitry Andric 680*06c3fb27SDimitry Andric auto StrictLessThan = ConstraintSystem::toStrictLessThan(Coefficients); 681*06c3fb27SDimitry Andric bool IsStrictLessThanImplied = 682*06c3fb27SDimitry Andric !StrictLessThan.empty() && CS.isConditionImplied(StrictLessThan); 683*06c3fb27SDimitry Andric 684*06c3fb27SDimitry Andric // In order to check that `%a != %b` is true (non-equality), either 685*06c3fb27SDimitry Andric // condition `%a > %b` or `%a < %b` must hold true. When checking for 686*06c3fb27SDimitry Andric // non-equality (`IsNe` is true), we return true if one of the two holds, 687*06c3fb27SDimitry Andric // false in the other cases. 688*06c3fb27SDimitry Andric if (IsNegatedImplied || IsStrictLessThanImplied) 689*06c3fb27SDimitry Andric return IsNe; 690*06c3fb27SDimitry Andric 691*06c3fb27SDimitry Andric return std::nullopt; 692*06c3fb27SDimitry Andric } 693*06c3fb27SDimitry Andric 694*06c3fb27SDimitry Andric if (IsConditionImplied) 695*06c3fb27SDimitry Andric return true; 696*06c3fb27SDimitry Andric 697*06c3fb27SDimitry Andric auto Negated = ConstraintSystem::negate(Coefficients); 698*06c3fb27SDimitry Andric auto IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated); 699*06c3fb27SDimitry Andric if (IsNegatedImplied) 700*06c3fb27SDimitry Andric return false; 701*06c3fb27SDimitry Andric 702*06c3fb27SDimitry Andric // Neither the condition nor its negated holds, did not prove anything. 703*06c3fb27SDimitry Andric return std::nullopt; 704*06c3fb27SDimitry Andric } 705*06c3fb27SDimitry Andric 70681ad6265SDimitry Andric bool ConstraintInfo::doesHold(CmpInst::Predicate Pred, Value *A, 70781ad6265SDimitry Andric Value *B) const { 708bdd1243dSDimitry Andric auto R = getConstraintForSolving(Pred, A, B); 709*06c3fb27SDimitry 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; 738*06c3fb27SDimitry 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); 742*06c3fb27SDimitry Andric if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0))) 743*06c3fb27SDimitry Andric addFact(CmpInst::ICMP_UGT, A, B, NumIn, NumOut, DFSInStack); 744*06c3fb27SDimitry Andric 74581ad6265SDimitry Andric break; 746*06c3fb27SDimitry 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 757*06c3fb27SDimitry Andric static void dumpConstraint(ArrayRef<int64_t> C, 758*06c3fb27SDimitry Andric const DenseMap<Value *, unsigned> &Value2Index) { 759*06c3fb27SDimitry Andric ConstraintSystem CS(Value2Index); 76081ad6265SDimitry Andric CS.addVariableRowFill(C); 761*06c3fb27SDimitry 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)) { 771*06c3fb27SDimitry Andric for (Use &U : Cmp->uses()) { 772*06c3fb27SDimitry Andric auto *UserI = getContextInstForUse(U); 773*06c3fb27SDimitry Andric auto *DTN = DT.getNode(UserI->getParent()); 774*06c3fb27SDimitry Andric if (!DTN) 775*06c3fb27SDimitry Andric continue; 776*06c3fb27SDimitry Andric WorkList.push_back(FactOrCheck::getCheck(DTN, &U)); 777*06c3fb27SDimitry Andric } 778bdd1243dSDimitry Andric continue; 779bdd1243dSDimitry Andric } 780bdd1243dSDimitry Andric 781bdd1243dSDimitry Andric if (match(&I, m_Intrinsic<Intrinsic::ssub_with_overflow>())) { 782*06c3fb27SDimitry Andric WorkList.push_back( 783*06c3fb27SDimitry Andric FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I))); 784*06c3fb27SDimitry Andric continue; 785*06c3fb27SDimitry Andric } 786*06c3fb27SDimitry Andric 787*06c3fb27SDimitry Andric if (isa<MinMaxIntrinsic>(&I)) { 788*06c3fb27SDimitry 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 870*06c3fb27SDimitry Andric namespace { 871*06c3fb27SDimitry Andric /// Helper to keep track of a condition and if it should be treated as negated 872*06c3fb27SDimitry Andric /// for reproducer construction. 873*06c3fb27SDimitry Andric /// Pred == Predicate::BAD_ICMP_PREDICATE indicates that this entry is a 874*06c3fb27SDimitry Andric /// placeholder to keep the ReproducerCondStack in sync with DFSInStack. 875*06c3fb27SDimitry Andric struct ReproducerEntry { 876*06c3fb27SDimitry Andric ICmpInst::Predicate Pred; 877*06c3fb27SDimitry Andric Value *LHS; 878*06c3fb27SDimitry Andric Value *RHS; 879*06c3fb27SDimitry Andric 880*06c3fb27SDimitry Andric ReproducerEntry(ICmpInst::Predicate Pred, Value *LHS, Value *RHS) 881*06c3fb27SDimitry Andric : Pred(Pred), LHS(LHS), RHS(RHS) {} 882*06c3fb27SDimitry Andric }; 883*06c3fb27SDimitry Andric } // namespace 884*06c3fb27SDimitry Andric 885*06c3fb27SDimitry Andric /// Helper function to generate a reproducer function for simplifying \p Cond. 886*06c3fb27SDimitry Andric /// The reproducer function contains a series of @llvm.assume calls, one for 887*06c3fb27SDimitry Andric /// each condition in \p Stack. For each condition, the operand instruction are 888*06c3fb27SDimitry Andric /// cloned until we reach operands that have an entry in \p Value2Index. Those 889*06c3fb27SDimitry Andric /// will then be added as function arguments. \p DT is used to order cloned 890*06c3fb27SDimitry Andric /// instructions. The reproducer function will get added to \p M, if it is 891*06c3fb27SDimitry Andric /// non-null. Otherwise no reproducer function is generated. 892*06c3fb27SDimitry Andric static void generateReproducer(CmpInst *Cond, Module *M, 893*06c3fb27SDimitry Andric ArrayRef<ReproducerEntry> Stack, 894*06c3fb27SDimitry Andric ConstraintInfo &Info, DominatorTree &DT) { 895*06c3fb27SDimitry Andric if (!M) 896*06c3fb27SDimitry Andric return; 897*06c3fb27SDimitry Andric 898*06c3fb27SDimitry Andric LLVMContext &Ctx = Cond->getContext(); 899*06c3fb27SDimitry Andric 900*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Creating reproducer for " << *Cond << "\n"); 901*06c3fb27SDimitry Andric 902*06c3fb27SDimitry Andric ValueToValueMapTy Old2New; 903*06c3fb27SDimitry Andric SmallVector<Value *> Args; 904*06c3fb27SDimitry Andric SmallPtrSet<Value *, 8> Seen; 905*06c3fb27SDimitry Andric // Traverse Cond and its operands recursively until we reach a value that's in 906*06c3fb27SDimitry Andric // Value2Index or not an instruction, or not a operation that 907*06c3fb27SDimitry Andric // ConstraintElimination can decompose. Such values will be considered as 908*06c3fb27SDimitry Andric // external inputs to the reproducer, they are collected and added as function 909*06c3fb27SDimitry Andric // arguments later. 910*06c3fb27SDimitry Andric auto CollectArguments = [&](ArrayRef<Value *> Ops, bool IsSigned) { 911*06c3fb27SDimitry Andric auto &Value2Index = Info.getValue2Index(IsSigned); 912*06c3fb27SDimitry Andric SmallVector<Value *, 4> WorkList(Ops); 913*06c3fb27SDimitry Andric while (!WorkList.empty()) { 914*06c3fb27SDimitry Andric Value *V = WorkList.pop_back_val(); 915*06c3fb27SDimitry Andric if (!Seen.insert(V).second) 916*06c3fb27SDimitry Andric continue; 917*06c3fb27SDimitry Andric if (Old2New.find(V) != Old2New.end()) 918*06c3fb27SDimitry Andric continue; 919*06c3fb27SDimitry Andric if (isa<Constant>(V)) 920*06c3fb27SDimitry Andric continue; 921*06c3fb27SDimitry Andric 922*06c3fb27SDimitry Andric auto *I = dyn_cast<Instruction>(V); 923*06c3fb27SDimitry Andric if (Value2Index.contains(V) || !I || 924*06c3fb27SDimitry Andric !isa<CmpInst, BinaryOperator, GEPOperator, CastInst>(V)) { 925*06c3fb27SDimitry Andric Old2New[V] = V; 926*06c3fb27SDimitry Andric Args.push_back(V); 927*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << " found external input " << *V << "\n"); 928*06c3fb27SDimitry Andric } else { 929*06c3fb27SDimitry Andric append_range(WorkList, I->operands()); 930*06c3fb27SDimitry Andric } 931*06c3fb27SDimitry Andric } 932*06c3fb27SDimitry Andric }; 933*06c3fb27SDimitry Andric 934*06c3fb27SDimitry Andric for (auto &Entry : Stack) 935*06c3fb27SDimitry Andric if (Entry.Pred != ICmpInst::BAD_ICMP_PREDICATE) 936*06c3fb27SDimitry Andric CollectArguments({Entry.LHS, Entry.RHS}, ICmpInst::isSigned(Entry.Pred)); 937*06c3fb27SDimitry Andric CollectArguments(Cond, ICmpInst::isSigned(Cond->getPredicate())); 938*06c3fb27SDimitry Andric 939*06c3fb27SDimitry Andric SmallVector<Type *> ParamTys; 940*06c3fb27SDimitry Andric for (auto *P : Args) 941*06c3fb27SDimitry Andric ParamTys.push_back(P->getType()); 942*06c3fb27SDimitry Andric 943*06c3fb27SDimitry Andric FunctionType *FTy = FunctionType::get(Cond->getType(), ParamTys, 944*06c3fb27SDimitry Andric /*isVarArg=*/false); 945*06c3fb27SDimitry Andric Function *F = Function::Create(FTy, Function::ExternalLinkage, 946*06c3fb27SDimitry Andric Cond->getModule()->getName() + 947*06c3fb27SDimitry Andric Cond->getFunction()->getName() + "repro", 948*06c3fb27SDimitry Andric M); 949*06c3fb27SDimitry Andric // Add arguments to the reproducer function for each external value collected. 950*06c3fb27SDimitry Andric for (unsigned I = 0; I < Args.size(); ++I) { 951*06c3fb27SDimitry Andric F->getArg(I)->setName(Args[I]->getName()); 952*06c3fb27SDimitry Andric Old2New[Args[I]] = F->getArg(I); 953*06c3fb27SDimitry Andric } 954*06c3fb27SDimitry Andric 955*06c3fb27SDimitry Andric BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F); 956*06c3fb27SDimitry Andric IRBuilder<> Builder(Entry); 957*06c3fb27SDimitry Andric Builder.CreateRet(Builder.getTrue()); 958*06c3fb27SDimitry Andric Builder.SetInsertPoint(Entry->getTerminator()); 959*06c3fb27SDimitry Andric 960*06c3fb27SDimitry Andric // Clone instructions in \p Ops and their operands recursively until reaching 961*06c3fb27SDimitry Andric // an value in Value2Index (external input to the reproducer). Update Old2New 962*06c3fb27SDimitry Andric // mapping for the original and cloned instructions. Sort instructions to 963*06c3fb27SDimitry Andric // clone by dominance, then insert the cloned instructions in the function. 964*06c3fb27SDimitry Andric auto CloneInstructions = [&](ArrayRef<Value *> Ops, bool IsSigned) { 965*06c3fb27SDimitry Andric SmallVector<Value *, 4> WorkList(Ops); 966*06c3fb27SDimitry Andric SmallVector<Instruction *> ToClone; 967*06c3fb27SDimitry Andric auto &Value2Index = Info.getValue2Index(IsSigned); 968*06c3fb27SDimitry Andric while (!WorkList.empty()) { 969*06c3fb27SDimitry Andric Value *V = WorkList.pop_back_val(); 970*06c3fb27SDimitry Andric if (Old2New.find(V) != Old2New.end()) 971*06c3fb27SDimitry Andric continue; 972*06c3fb27SDimitry Andric 973*06c3fb27SDimitry Andric auto *I = dyn_cast<Instruction>(V); 974*06c3fb27SDimitry Andric if (!Value2Index.contains(V) && I) { 975*06c3fb27SDimitry Andric Old2New[V] = nullptr; 976*06c3fb27SDimitry Andric ToClone.push_back(I); 977*06c3fb27SDimitry Andric append_range(WorkList, I->operands()); 978*06c3fb27SDimitry Andric } 979*06c3fb27SDimitry Andric } 980*06c3fb27SDimitry Andric 981*06c3fb27SDimitry Andric sort(ToClone, 982*06c3fb27SDimitry Andric [&DT](Instruction *A, Instruction *B) { return DT.dominates(A, B); }); 983*06c3fb27SDimitry Andric for (Instruction *I : ToClone) { 984*06c3fb27SDimitry Andric Instruction *Cloned = I->clone(); 985*06c3fb27SDimitry Andric Old2New[I] = Cloned; 986*06c3fb27SDimitry Andric Old2New[I]->setName(I->getName()); 987*06c3fb27SDimitry Andric Cloned->insertBefore(&*Builder.GetInsertPoint()); 988*06c3fb27SDimitry Andric Cloned->dropUnknownNonDebugMetadata(); 989*06c3fb27SDimitry Andric Cloned->setDebugLoc({}); 990*06c3fb27SDimitry Andric } 991*06c3fb27SDimitry Andric }; 992*06c3fb27SDimitry Andric 993*06c3fb27SDimitry Andric // Materialize the assumptions for the reproducer using the entries in Stack. 994*06c3fb27SDimitry Andric // That is, first clone the operands of the condition recursively until we 995*06c3fb27SDimitry Andric // reach an external input to the reproducer and add them to the reproducer 996*06c3fb27SDimitry Andric // function. Then add an ICmp for the condition (with the inverse predicate if 997*06c3fb27SDimitry Andric // the entry is negated) and an assert using the ICmp. 998*06c3fb27SDimitry Andric for (auto &Entry : Stack) { 999*06c3fb27SDimitry Andric if (Entry.Pred == ICmpInst::BAD_ICMP_PREDICATE) 1000*06c3fb27SDimitry Andric continue; 1001*06c3fb27SDimitry Andric 1002*06c3fb27SDimitry Andric LLVM_DEBUG( 1003*06c3fb27SDimitry Andric dbgs() << " Materializing assumption icmp " << Entry.Pred << ' '; 1004*06c3fb27SDimitry Andric Entry.LHS->printAsOperand(dbgs(), /*PrintType=*/true); dbgs() << ", "; 1005*06c3fb27SDimitry Andric Entry.RHS->printAsOperand(dbgs(), /*PrintType=*/false); dbgs() << "\n"); 1006*06c3fb27SDimitry Andric CloneInstructions({Entry.LHS, Entry.RHS}, CmpInst::isSigned(Entry.Pred)); 1007*06c3fb27SDimitry Andric 1008*06c3fb27SDimitry Andric auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS); 1009*06c3fb27SDimitry Andric Builder.CreateAssumption(Cmp); 1010*06c3fb27SDimitry Andric } 1011*06c3fb27SDimitry Andric 1012*06c3fb27SDimitry Andric // Finally, clone the condition to reproduce and remap instruction operands in 1013*06c3fb27SDimitry Andric // the reproducer using Old2New. 1014*06c3fb27SDimitry Andric CloneInstructions(Cond, CmpInst::isSigned(Cond->getPredicate())); 1015*06c3fb27SDimitry Andric Entry->getTerminator()->setOperand(0, Cond); 1016*06c3fb27SDimitry Andric remapInstructionsInBlocks({Entry}, Old2New); 1017*06c3fb27SDimitry Andric 1018*06c3fb27SDimitry Andric assert(!verifyFunction(*F, &dbgs())); 1019*06c3fb27SDimitry Andric } 1020*06c3fb27SDimitry Andric 1021*06c3fb27SDimitry Andric static std::optional<bool> checkCondition(CmpInst *Cmp, ConstraintInfo &Info, 1022*06c3fb27SDimitry Andric unsigned NumIn, unsigned NumOut, 1023*06c3fb27SDimitry 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"); 1033*06c3fb27SDimitry 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 1048*06c3fb27SDimitry Andric if (auto ImpliedCondition = R.isImpliedBy(CSToUse)) { 1049bdd1243dSDimitry Andric if (!DebugCounter::shouldExecute(EliminatedCounter)) 1050*06c3fb27SDimitry Andric return std::nullopt; 1051bdd1243dSDimitry Andric 1052bdd1243dSDimitry Andric LLVM_DEBUG({ 1053*06c3fb27SDimitry Andric if (*ImpliedCondition) { 1054*06c3fb27SDimitry Andric dbgs() << "Condition " << *Cmp; 1055*06c3fb27SDimitry Andric } else { 1056*06c3fb27SDimitry Andric auto InversePred = Cmp->getInversePredicate(); 1057*06c3fb27SDimitry Andric dbgs() << "Condition " << CmpInst::getPredicateName(InversePred) << " " 1058*06c3fb27SDimitry Andric << *A << ", " << *B; 1059*06c3fb27SDimitry Andric } 1060*06c3fb27SDimitry Andric dbgs() << " implied by dominating constraints\n"; 1061*06c3fb27SDimitry Andric CSToUse.dump(); 1062bdd1243dSDimitry Andric }); 1063*06c3fb27SDimitry Andric return ImpliedCondition; 1064*06c3fb27SDimitry Andric } 1065*06c3fb27SDimitry Andric 1066*06c3fb27SDimitry Andric return std::nullopt; 1067*06c3fb27SDimitry Andric } 1068*06c3fb27SDimitry Andric 1069*06c3fb27SDimitry Andric static bool checkAndReplaceCondition( 1070*06c3fb27SDimitry Andric CmpInst *Cmp, ConstraintInfo &Info, unsigned NumIn, unsigned NumOut, 1071*06c3fb27SDimitry Andric Instruction *ContextInst, Module *ReproducerModule, 1072*06c3fb27SDimitry Andric ArrayRef<ReproducerEntry> ReproducerCondStack, DominatorTree &DT) { 1073*06c3fb27SDimitry Andric auto ReplaceCmpWithConstant = [&](CmpInst *Cmp, bool IsTrue) { 1074*06c3fb27SDimitry Andric generateReproducer(Cmp, ReproducerModule, ReproducerCondStack, Info, DT); 1075*06c3fb27SDimitry Andric Constant *ConstantC = ConstantInt::getBool( 1076*06c3fb27SDimitry Andric CmpInst::makeCmpResultType(Cmp->getType()), IsTrue); 1077*06c3fb27SDimitry Andric Cmp->replaceUsesWithIf(ConstantC, [&DT, NumIn, NumOut, 1078*06c3fb27SDimitry Andric ContextInst](Use &U) { 1079*06c3fb27SDimitry Andric auto *UserI = getContextInstForUse(U); 1080*06c3fb27SDimitry Andric auto *DTN = DT.getNode(UserI->getParent()); 1081*06c3fb27SDimitry Andric if (!DTN || DTN->getDFSNumIn() < NumIn || DTN->getDFSNumOut() > NumOut) 1082*06c3fb27SDimitry Andric return false; 1083*06c3fb27SDimitry Andric if (UserI->getParent() == ContextInst->getParent() && 1084*06c3fb27SDimitry Andric UserI->comesBefore(ContextInst)) 1085*06c3fb27SDimitry Andric return false; 1086*06c3fb27SDimitry 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++; 1093*06c3fb27SDimitry Andric return true; 1094*06c3fb27SDimitry Andric }; 1095*06c3fb27SDimitry Andric 1096*06c3fb27SDimitry Andric if (auto ImpliedCondition = 1097*06c3fb27SDimitry Andric checkCondition(Cmp, Info, NumIn, NumOut, ContextInst)) 1098*06c3fb27SDimitry Andric return ReplaceCmpWithConstant(Cmp, *ImpliedCondition); 1099*06c3fb27SDimitry Andric return false; 1100bdd1243dSDimitry Andric } 1101*06c3fb27SDimitry Andric 1102*06c3fb27SDimitry Andric static void 1103*06c3fb27SDimitry Andric removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info, 1104*06c3fb27SDimitry Andric Module *ReproducerModule, 1105*06c3fb27SDimitry Andric SmallVectorImpl<ReproducerEntry> &ReproducerCondStack, 1106*06c3fb27SDimitry Andric SmallVectorImpl<StackEntry> &DFSInStack) { 1107*06c3fb27SDimitry Andric Info.popLastConstraint(E.IsSigned); 1108*06c3fb27SDimitry Andric // Remove variables in the system that went out of scope. 1109*06c3fb27SDimitry Andric auto &Mapping = Info.getValue2Index(E.IsSigned); 1110*06c3fb27SDimitry Andric for (Value *V : E.ValuesToRelease) 1111*06c3fb27SDimitry Andric Mapping.erase(V); 1112*06c3fb27SDimitry Andric Info.popLastNVariables(E.IsSigned, E.ValuesToRelease.size()); 1113*06c3fb27SDimitry Andric DFSInStack.pop_back(); 1114*06c3fb27SDimitry Andric if (ReproducerModule) 1115*06c3fb27SDimitry Andric ReproducerCondStack.pop_back(); 1116*06c3fb27SDimitry Andric } 1117*06c3fb27SDimitry Andric 1118*06c3fb27SDimitry Andric /// Check if the first condition for an AND implies the second. 1119*06c3fb27SDimitry Andric static bool checkAndSecondOpImpliedByFirst( 1120*06c3fb27SDimitry Andric FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule, 1121*06c3fb27SDimitry Andric SmallVectorImpl<ReproducerEntry> &ReproducerCondStack, 1122*06c3fb27SDimitry Andric SmallVectorImpl<StackEntry> &DFSInStack) { 1123*06c3fb27SDimitry Andric CmpInst::Predicate Pred; 1124*06c3fb27SDimitry Andric Value *A, *B; 1125*06c3fb27SDimitry Andric Instruction *And = CB.getContextInst(); 1126*06c3fb27SDimitry Andric if (!match(And->getOperand(0), m_ICmp(Pred, m_Value(A), m_Value(B)))) 1127bdd1243dSDimitry Andric return false; 1128bdd1243dSDimitry Andric 1129*06c3fb27SDimitry Andric // Optimistically add fact from first condition. 1130*06c3fb27SDimitry Andric unsigned OldSize = DFSInStack.size(); 1131*06c3fb27SDimitry Andric Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack); 1132*06c3fb27SDimitry Andric if (OldSize == DFSInStack.size()) 1133*06c3fb27SDimitry Andric return false; 1134*06c3fb27SDimitry Andric 1135*06c3fb27SDimitry Andric bool Changed = false; 1136*06c3fb27SDimitry Andric // Check if the second condition can be simplified now. 1137*06c3fb27SDimitry Andric if (auto ImpliedCondition = 1138*06c3fb27SDimitry Andric checkCondition(cast<ICmpInst>(And->getOperand(1)), Info, CB.NumIn, 1139*06c3fb27SDimitry Andric CB.NumOut, CB.getContextInst())) { 1140*06c3fb27SDimitry Andric And->setOperand(1, ConstantInt::getBool(And->getType(), *ImpliedCondition)); 1141bdd1243dSDimitry Andric Changed = true; 1142bdd1243dSDimitry Andric } 1143*06c3fb27SDimitry Andric 1144*06c3fb27SDimitry Andric // Remove entries again. 1145*06c3fb27SDimitry Andric while (OldSize < DFSInStack.size()) { 1146*06c3fb27SDimitry Andric StackEntry E = DFSInStack.back(); 1147*06c3fb27SDimitry Andric removeEntryFromStack(E, Info, ReproducerModule, ReproducerCondStack, 1148*06c3fb27SDimitry Andric DFSInStack); 1149*06c3fb27SDimitry 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); 1160*06c3fb27SDimitry Andric 1161*06c3fb27SDimitry Andric // TODO: Support non-equality for facts as well. 1162*06c3fb27SDimitry Andric if (!R.isValid(*this) || R.isNe()) 116381ad6265SDimitry Andric return; 116481ad6265SDimitry Andric 1165*06c3fb27SDimitry 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: "; 1187*06c3fb27SDimitry 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 1194*06c3fb27SDimitry 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 1266*06c3fb27SDimitry Andric static bool eliminateConstraints(Function &F, DominatorTree &DT, 1267*06c3fb27SDimitry Andric OptimizationRemarkEmitter &ORE) { 126881ad6265SDimitry Andric bool Changed = false; 126981ad6265SDimitry Andric DT.updateDFSNumbers(); 1270*06c3fb27SDimitry Andric SmallVector<Value *> FunctionArgs; 1271*06c3fb27SDimitry Andric for (Value &Arg : F.args()) 1272*06c3fb27SDimitry Andric FunctionArgs.push_back(&Arg); 1273*06c3fb27SDimitry Andric ConstraintInfo Info(F.getParent()->getDataLayout(), FunctionArgs); 127481ad6265SDimitry Andric State S(DT); 1275*06c3fb27SDimitry Andric std::unique_ptr<Module> ReproducerModule( 1276*06c3fb27SDimitry 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; 1311*06c3fb27SDimitry Andric auto *InstA = A.getContextInst(); 1312*06c3fb27SDimitry Andric auto *InstB = B.getContextInst(); 1313*06c3fb27SDimitry 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; 1322*06c3fb27SDimitry 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 "; 1336*06c3fb27SDimitry Andric dumpConstraint(Info.getCS(E.IsSigned).getLastConstraint(), 133781ad6265SDimitry Andric Info.getValue2Index(E.IsSigned)); 133881ad6265SDimitry Andric dbgs() << "\n"; 133981ad6265SDimitry Andric }); 1340*06c3fb27SDimitry Andric removeEntryFromStack(E, Info, ReproducerModule.get(), ReproducerCondStack, 1341*06c3fb27SDimitry Andric DFSInStack); 1342e8d8bef9SDimitry Andric } 1343e8d8bef9SDimitry Andric 1344*06c3fb27SDimitry 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. 1348*06c3fb27SDimitry Andric if (CB.isCheck()) { 1349*06c3fb27SDimitry Andric Instruction *Inst = CB.getInstructionToSimplify(); 1350*06c3fb27SDimitry Andric if (!Inst) 1351*06c3fb27SDimitry Andric continue; 1352*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "condition to simplify: " << *Inst << "\n"); 1353*06c3fb27SDimitry Andric if (auto *II = dyn_cast<WithOverflowInst>(Inst)) { 1354bdd1243dSDimitry Andric Changed |= tryToSimplifyOverflowMath(II, Info, ToRemove); 1355*06c3fb27SDimitry Andric } else if (auto *Cmp = dyn_cast<ICmpInst>(Inst)) { 1356*06c3fb27SDimitry Andric bool Simplified = checkAndReplaceCondition( 1357*06c3fb27SDimitry Andric Cmp, Info, CB.NumIn, CB.NumOut, CB.getContextInst(), 1358*06c3fb27SDimitry Andric ReproducerModule.get(), ReproducerCondStack, S.DT); 1359*06c3fb27SDimitry Andric if (!Simplified && match(CB.getContextInst(), 1360*06c3fb27SDimitry Andric m_LogicalAnd(m_Value(), m_Specific(Inst)))) { 1361*06c3fb27SDimitry Andric Simplified = 1362*06c3fb27SDimitry Andric checkAndSecondOpImpliedByFirst(CB, Info, ReproducerModule.get(), 1363*06c3fb27SDimitry Andric ReproducerCondStack, DFSInStack); 1364*06c3fb27SDimitry Andric } 1365*06c3fb27SDimitry Andric Changed |= Simplified; 1366e8d8bef9SDimitry Andric } 1367e8d8bef9SDimitry Andric continue; 1368e8d8bef9SDimitry Andric } 1369e8d8bef9SDimitry Andric 1370*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "fact to add to the system: " << *CB.Inst << "\n"); 1371*06c3fb27SDimitry 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"); 1376*06c3fb27SDimitry Andric return; 1377*06c3fb27SDimitry Andric } 1378*06c3fb27SDimitry Andric 1379*06c3fb27SDimitry Andric Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack); 1380*06c3fb27SDimitry Andric if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) 1381*06c3fb27SDimitry Andric ReproducerCondStack.emplace_back(Pred, A, B); 1382*06c3fb27SDimitry Andric 1383*06c3fb27SDimitry Andric Info.transferToOtherSystem(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack); 1384*06c3fb27SDimitry Andric if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) { 1385*06c3fb27SDimitry Andric // Add dummy entries to ReproducerCondStack to keep it in sync with 1386*06c3fb27SDimitry Andric // DFSInStack. 1387*06c3fb27SDimitry Andric for (unsigned I = 0, 1388*06c3fb27SDimitry Andric E = (DFSInStack.size() - ReproducerCondStack.size()); 1389*06c3fb27SDimitry Andric I < E; ++I) { 1390*06c3fb27SDimitry Andric ReproducerCondStack.emplace_back(ICmpInst::BAD_ICMP_PREDICATE, 1391*06c3fb27SDimitry Andric nullptr, nullptr); 1392*06c3fb27SDimitry Andric } 1393*06c3fb27SDimitry Andric } 1394*06c3fb27SDimitry Andric }; 1395*06c3fb27SDimitry Andric 1396*06c3fb27SDimitry Andric ICmpInst::Predicate Pred; 1397*06c3fb27SDimitry Andric if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) { 1398*06c3fb27SDimitry Andric Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate()); 1399*06c3fb27SDimitry Andric AddFact(Pred, MinMax, MinMax->getLHS()); 1400*06c3fb27SDimitry Andric AddFact(Pred, MinMax, MinMax->getRHS()); 1401bdd1243dSDimitry Andric continue; 1402bdd1243dSDimitry Andric } 1403bdd1243dSDimitry Andric 1404*06c3fb27SDimitry Andric Value *A, *B; 1405*06c3fb27SDimitry Andric Value *Cmp = CB.Inst; 1406*06c3fb27SDimitry Andric match(Cmp, m_Intrinsic<Intrinsic::assume>(m_Value(Cmp))); 1407*06c3fb27SDimitry 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 1412*06c3fb27SDimitry Andric AddFact(Pred, A, B); 1413e8d8bef9SDimitry Andric } 1414fe6060f1SDimitry Andric } 1415e8d8bef9SDimitry Andric 1416*06c3fb27SDimitry Andric if (ReproducerModule && !ReproducerModule->functions().empty()) { 1417*06c3fb27SDimitry Andric std::string S; 1418*06c3fb27SDimitry Andric raw_string_ostream StringS(S); 1419*06c3fb27SDimitry Andric ReproducerModule->print(StringS, nullptr); 1420*06c3fb27SDimitry Andric StringS.flush(); 1421*06c3fb27SDimitry Andric OptimizationRemark Rem(DEBUG_TYPE, "Reproducer", &F); 1422*06c3fb27SDimitry Andric Rem << ore::NV("module") << S; 1423*06c3fb27SDimitry Andric ORE.emit(Rem); 1424*06c3fb27SDimitry Andric } 1425*06c3fb27SDimitry 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); 1443*06c3fb27SDimitry Andric auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F); 1444*06c3fb27SDimitry 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