Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
35269 views
//===-- ConstraintElimination.cpp - Eliminate conds using constraints. ----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Eliminate conditions based on constraints collected from dominating9// conditions.10//11//===----------------------------------------------------------------------===//1213#include "llvm/Transforms/Scalar/ConstraintElimination.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/ADT/ScopeExit.h"16#include "llvm/ADT/SmallVector.h"17#include "llvm/ADT/Statistic.h"18#include "llvm/Analysis/ConstraintSystem.h"19#include "llvm/Analysis/GlobalsModRef.h"20#include "llvm/Analysis/LoopInfo.h"21#include "llvm/Analysis/OptimizationRemarkEmitter.h"22#include "llvm/Analysis/ScalarEvolution.h"23#include "llvm/Analysis/ScalarEvolutionExpressions.h"24#include "llvm/Analysis/ValueTracking.h"25#include "llvm/IR/DataLayout.h"26#include "llvm/IR/Dominators.h"27#include "llvm/IR/Function.h"28#include "llvm/IR/IRBuilder.h"29#include "llvm/IR/InstrTypes.h"30#include "llvm/IR/Instructions.h"31#include "llvm/IR/Module.h"32#include "llvm/IR/PatternMatch.h"33#include "llvm/IR/Verifier.h"34#include "llvm/Pass.h"35#include "llvm/Support/CommandLine.h"36#include "llvm/Support/Debug.h"37#include "llvm/Support/DebugCounter.h"38#include "llvm/Support/MathExtras.h"39#include "llvm/Transforms/Utils/Cloning.h"40#include "llvm/Transforms/Utils/ValueMapper.h"4142#include <cmath>43#include <optional>44#include <string>4546using namespace llvm;47using namespace PatternMatch;4849#define DEBUG_TYPE "constraint-elimination"5051STATISTIC(NumCondsRemoved, "Number of instructions removed");52DEBUG_COUNTER(EliminatedCounter, "conds-eliminated",53"Controls which conditions are eliminated");5455static cl::opt<unsigned>56MaxRows("constraint-elimination-max-rows", cl::init(500), cl::Hidden,57cl::desc("Maximum number of rows to keep in constraint system"));5859static cl::opt<bool> DumpReproducers(60"constraint-elimination-dump-reproducers", cl::init(false), cl::Hidden,61cl::desc("Dump IR to reproduce successful transformations."));6263static int64_t MaxConstraintValue = std::numeric_limits<int64_t>::max();64static int64_t MinSignedConstraintValue = std::numeric_limits<int64_t>::min();6566// A helper to multiply 2 signed integers where overflowing is allowed.67static int64_t multiplyWithOverflow(int64_t A, int64_t B) {68int64_t Result;69MulOverflow(A, B, Result);70return Result;71}7273// A helper to add 2 signed integers where overflowing is allowed.74static int64_t addWithOverflow(int64_t A, int64_t B) {75int64_t Result;76AddOverflow(A, B, Result);77return Result;78}7980static Instruction *getContextInstForUse(Use &U) {81Instruction *UserI = cast<Instruction>(U.getUser());82if (auto *Phi = dyn_cast<PHINode>(UserI))83UserI = Phi->getIncomingBlock(U)->getTerminator();84return UserI;85}8687namespace {88/// Struct to express a condition of the form %Op0 Pred %Op1.89struct ConditionTy {90CmpInst::Predicate Pred;91Value *Op0;92Value *Op1;9394ConditionTy()95: Pred(CmpInst::BAD_ICMP_PREDICATE), Op0(nullptr), Op1(nullptr) {}96ConditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1)97: Pred(Pred), Op0(Op0), Op1(Op1) {}98};99100/// Represents either101/// * a condition that holds on entry to a block (=condition fact)102/// * an assume (=assume fact)103/// * a use of a compare instruction to simplify.104/// It also tracks the Dominator DFS in and out numbers for each entry.105struct FactOrCheck {106enum class EntryTy {107ConditionFact, /// A condition that holds on entry to a block.108InstFact, /// A fact that holds after Inst executed (e.g. an assume or109/// min/mix intrinsic.110InstCheck, /// An instruction to simplify (e.g. an overflow math111/// intrinsics).112UseCheck /// An use of a compare instruction to simplify.113};114115union {116Instruction *Inst;117Use *U;118ConditionTy Cond;119};120121/// A pre-condition that must hold for the current fact to be added to the122/// system.123ConditionTy DoesHold;124125unsigned NumIn;126unsigned NumOut;127EntryTy Ty;128129FactOrCheck(EntryTy Ty, DomTreeNode *DTN, Instruction *Inst)130: Inst(Inst), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),131Ty(Ty) {}132133FactOrCheck(DomTreeNode *DTN, Use *U)134: U(U), DoesHold(CmpInst::BAD_ICMP_PREDICATE, nullptr, nullptr),135NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),136Ty(EntryTy::UseCheck) {}137138FactOrCheck(DomTreeNode *DTN, CmpInst::Predicate Pred, Value *Op0, Value *Op1,139ConditionTy Precond = ConditionTy())140: Cond(Pred, Op0, Op1), DoesHold(Precond), NumIn(DTN->getDFSNumIn()),141NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {}142143static FactOrCheck getConditionFact(DomTreeNode *DTN, CmpInst::Predicate Pred,144Value *Op0, Value *Op1,145ConditionTy Precond = ConditionTy()) {146return FactOrCheck(DTN, Pred, Op0, Op1, Precond);147}148149static FactOrCheck getInstFact(DomTreeNode *DTN, Instruction *Inst) {150return FactOrCheck(EntryTy::InstFact, DTN, Inst);151}152153static FactOrCheck getCheck(DomTreeNode *DTN, Use *U) {154return FactOrCheck(DTN, U);155}156157static FactOrCheck getCheck(DomTreeNode *DTN, CallInst *CI) {158return FactOrCheck(EntryTy::InstCheck, DTN, CI);159}160161bool isCheck() const {162return Ty == EntryTy::InstCheck || Ty == EntryTy::UseCheck;163}164165Instruction *getContextInst() const {166if (Ty == EntryTy::UseCheck)167return getContextInstForUse(*U);168return Inst;169}170171Instruction *getInstructionToSimplify() const {172assert(isCheck());173if (Ty == EntryTy::InstCheck)174return Inst;175// The use may have been simplified to a constant already.176return dyn_cast<Instruction>(*U);177}178179bool isConditionFact() const { return Ty == EntryTy::ConditionFact; }180};181182/// Keep state required to build worklist.183struct State {184DominatorTree &DT;185LoopInfo &LI;186ScalarEvolution &SE;187SmallVector<FactOrCheck, 64> WorkList;188189State(DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE)190: DT(DT), LI(LI), SE(SE) {}191192/// Process block \p BB and add known facts to work-list.193void addInfoFor(BasicBlock &BB);194195/// Try to add facts for loop inductions (AddRecs) in EQ/NE compares196/// controlling the loop header.197void addInfoForInductions(BasicBlock &BB);198199/// Returns true if we can add a known condition from BB to its successor200/// block Succ.201bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ) const {202return DT.dominates(BasicBlockEdge(&BB, Succ), Succ);203}204};205206class ConstraintInfo;207208struct StackEntry {209unsigned NumIn;210unsigned NumOut;211bool IsSigned = false;212/// Variables that can be removed from the system once the stack entry gets213/// removed.214SmallVector<Value *, 2> ValuesToRelease;215216StackEntry(unsigned NumIn, unsigned NumOut, bool IsSigned,217SmallVector<Value *, 2> ValuesToRelease)218: NumIn(NumIn), NumOut(NumOut), IsSigned(IsSigned),219ValuesToRelease(ValuesToRelease) {}220};221222struct ConstraintTy {223SmallVector<int64_t, 8> Coefficients;224SmallVector<ConditionTy, 2> Preconditions;225226SmallVector<SmallVector<int64_t, 8>> ExtraInfo;227228bool IsSigned = false;229230ConstraintTy() = default;231232ConstraintTy(SmallVector<int64_t, 8> Coefficients, bool IsSigned, bool IsEq,233bool IsNe)234: Coefficients(std::move(Coefficients)), IsSigned(IsSigned), IsEq(IsEq),235IsNe(IsNe) {}236237unsigned size() const { return Coefficients.size(); }238239unsigned empty() const { return Coefficients.empty(); }240241/// Returns true if all preconditions for this list of constraints are242/// satisfied given \p CS and the corresponding \p Value2Index mapping.243bool isValid(const ConstraintInfo &Info) const;244245bool isEq() const { return IsEq; }246247bool isNe() const { return IsNe; }248249/// Check if the current constraint is implied by the given ConstraintSystem.250///251/// \return true or false if the constraint is proven to be respectively true,252/// or false. When the constraint cannot be proven to be either true or false,253/// std::nullopt is returned.254std::optional<bool> isImpliedBy(const ConstraintSystem &CS) const;255256private:257bool IsEq = false;258bool IsNe = false;259};260261/// Wrapper encapsulating separate constraint systems and corresponding value262/// mappings for both unsigned and signed information. Facts are added to and263/// conditions are checked against the corresponding system depending on the264/// signed-ness of their predicates. While the information is kept separate265/// based on signed-ness, certain conditions can be transferred between the two266/// systems.267class ConstraintInfo {268269ConstraintSystem UnsignedCS;270ConstraintSystem SignedCS;271272const DataLayout &DL;273274public:275ConstraintInfo(const DataLayout &DL, ArrayRef<Value *> FunctionArgs)276: UnsignedCS(FunctionArgs), SignedCS(FunctionArgs), DL(DL) {277auto &Value2Index = getValue2Index(false);278// Add Arg > -1 constraints to unsigned system for all function arguments.279for (Value *Arg : FunctionArgs) {280ConstraintTy VarPos(SmallVector<int64_t, 8>(Value2Index.size() + 1, 0),281false, false, false);282VarPos.Coefficients[Value2Index[Arg]] = -1;283UnsignedCS.addVariableRow(VarPos.Coefficients);284}285}286287DenseMap<Value *, unsigned> &getValue2Index(bool Signed) {288return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();289}290const DenseMap<Value *, unsigned> &getValue2Index(bool Signed) const {291return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();292}293294ConstraintSystem &getCS(bool Signed) {295return Signed ? SignedCS : UnsignedCS;296}297const ConstraintSystem &getCS(bool Signed) const {298return Signed ? SignedCS : UnsignedCS;299}300301void popLastConstraint(bool Signed) { getCS(Signed).popLastConstraint(); }302void popLastNVariables(bool Signed, unsigned N) {303getCS(Signed).popLastNVariables(N);304}305306bool doesHold(CmpInst::Predicate Pred, Value *A, Value *B) const;307308void addFact(CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn,309unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack);310311/// Turn a comparison of the form \p Op0 \p Pred \p Op1 into a vector of312/// constraints, using indices from the corresponding constraint system.313/// New variables that need to be added to the system are collected in314/// \p NewVariables.315ConstraintTy getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,316SmallVectorImpl<Value *> &NewVariables) const;317318/// Turns a comparison of the form \p Op0 \p Pred \p Op1 into a vector of319/// constraints using getConstraint. Returns an empty constraint if the result320/// cannot be used to query the existing constraint system, e.g. because it321/// would require adding new variables. Also tries to convert signed322/// predicates to unsigned ones if possible to allow using the unsigned system323/// which increases the effectiveness of the signed <-> unsigned transfer324/// logic.325ConstraintTy getConstraintForSolving(CmpInst::Predicate Pred, Value *Op0,326Value *Op1) const;327328/// Try to add information from \p A \p Pred \p B to the unsigned/signed329/// system if \p Pred is signed/unsigned.330void transferToOtherSystem(CmpInst::Predicate Pred, Value *A, Value *B,331unsigned NumIn, unsigned NumOut,332SmallVectorImpl<StackEntry> &DFSInStack);333};334335/// Represents a (Coefficient * Variable) entry after IR decomposition.336struct DecompEntry {337int64_t Coefficient;338Value *Variable;339/// True if the variable is known positive in the current constraint.340bool IsKnownNonNegative;341342DecompEntry(int64_t Coefficient, Value *Variable,343bool IsKnownNonNegative = false)344: Coefficient(Coefficient), Variable(Variable),345IsKnownNonNegative(IsKnownNonNegative) {}346};347348/// Represents an Offset + Coefficient1 * Variable1 + ... decomposition.349struct Decomposition {350int64_t Offset = 0;351SmallVector<DecompEntry, 3> Vars;352353Decomposition(int64_t Offset) : Offset(Offset) {}354Decomposition(Value *V, bool IsKnownNonNegative = false) {355Vars.emplace_back(1, V, IsKnownNonNegative);356}357Decomposition(int64_t Offset, ArrayRef<DecompEntry> Vars)358: Offset(Offset), Vars(Vars) {}359360void add(int64_t OtherOffset) {361Offset = addWithOverflow(Offset, OtherOffset);362}363364void add(const Decomposition &Other) {365add(Other.Offset);366append_range(Vars, Other.Vars);367}368369void sub(const Decomposition &Other) {370Decomposition Tmp = Other;371Tmp.mul(-1);372add(Tmp.Offset);373append_range(Vars, Tmp.Vars);374}375376void mul(int64_t Factor) {377Offset = multiplyWithOverflow(Offset, Factor);378for (auto &Var : Vars)379Var.Coefficient = multiplyWithOverflow(Var.Coefficient, Factor);380}381};382383// Variable and constant offsets for a chain of GEPs, with base pointer BasePtr.384struct OffsetResult {385Value *BasePtr;386APInt ConstantOffset;387MapVector<Value *, APInt> VariableOffsets;388bool AllInbounds;389390OffsetResult() : BasePtr(nullptr), ConstantOffset(0, uint64_t(0)) {}391392OffsetResult(GEPOperator &GEP, const DataLayout &DL)393: BasePtr(GEP.getPointerOperand()), AllInbounds(GEP.isInBounds()) {394ConstantOffset = APInt(DL.getIndexTypeSizeInBits(BasePtr->getType()), 0);395}396};397} // namespace398399// Try to collect variable and constant offsets for \p GEP, partly traversing400// nested GEPs. Returns an OffsetResult with nullptr as BasePtr of collecting401// the offset fails.402static OffsetResult collectOffsets(GEPOperator &GEP, const DataLayout &DL) {403OffsetResult Result(GEP, DL);404unsigned BitWidth = Result.ConstantOffset.getBitWidth();405if (!GEP.collectOffset(DL, BitWidth, Result.VariableOffsets,406Result.ConstantOffset))407return {};408409// If we have a nested GEP, check if we can combine the constant offset of the410// inner GEP with the outer GEP.411if (auto *InnerGEP = dyn_cast<GetElementPtrInst>(Result.BasePtr)) {412MapVector<Value *, APInt> VariableOffsets2;413APInt ConstantOffset2(BitWidth, 0);414bool CanCollectInner = InnerGEP->collectOffset(415DL, BitWidth, VariableOffsets2, ConstantOffset2);416// TODO: Support cases with more than 1 variable offset.417if (!CanCollectInner || Result.VariableOffsets.size() > 1 ||418VariableOffsets2.size() > 1 ||419(Result.VariableOffsets.size() >= 1 && VariableOffsets2.size() >= 1)) {420// More than 1 variable index, use outer result.421return Result;422}423Result.BasePtr = InnerGEP->getPointerOperand();424Result.ConstantOffset += ConstantOffset2;425if (Result.VariableOffsets.size() == 0 && VariableOffsets2.size() == 1)426Result.VariableOffsets = VariableOffsets2;427Result.AllInbounds &= InnerGEP->isInBounds();428}429return Result;430}431432static Decomposition decompose(Value *V,433SmallVectorImpl<ConditionTy> &Preconditions,434bool IsSigned, const DataLayout &DL);435436static bool canUseSExt(ConstantInt *CI) {437const APInt &Val = CI->getValue();438return Val.sgt(MinSignedConstraintValue) && Val.slt(MaxConstraintValue);439}440441static Decomposition decomposeGEP(GEPOperator &GEP,442SmallVectorImpl<ConditionTy> &Preconditions,443bool IsSigned, const DataLayout &DL) {444// Do not reason about pointers where the index size is larger than 64 bits,445// as the coefficients used to encode constraints are 64 bit integers.446if (DL.getIndexTypeSizeInBits(GEP.getPointerOperand()->getType()) > 64)447return &GEP;448449assert(!IsSigned && "The logic below only supports decomposition for "450"unsigned predicates at the moment.");451const auto &[BasePtr, ConstantOffset, VariableOffsets, AllInbounds] =452collectOffsets(GEP, DL);453if (!BasePtr || !AllInbounds)454return &GEP;455456Decomposition Result(ConstantOffset.getSExtValue(), DecompEntry(1, BasePtr));457for (auto [Index, Scale] : VariableOffsets) {458auto IdxResult = decompose(Index, Preconditions, IsSigned, DL);459IdxResult.mul(Scale.getSExtValue());460Result.add(IdxResult);461462// If Op0 is signed non-negative, the GEP is increasing monotonically and463// can be de-composed.464if (!isKnownNonNegative(Index, DL))465Preconditions.emplace_back(CmpInst::ICMP_SGE, Index,466ConstantInt::get(Index->getType(), 0));467}468return Result;469}470471// Decomposes \p V into a constant offset + list of pairs { Coefficient,472// Variable } where Coefficient * Variable. The sum of the constant offset and473// pairs equals \p V.474static Decomposition decompose(Value *V,475SmallVectorImpl<ConditionTy> &Preconditions,476bool IsSigned, const DataLayout &DL) {477478auto MergeResults = [&Preconditions, IsSigned, &DL](Value *A, Value *B,479bool IsSignedB) {480auto ResA = decompose(A, Preconditions, IsSigned, DL);481auto ResB = decompose(B, Preconditions, IsSignedB, DL);482ResA.add(ResB);483return ResA;484};485486Type *Ty = V->getType()->getScalarType();487if (Ty->isPointerTy() && !IsSigned) {488if (auto *GEP = dyn_cast<GEPOperator>(V))489return decomposeGEP(*GEP, Preconditions, IsSigned, DL);490if (isa<ConstantPointerNull>(V))491return int64_t(0);492493return V;494}495496// Don't handle integers > 64 bit. Our coefficients are 64-bit large, so497// coefficient add/mul may wrap, while the operation in the full bit width498// would not.499if (!Ty->isIntegerTy() || Ty->getIntegerBitWidth() > 64)500return V;501502bool IsKnownNonNegative = false;503504// Decompose \p V used with a signed predicate.505if (IsSigned) {506if (auto *CI = dyn_cast<ConstantInt>(V)) {507if (canUseSExt(CI))508return CI->getSExtValue();509}510Value *Op0;511Value *Op1;512513if (match(V, m_SExt(m_Value(Op0))))514V = Op0;515else if (match(V, m_NNegZExt(m_Value(Op0)))) {516V = Op0;517IsKnownNonNegative = true;518}519520if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1))))521return MergeResults(Op0, Op1, IsSigned);522523ConstantInt *CI;524if (match(V, m_NSWMul(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI)) {525auto Result = decompose(Op0, Preconditions, IsSigned, DL);526Result.mul(CI->getSExtValue());527return Result;528}529530// (shl nsw x, shift) is (mul nsw x, (1<<shift)), with the exception of531// shift == bw-1.532if (match(V, m_NSWShl(m_Value(Op0), m_ConstantInt(CI)))) {533uint64_t Shift = CI->getValue().getLimitedValue();534if (Shift < Ty->getIntegerBitWidth() - 1) {535assert(Shift < 64 && "Would overflow");536auto Result = decompose(Op0, Preconditions, IsSigned, DL);537Result.mul(int64_t(1) << Shift);538return Result;539}540}541542return {V, IsKnownNonNegative};543}544545if (auto *CI = dyn_cast<ConstantInt>(V)) {546if (CI->uge(MaxConstraintValue))547return V;548return int64_t(CI->getZExtValue());549}550551Value *Op0;552if (match(V, m_ZExt(m_Value(Op0)))) {553IsKnownNonNegative = true;554V = Op0;555}556557if (match(V, m_SExt(m_Value(Op0)))) {558V = Op0;559Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,560ConstantInt::get(Op0->getType(), 0));561}562563Value *Op1;564ConstantInt *CI;565if (match(V, m_NUWAdd(m_Value(Op0), m_Value(Op1)))) {566return MergeResults(Op0, Op1, IsSigned);567}568if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) {569if (!isKnownNonNegative(Op0, DL))570Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,571ConstantInt::get(Op0->getType(), 0));572if (!isKnownNonNegative(Op1, DL))573Preconditions.emplace_back(CmpInst::ICMP_SGE, Op1,574ConstantInt::get(Op1->getType(), 0));575576return MergeResults(Op0, Op1, IsSigned);577}578579if (match(V, m_Add(m_Value(Op0), m_ConstantInt(CI))) && CI->isNegative() &&580canUseSExt(CI)) {581Preconditions.emplace_back(582CmpInst::ICMP_UGE, Op0,583ConstantInt::get(Op0->getType(), CI->getSExtValue() * -1));584return MergeResults(Op0, CI, true);585}586587// Decompose or as an add if there are no common bits between the operands.588if (match(V, m_DisjointOr(m_Value(Op0), m_ConstantInt(CI))))589return MergeResults(Op0, CI, IsSigned);590591if (match(V, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI)) {592if (CI->getSExtValue() < 0 || CI->getSExtValue() >= 64)593return {V, IsKnownNonNegative};594auto Result = decompose(Op1, Preconditions, IsSigned, DL);595Result.mul(int64_t{1} << CI->getSExtValue());596return Result;597}598599if (match(V, m_NUWMul(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI) &&600(!CI->isNegative())) {601auto Result = decompose(Op1, Preconditions, IsSigned, DL);602Result.mul(CI->getSExtValue());603return Result;604}605606if (match(V, m_NUWSub(m_Value(Op0), m_Value(Op1)))) {607auto ResA = decompose(Op0, Preconditions, IsSigned, DL);608auto ResB = decompose(Op1, Preconditions, IsSigned, DL);609ResA.sub(ResB);610return ResA;611}612613return {V, IsKnownNonNegative};614}615616ConstraintTy617ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,618SmallVectorImpl<Value *> &NewVariables) const {619assert(NewVariables.empty() && "NewVariables must be empty when passed in");620bool IsEq = false;621bool IsNe = false;622623// Try to convert Pred to one of ULE/SLT/SLE/SLT.624switch (Pred) {625case CmpInst::ICMP_UGT:626case CmpInst::ICMP_UGE:627case CmpInst::ICMP_SGT:628case CmpInst::ICMP_SGE: {629Pred = CmpInst::getSwappedPredicate(Pred);630std::swap(Op0, Op1);631break;632}633case CmpInst::ICMP_EQ:634if (match(Op1, m_Zero())) {635Pred = CmpInst::ICMP_ULE;636} else {637IsEq = true;638Pred = CmpInst::ICMP_ULE;639}640break;641case CmpInst::ICMP_NE:642if (match(Op1, m_Zero())) {643Pred = CmpInst::getSwappedPredicate(CmpInst::ICMP_UGT);644std::swap(Op0, Op1);645} else {646IsNe = true;647Pred = CmpInst::ICMP_ULE;648}649break;650default:651break;652}653654if (Pred != CmpInst::ICMP_ULE && Pred != CmpInst::ICMP_ULT &&655Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SLT)656return {};657658SmallVector<ConditionTy, 4> Preconditions;659bool IsSigned = CmpInst::isSigned(Pred);660auto &Value2Index = getValue2Index(IsSigned);661auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(),662Preconditions, IsSigned, DL);663auto BDec = decompose(Op1->stripPointerCastsSameRepresentation(),664Preconditions, IsSigned, DL);665int64_t Offset1 = ADec.Offset;666int64_t Offset2 = BDec.Offset;667Offset1 *= -1;668669auto &VariablesA = ADec.Vars;670auto &VariablesB = BDec.Vars;671672// First try to look up \p V in Value2Index and NewVariables. Otherwise add a673// new entry to NewVariables.674SmallDenseMap<Value *, unsigned> NewIndexMap;675auto GetOrAddIndex = [&Value2Index, &NewVariables,676&NewIndexMap](Value *V) -> unsigned {677auto V2I = Value2Index.find(V);678if (V2I != Value2Index.end())679return V2I->second;680auto Insert =681NewIndexMap.insert({V, Value2Index.size() + NewVariables.size() + 1});682if (Insert.second)683NewVariables.push_back(V);684return Insert.first->second;685};686687// Make sure all variables have entries in Value2Index or NewVariables.688for (const auto &KV : concat<DecompEntry>(VariablesA, VariablesB))689GetOrAddIndex(KV.Variable);690691// Build result constraint, by first adding all coefficients from A and then692// subtracting all coefficients from B.693ConstraintTy Res(694SmallVector<int64_t, 8>(Value2Index.size() + NewVariables.size() + 1, 0),695IsSigned, IsEq, IsNe);696// Collect variables that are known to be positive in all uses in the697// constraint.698SmallDenseMap<Value *, bool> KnownNonNegativeVariables;699auto &R = Res.Coefficients;700for (const auto &KV : VariablesA) {701R[GetOrAddIndex(KV.Variable)] += KV.Coefficient;702auto I =703KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative});704I.first->second &= KV.IsKnownNonNegative;705}706707for (const auto &KV : VariablesB) {708if (SubOverflow(R[GetOrAddIndex(KV.Variable)], KV.Coefficient,709R[GetOrAddIndex(KV.Variable)]))710return {};711auto I =712KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative});713I.first->second &= KV.IsKnownNonNegative;714}715716int64_t OffsetSum;717if (AddOverflow(Offset1, Offset2, OffsetSum))718return {};719if (Pred == (IsSigned ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT))720if (AddOverflow(OffsetSum, int64_t(-1), OffsetSum))721return {};722R[0] = OffsetSum;723Res.Preconditions = std::move(Preconditions);724725// Remove any (Coefficient, Variable) entry where the Coefficient is 0 for new726// variables.727while (!NewVariables.empty()) {728int64_t Last = R.back();729if (Last != 0)730break;731R.pop_back();732Value *RemovedV = NewVariables.pop_back_val();733NewIndexMap.erase(RemovedV);734}735736// Add extra constraints for variables that are known positive.737for (auto &KV : KnownNonNegativeVariables) {738if (!KV.second ||739(!Value2Index.contains(KV.first) && !NewIndexMap.contains(KV.first)))740continue;741SmallVector<int64_t, 8> C(Value2Index.size() + NewVariables.size() + 1, 0);742C[GetOrAddIndex(KV.first)] = -1;743Res.ExtraInfo.push_back(C);744}745return Res;746}747748ConstraintTy ConstraintInfo::getConstraintForSolving(CmpInst::Predicate Pred,749Value *Op0,750Value *Op1) const {751Constant *NullC = Constant::getNullValue(Op0->getType());752// Handle trivially true compares directly to avoid adding V UGE 0 constraints753// for all variables in the unsigned system.754if ((Pred == CmpInst::ICMP_ULE && Op0 == NullC) ||755(Pred == CmpInst::ICMP_UGE && Op1 == NullC)) {756auto &Value2Index = getValue2Index(false);757// Return constraint that's trivially true.758return ConstraintTy(SmallVector<int64_t, 8>(Value2Index.size(), 0), false,759false, false);760}761762// If both operands are known to be non-negative, change signed predicates to763// unsigned ones. This increases the reasoning effectiveness in combination764// with the signed <-> unsigned transfer logic.765if (CmpInst::isSigned(Pred) &&766isKnownNonNegative(Op0, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1) &&767isKnownNonNegative(Op1, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1))768Pred = CmpInst::getUnsignedPredicate(Pred);769770SmallVector<Value *> NewVariables;771ConstraintTy R = getConstraint(Pred, Op0, Op1, NewVariables);772if (!NewVariables.empty())773return {};774return R;775}776777bool ConstraintTy::isValid(const ConstraintInfo &Info) const {778return Coefficients.size() > 0 &&779all_of(Preconditions, [&Info](const ConditionTy &C) {780return Info.doesHold(C.Pred, C.Op0, C.Op1);781});782}783784std::optional<bool>785ConstraintTy::isImpliedBy(const ConstraintSystem &CS) const {786bool IsConditionImplied = CS.isConditionImplied(Coefficients);787788if (IsEq || IsNe) {789auto NegatedOrEqual = ConstraintSystem::negateOrEqual(Coefficients);790bool IsNegatedOrEqualImplied =791!NegatedOrEqual.empty() && CS.isConditionImplied(NegatedOrEqual);792793// In order to check that `%a == %b` is true (equality), both conditions `%a794// >= %b` and `%a <= %b` must hold true. When checking for equality (`IsEq`795// is true), we return true if they both hold, false in the other cases.796if (IsConditionImplied && IsNegatedOrEqualImplied)797return IsEq;798799auto Negated = ConstraintSystem::negate(Coefficients);800bool IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated);801802auto StrictLessThan = ConstraintSystem::toStrictLessThan(Coefficients);803bool IsStrictLessThanImplied =804!StrictLessThan.empty() && CS.isConditionImplied(StrictLessThan);805806// In order to check that `%a != %b` is true (non-equality), either807// condition `%a > %b` or `%a < %b` must hold true. When checking for808// non-equality (`IsNe` is true), we return true if one of the two holds,809// false in the other cases.810if (IsNegatedImplied || IsStrictLessThanImplied)811return IsNe;812813return std::nullopt;814}815816if (IsConditionImplied)817return true;818819auto Negated = ConstraintSystem::negate(Coefficients);820auto IsNegatedImplied = !Negated.empty() && CS.isConditionImplied(Negated);821if (IsNegatedImplied)822return false;823824// Neither the condition nor its negated holds, did not prove anything.825return std::nullopt;826}827828bool ConstraintInfo::doesHold(CmpInst::Predicate Pred, Value *A,829Value *B) const {830auto R = getConstraintForSolving(Pred, A, B);831return R.isValid(*this) &&832getCS(R.IsSigned).isConditionImplied(R.Coefficients);833}834835void ConstraintInfo::transferToOtherSystem(836CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn,837unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack) {838auto IsKnownNonNegative = [this](Value *V) {839return doesHold(CmpInst::ICMP_SGE, V, ConstantInt::get(V->getType(), 0)) ||840isKnownNonNegative(V, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1);841};842// Check if we can combine facts from the signed and unsigned systems to843// derive additional facts.844if (!A->getType()->isIntegerTy())845return;846// FIXME: This currently depends on the order we add facts. Ideally we847// would first add all known facts and only then try to add additional848// facts.849switch (Pred) {850default:851break;852case CmpInst::ICMP_ULT:853case CmpInst::ICMP_ULE:854// If B is a signed positive constant, then A >=s 0 and A <s (or <=s) B.855if (IsKnownNonNegative(B)) {856addFact(CmpInst::ICMP_SGE, A, ConstantInt::get(B->getType(), 0), NumIn,857NumOut, DFSInStack);858addFact(CmpInst::getSignedPredicate(Pred), A, B, NumIn, NumOut,859DFSInStack);860}861break;862case CmpInst::ICMP_UGE:863case CmpInst::ICMP_UGT:864// If A is a signed positive constant, then B >=s 0 and A >s (or >=s) B.865if (IsKnownNonNegative(A)) {866addFact(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0), NumIn,867NumOut, DFSInStack);868addFact(CmpInst::getSignedPredicate(Pred), A, B, NumIn, NumOut,869DFSInStack);870}871break;872case CmpInst::ICMP_SLT:873if (IsKnownNonNegative(A))874addFact(CmpInst::ICMP_ULT, A, B, NumIn, NumOut, DFSInStack);875break;876case CmpInst::ICMP_SGT: {877if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), -1)))878addFact(CmpInst::ICMP_UGE, A, ConstantInt::get(B->getType(), 0), NumIn,879NumOut, DFSInStack);880if (IsKnownNonNegative(B))881addFact(CmpInst::ICMP_UGT, A, B, NumIn, NumOut, DFSInStack);882883break;884}885case CmpInst::ICMP_SGE:886if (IsKnownNonNegative(B))887addFact(CmpInst::ICMP_UGE, A, B, NumIn, NumOut, DFSInStack);888break;889}890}891892#ifndef NDEBUG893894static void dumpConstraint(ArrayRef<int64_t> C,895const DenseMap<Value *, unsigned> &Value2Index) {896ConstraintSystem CS(Value2Index);897CS.addVariableRowFill(C);898CS.dump();899}900#endif901902void State::addInfoForInductions(BasicBlock &BB) {903auto *L = LI.getLoopFor(&BB);904if (!L || L->getHeader() != &BB)905return;906907Value *A;908Value *B;909CmpInst::Predicate Pred;910911if (!match(BB.getTerminator(),912m_Br(m_ICmp(Pred, m_Value(A), m_Value(B)), m_Value(), m_Value())))913return;914PHINode *PN = dyn_cast<PHINode>(A);915if (!PN) {916Pred = CmpInst::getSwappedPredicate(Pred);917std::swap(A, B);918PN = dyn_cast<PHINode>(A);919}920921if (!PN || PN->getParent() != &BB || PN->getNumIncomingValues() != 2 ||922!SE.isSCEVable(PN->getType()))923return;924925BasicBlock *InLoopSucc = nullptr;926if (Pred == CmpInst::ICMP_NE)927InLoopSucc = cast<BranchInst>(BB.getTerminator())->getSuccessor(0);928else if (Pred == CmpInst::ICMP_EQ)929InLoopSucc = cast<BranchInst>(BB.getTerminator())->getSuccessor(1);930else931return;932933if (!L->contains(InLoopSucc) || !L->isLoopExiting(&BB) || InLoopSucc == &BB)934return;935936auto *AR = dyn_cast_or_null<SCEVAddRecExpr>(SE.getSCEV(PN));937BasicBlock *LoopPred = L->getLoopPredecessor();938if (!AR || AR->getLoop() != L || !LoopPred)939return;940941const SCEV *StartSCEV = AR->getStart();942Value *StartValue = nullptr;943if (auto *C = dyn_cast<SCEVConstant>(StartSCEV)) {944StartValue = C->getValue();945} else {946StartValue = PN->getIncomingValueForBlock(LoopPred);947assert(SE.getSCEV(StartValue) == StartSCEV && "inconsistent start value");948}949950DomTreeNode *DTN = DT.getNode(InLoopSucc);951auto IncUnsigned = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_UGT);952auto IncSigned = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_SGT);953bool MonotonicallyIncreasingUnsigned =954IncUnsigned && *IncUnsigned == ScalarEvolution::MonotonicallyIncreasing;955bool MonotonicallyIncreasingSigned =956IncSigned && *IncSigned == ScalarEvolution::MonotonicallyIncreasing;957// If SCEV guarantees that AR does not wrap, PN >= StartValue can be added958// unconditionally.959if (MonotonicallyIncreasingUnsigned)960WorkList.push_back(961FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_UGE, PN, StartValue));962if (MonotonicallyIncreasingSigned)963WorkList.push_back(964FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SGE, PN, StartValue));965966APInt StepOffset;967if (auto *C = dyn_cast<SCEVConstant>(AR->getStepRecurrence(SE)))968StepOffset = C->getAPInt();969else970return;971972// Make sure the bound B is loop-invariant.973if (!L->isLoopInvariant(B))974return;975976// Handle negative steps.977if (StepOffset.isNegative()) {978// TODO: Extend to allow steps > -1.979if (!(-StepOffset).isOne())980return;981982// AR may wrap.983// Add StartValue >= PN conditional on B <= StartValue which guarantees that984// the loop exits before wrapping with a step of -1.985WorkList.push_back(FactOrCheck::getConditionFact(986DTN, CmpInst::ICMP_UGE, StartValue, PN,987ConditionTy(CmpInst::ICMP_ULE, B, StartValue)));988WorkList.push_back(FactOrCheck::getConditionFact(989DTN, CmpInst::ICMP_SGE, StartValue, PN,990ConditionTy(CmpInst::ICMP_SLE, B, StartValue)));991// Add PN > B conditional on B <= StartValue which guarantees that the loop992// exits when reaching B with a step of -1.993WorkList.push_back(FactOrCheck::getConditionFact(994DTN, CmpInst::ICMP_UGT, PN, B,995ConditionTy(CmpInst::ICMP_ULE, B, StartValue)));996WorkList.push_back(FactOrCheck::getConditionFact(997DTN, CmpInst::ICMP_SGT, PN, B,998ConditionTy(CmpInst::ICMP_SLE, B, StartValue)));999return;1000}10011002// Make sure AR either steps by 1 or that the value we compare against is a1003// GEP based on the same start value and all offsets are a multiple of the1004// step size, to guarantee that the induction will reach the value.1005if (StepOffset.isZero() || StepOffset.isNegative())1006return;10071008if (!StepOffset.isOne()) {1009// Check whether B-Start is known to be a multiple of StepOffset.1010const SCEV *BMinusStart = SE.getMinusSCEV(SE.getSCEV(B), StartSCEV);1011if (isa<SCEVCouldNotCompute>(BMinusStart) ||1012!SE.getConstantMultiple(BMinusStart).urem(StepOffset).isZero())1013return;1014}10151016// AR may wrap. Add PN >= StartValue conditional on StartValue <= B which1017// guarantees that the loop exits before wrapping in combination with the1018// restrictions on B and the step above.1019if (!MonotonicallyIncreasingUnsigned)1020WorkList.push_back(FactOrCheck::getConditionFact(1021DTN, CmpInst::ICMP_UGE, PN, StartValue,1022ConditionTy(CmpInst::ICMP_ULE, StartValue, B)));1023if (!MonotonicallyIncreasingSigned)1024WorkList.push_back(FactOrCheck::getConditionFact(1025DTN, CmpInst::ICMP_SGE, PN, StartValue,1026ConditionTy(CmpInst::ICMP_SLE, StartValue, B)));10271028WorkList.push_back(FactOrCheck::getConditionFact(1029DTN, CmpInst::ICMP_ULT, PN, B,1030ConditionTy(CmpInst::ICMP_ULE, StartValue, B)));1031WorkList.push_back(FactOrCheck::getConditionFact(1032DTN, CmpInst::ICMP_SLT, PN, B,1033ConditionTy(CmpInst::ICMP_SLE, StartValue, B)));10341035// Try to add condition from header to the dedicated exit blocks. When exiting1036// either with EQ or NE in the header, we know that the induction value must1037// be u<= B, as other exits may only exit earlier.1038assert(!StepOffset.isNegative() && "induction must be increasing");1039assert((Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE) &&1040"unsupported predicate");1041ConditionTy Precond = {CmpInst::ICMP_ULE, StartValue, B};1042SmallVector<BasicBlock *> ExitBBs;1043L->getExitBlocks(ExitBBs);1044for (BasicBlock *EB : ExitBBs) {1045// Bail out on non-dedicated exits.1046if (DT.dominates(&BB, EB)) {1047WorkList.emplace_back(FactOrCheck::getConditionFact(1048DT.getNode(EB), CmpInst::ICMP_ULE, A, B, Precond));1049}1050}1051}10521053void State::addInfoFor(BasicBlock &BB) {1054addInfoForInductions(BB);10551056// True as long as long as the current instruction is guaranteed to execute.1057bool GuaranteedToExecute = true;1058// Queue conditions and assumes.1059for (Instruction &I : BB) {1060if (auto Cmp = dyn_cast<ICmpInst>(&I)) {1061for (Use &U : Cmp->uses()) {1062auto *UserI = getContextInstForUse(U);1063auto *DTN = DT.getNode(UserI->getParent());1064if (!DTN)1065continue;1066WorkList.push_back(FactOrCheck::getCheck(DTN, &U));1067}1068continue;1069}10701071auto *II = dyn_cast<IntrinsicInst>(&I);1072Intrinsic::ID ID = II ? II->getIntrinsicID() : Intrinsic::not_intrinsic;1073switch (ID) {1074case Intrinsic::assume: {1075Value *A, *B;1076CmpInst::Predicate Pred;1077if (!match(I.getOperand(0), m_ICmp(Pred, m_Value(A), m_Value(B))))1078break;1079if (GuaranteedToExecute) {1080// The assume is guaranteed to execute when BB is entered, hence Cond1081// holds on entry to BB.1082WorkList.emplace_back(FactOrCheck::getConditionFact(1083DT.getNode(I.getParent()), Pred, A, B));1084} else {1085WorkList.emplace_back(1086FactOrCheck::getInstFact(DT.getNode(I.getParent()), &I));1087}1088break;1089}1090// Enqueue ssub_with_overflow for simplification.1091case Intrinsic::ssub_with_overflow:1092case Intrinsic::ucmp:1093case Intrinsic::scmp:1094WorkList.push_back(1095FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));1096break;1097// Enqueue the intrinsics to add extra info.1098case Intrinsic::umin:1099case Intrinsic::umax:1100case Intrinsic::smin:1101case Intrinsic::smax:1102// TODO: handle llvm.abs as well1103WorkList.push_back(1104FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));1105// TODO: Check if it is possible to instead only added the min/max facts1106// when simplifying uses of the min/max intrinsics.1107if (!isGuaranteedNotToBePoison(&I))1108break;1109[[fallthrough]];1110case Intrinsic::abs:1111WorkList.push_back(FactOrCheck::getInstFact(DT.getNode(&BB), &I));1112break;1113}11141115GuaranteedToExecute &= isGuaranteedToTransferExecutionToSuccessor(&I);1116}11171118if (auto *Switch = dyn_cast<SwitchInst>(BB.getTerminator())) {1119for (auto &Case : Switch->cases()) {1120BasicBlock *Succ = Case.getCaseSuccessor();1121Value *V = Case.getCaseValue();1122if (!canAddSuccessor(BB, Succ))1123continue;1124WorkList.emplace_back(FactOrCheck::getConditionFact(1125DT.getNode(Succ), CmpInst::ICMP_EQ, Switch->getCondition(), V));1126}1127return;1128}11291130auto *Br = dyn_cast<BranchInst>(BB.getTerminator());1131if (!Br || !Br->isConditional())1132return;11331134Value *Cond = Br->getCondition();11351136// If the condition is a chain of ORs/AND and the successor only has the1137// current block as predecessor, queue conditions for the successor.1138Value *Op0, *Op1;1139if (match(Cond, m_LogicalOr(m_Value(Op0), m_Value(Op1))) ||1140match(Cond, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {1141bool IsOr = match(Cond, m_LogicalOr());1142bool IsAnd = match(Cond, m_LogicalAnd());1143// If there's a select that matches both AND and OR, we need to commit to1144// one of the options. Arbitrarily pick OR.1145if (IsOr && IsAnd)1146IsAnd = false;11471148BasicBlock *Successor = Br->getSuccessor(IsOr ? 1 : 0);1149if (canAddSuccessor(BB, Successor)) {1150SmallVector<Value *> CondWorkList;1151SmallPtrSet<Value *, 8> SeenCond;1152auto QueueValue = [&CondWorkList, &SeenCond](Value *V) {1153if (SeenCond.insert(V).second)1154CondWorkList.push_back(V);1155};1156QueueValue(Op1);1157QueueValue(Op0);1158while (!CondWorkList.empty()) {1159Value *Cur = CondWorkList.pop_back_val();1160if (auto *Cmp = dyn_cast<ICmpInst>(Cur)) {1161WorkList.emplace_back(FactOrCheck::getConditionFact(1162DT.getNode(Successor),1163IsOr ? CmpInst::getInversePredicate(Cmp->getPredicate())1164: Cmp->getPredicate(),1165Cmp->getOperand(0), Cmp->getOperand(1)));1166continue;1167}1168if (IsOr && match(Cur, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) {1169QueueValue(Op1);1170QueueValue(Op0);1171continue;1172}1173if (IsAnd && match(Cur, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {1174QueueValue(Op1);1175QueueValue(Op0);1176continue;1177}1178}1179}1180return;1181}11821183auto *CmpI = dyn_cast<ICmpInst>(Br->getCondition());1184if (!CmpI)1185return;1186if (canAddSuccessor(BB, Br->getSuccessor(0)))1187WorkList.emplace_back(FactOrCheck::getConditionFact(1188DT.getNode(Br->getSuccessor(0)), CmpI->getPredicate(),1189CmpI->getOperand(0), CmpI->getOperand(1)));1190if (canAddSuccessor(BB, Br->getSuccessor(1)))1191WorkList.emplace_back(FactOrCheck::getConditionFact(1192DT.getNode(Br->getSuccessor(1)),1193CmpInst::getInversePredicate(CmpI->getPredicate()), CmpI->getOperand(0),1194CmpI->getOperand(1)));1195}11961197#ifndef NDEBUG1198static void dumpUnpackedICmp(raw_ostream &OS, ICmpInst::Predicate Pred,1199Value *LHS, Value *RHS) {1200OS << "icmp " << Pred << ' ';1201LHS->printAsOperand(OS, /*PrintType=*/true);1202OS << ", ";1203RHS->printAsOperand(OS, /*PrintType=*/false);1204}1205#endif12061207namespace {1208/// Helper to keep track of a condition and if it should be treated as negated1209/// for reproducer construction.1210/// Pred == Predicate::BAD_ICMP_PREDICATE indicates that this entry is a1211/// placeholder to keep the ReproducerCondStack in sync with DFSInStack.1212struct ReproducerEntry {1213ICmpInst::Predicate Pred;1214Value *LHS;1215Value *RHS;12161217ReproducerEntry(ICmpInst::Predicate Pred, Value *LHS, Value *RHS)1218: Pred(Pred), LHS(LHS), RHS(RHS) {}1219};1220} // namespace12211222/// Helper function to generate a reproducer function for simplifying \p Cond.1223/// The reproducer function contains a series of @llvm.assume calls, one for1224/// each condition in \p Stack. For each condition, the operand instruction are1225/// cloned until we reach operands that have an entry in \p Value2Index. Those1226/// will then be added as function arguments. \p DT is used to order cloned1227/// instructions. The reproducer function will get added to \p M, if it is1228/// non-null. Otherwise no reproducer function is generated.1229static void generateReproducer(CmpInst *Cond, Module *M,1230ArrayRef<ReproducerEntry> Stack,1231ConstraintInfo &Info, DominatorTree &DT) {1232if (!M)1233return;12341235LLVMContext &Ctx = Cond->getContext();12361237LLVM_DEBUG(dbgs() << "Creating reproducer for " << *Cond << "\n");12381239ValueToValueMapTy Old2New;1240SmallVector<Value *> Args;1241SmallPtrSet<Value *, 8> Seen;1242// Traverse Cond and its operands recursively until we reach a value that's in1243// Value2Index or not an instruction, or not a operation that1244// ConstraintElimination can decompose. Such values will be considered as1245// external inputs to the reproducer, they are collected and added as function1246// arguments later.1247auto CollectArguments = [&](ArrayRef<Value *> Ops, bool IsSigned) {1248auto &Value2Index = Info.getValue2Index(IsSigned);1249SmallVector<Value *, 4> WorkList(Ops);1250while (!WorkList.empty()) {1251Value *V = WorkList.pop_back_val();1252if (!Seen.insert(V).second)1253continue;1254if (Old2New.find(V) != Old2New.end())1255continue;1256if (isa<Constant>(V))1257continue;12581259auto *I = dyn_cast<Instruction>(V);1260if (Value2Index.contains(V) || !I ||1261!isa<CmpInst, BinaryOperator, GEPOperator, CastInst>(V)) {1262Old2New[V] = V;1263Args.push_back(V);1264LLVM_DEBUG(dbgs() << " found external input " << *V << "\n");1265} else {1266append_range(WorkList, I->operands());1267}1268}1269};12701271for (auto &Entry : Stack)1272if (Entry.Pred != ICmpInst::BAD_ICMP_PREDICATE)1273CollectArguments({Entry.LHS, Entry.RHS}, ICmpInst::isSigned(Entry.Pred));1274CollectArguments(Cond, ICmpInst::isSigned(Cond->getPredicate()));12751276SmallVector<Type *> ParamTys;1277for (auto *P : Args)1278ParamTys.push_back(P->getType());12791280FunctionType *FTy = FunctionType::get(Cond->getType(), ParamTys,1281/*isVarArg=*/false);1282Function *F = Function::Create(FTy, Function::ExternalLinkage,1283Cond->getModule()->getName() +1284Cond->getFunction()->getName() + "repro",1285M);1286// Add arguments to the reproducer function for each external value collected.1287for (unsigned I = 0; I < Args.size(); ++I) {1288F->getArg(I)->setName(Args[I]->getName());1289Old2New[Args[I]] = F->getArg(I);1290}12911292BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F);1293IRBuilder<> Builder(Entry);1294Builder.CreateRet(Builder.getTrue());1295Builder.SetInsertPoint(Entry->getTerminator());12961297// Clone instructions in \p Ops and their operands recursively until reaching1298// an value in Value2Index (external input to the reproducer). Update Old2New1299// mapping for the original and cloned instructions. Sort instructions to1300// clone by dominance, then insert the cloned instructions in the function.1301auto CloneInstructions = [&](ArrayRef<Value *> Ops, bool IsSigned) {1302SmallVector<Value *, 4> WorkList(Ops);1303SmallVector<Instruction *> ToClone;1304auto &Value2Index = Info.getValue2Index(IsSigned);1305while (!WorkList.empty()) {1306Value *V = WorkList.pop_back_val();1307if (Old2New.find(V) != Old2New.end())1308continue;13091310auto *I = dyn_cast<Instruction>(V);1311if (!Value2Index.contains(V) && I) {1312Old2New[V] = nullptr;1313ToClone.push_back(I);1314append_range(WorkList, I->operands());1315}1316}13171318sort(ToClone,1319[&DT](Instruction *A, Instruction *B) { return DT.dominates(A, B); });1320for (Instruction *I : ToClone) {1321Instruction *Cloned = I->clone();1322Old2New[I] = Cloned;1323Old2New[I]->setName(I->getName());1324Cloned->insertBefore(&*Builder.GetInsertPoint());1325Cloned->dropUnknownNonDebugMetadata();1326Cloned->setDebugLoc({});1327}1328};13291330// Materialize the assumptions for the reproducer using the entries in Stack.1331// That is, first clone the operands of the condition recursively until we1332// reach an external input to the reproducer and add them to the reproducer1333// function. Then add an ICmp for the condition (with the inverse predicate if1334// the entry is negated) and an assert using the ICmp.1335for (auto &Entry : Stack) {1336if (Entry.Pred == ICmpInst::BAD_ICMP_PREDICATE)1337continue;13381339LLVM_DEBUG(dbgs() << " Materializing assumption ";1340dumpUnpackedICmp(dbgs(), Entry.Pred, Entry.LHS, Entry.RHS);1341dbgs() << "\n");1342CloneInstructions({Entry.LHS, Entry.RHS}, CmpInst::isSigned(Entry.Pred));13431344auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS);1345Builder.CreateAssumption(Cmp);1346}13471348// Finally, clone the condition to reproduce and remap instruction operands in1349// the reproducer using Old2New.1350CloneInstructions(Cond, CmpInst::isSigned(Cond->getPredicate()));1351Entry->getTerminator()->setOperand(0, Cond);1352remapInstructionsInBlocks({Entry}, Old2New);13531354assert(!verifyFunction(*F, &dbgs()));1355}13561357static std::optional<bool> checkCondition(CmpInst::Predicate Pred, Value *A,1358Value *B, Instruction *CheckInst,1359ConstraintInfo &Info) {1360LLVM_DEBUG(dbgs() << "Checking " << *CheckInst << "\n");13611362auto R = Info.getConstraintForSolving(Pred, A, B);1363if (R.empty() || !R.isValid(Info)){1364LLVM_DEBUG(dbgs() << " failed to decompose condition\n");1365return std::nullopt;1366}13671368auto &CSToUse = Info.getCS(R.IsSigned);13691370// If there was extra information collected during decomposition, apply1371// it now and remove it immediately once we are done with reasoning1372// about the constraint.1373for (auto &Row : R.ExtraInfo)1374CSToUse.addVariableRow(Row);1375auto InfoRestorer = make_scope_exit([&]() {1376for (unsigned I = 0; I < R.ExtraInfo.size(); ++I)1377CSToUse.popLastConstraint();1378});13791380if (auto ImpliedCondition = R.isImpliedBy(CSToUse)) {1381if (!DebugCounter::shouldExecute(EliminatedCounter))1382return std::nullopt;13831384LLVM_DEBUG({1385dbgs() << "Condition ";1386dumpUnpackedICmp(1387dbgs(), *ImpliedCondition ? Pred : CmpInst::getInversePredicate(Pred),1388A, B);1389dbgs() << " implied by dominating constraints\n";1390CSToUse.dump();1391});1392return ImpliedCondition;1393}13941395return std::nullopt;1396}13971398static bool checkAndReplaceCondition(1399CmpInst *Cmp, ConstraintInfo &Info, unsigned NumIn, unsigned NumOut,1400Instruction *ContextInst, Module *ReproducerModule,1401ArrayRef<ReproducerEntry> ReproducerCondStack, DominatorTree &DT,1402SmallVectorImpl<Instruction *> &ToRemove) {1403auto ReplaceCmpWithConstant = [&](CmpInst *Cmp, bool IsTrue) {1404generateReproducer(Cmp, ReproducerModule, ReproducerCondStack, Info, DT);1405Constant *ConstantC = ConstantInt::getBool(1406CmpInst::makeCmpResultType(Cmp->getType()), IsTrue);1407Cmp->replaceUsesWithIf(ConstantC, [&DT, NumIn, NumOut,1408ContextInst](Use &U) {1409auto *UserI = getContextInstForUse(U);1410auto *DTN = DT.getNode(UserI->getParent());1411if (!DTN || DTN->getDFSNumIn() < NumIn || DTN->getDFSNumOut() > NumOut)1412return false;1413if (UserI->getParent() == ContextInst->getParent() &&1414UserI->comesBefore(ContextInst))1415return false;14161417// Conditions in an assume trivially simplify to true. Skip uses1418// in assume calls to not destroy the available information.1419auto *II = dyn_cast<IntrinsicInst>(U.getUser());1420return !II || II->getIntrinsicID() != Intrinsic::assume;1421});1422NumCondsRemoved++;1423if (Cmp->use_empty())1424ToRemove.push_back(Cmp);1425return true;1426};14271428if (auto ImpliedCondition =1429checkCondition(Cmp->getPredicate(), Cmp->getOperand(0),1430Cmp->getOperand(1), Cmp, Info))1431return ReplaceCmpWithConstant(Cmp, *ImpliedCondition);1432return false;1433}14341435static bool checkAndReplaceMinMax(MinMaxIntrinsic *MinMax, ConstraintInfo &Info,1436SmallVectorImpl<Instruction *> &ToRemove) {1437auto ReplaceMinMaxWithOperand = [&](MinMaxIntrinsic *MinMax, bool UseLHS) {1438// TODO: generate reproducer for min/max.1439MinMax->replaceAllUsesWith(MinMax->getOperand(UseLHS ? 0 : 1));1440ToRemove.push_back(MinMax);1441return true;1442};14431444ICmpInst::Predicate Pred =1445ICmpInst::getNonStrictPredicate(MinMax->getPredicate());1446if (auto ImpliedCondition = checkCondition(1447Pred, MinMax->getOperand(0), MinMax->getOperand(1), MinMax, Info))1448return ReplaceMinMaxWithOperand(MinMax, *ImpliedCondition);1449if (auto ImpliedCondition = checkCondition(1450Pred, MinMax->getOperand(1), MinMax->getOperand(0), MinMax, Info))1451return ReplaceMinMaxWithOperand(MinMax, !*ImpliedCondition);1452return false;1453}14541455static bool checkAndReplaceCmp(CmpIntrinsic *I, ConstraintInfo &Info,1456SmallVectorImpl<Instruction *> &ToRemove) {1457Value *LHS = I->getOperand(0);1458Value *RHS = I->getOperand(1);1459if (checkCondition(I->getGTPredicate(), LHS, RHS, I, Info).value_or(false)) {1460I->replaceAllUsesWith(ConstantInt::get(I->getType(), 1));1461ToRemove.push_back(I);1462return true;1463}1464if (checkCondition(I->getLTPredicate(), LHS, RHS, I, Info).value_or(false)) {1465I->replaceAllUsesWith(ConstantInt::getSigned(I->getType(), -1));1466ToRemove.push_back(I);1467return true;1468}1469if (checkCondition(ICmpInst::ICMP_EQ, LHS, RHS, I, Info).value_or(false)) {1470I->replaceAllUsesWith(ConstantInt::get(I->getType(), 0));1471ToRemove.push_back(I);1472return true;1473}1474return false;1475}14761477static void1478removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info,1479Module *ReproducerModule,1480SmallVectorImpl<ReproducerEntry> &ReproducerCondStack,1481SmallVectorImpl<StackEntry> &DFSInStack) {1482Info.popLastConstraint(E.IsSigned);1483// Remove variables in the system that went out of scope.1484auto &Mapping = Info.getValue2Index(E.IsSigned);1485for (Value *V : E.ValuesToRelease)1486Mapping.erase(V);1487Info.popLastNVariables(E.IsSigned, E.ValuesToRelease.size());1488DFSInStack.pop_back();1489if (ReproducerModule)1490ReproducerCondStack.pop_back();1491}14921493/// Check if either the first condition of an AND or OR is implied by the1494/// (negated in case of OR) second condition or vice versa.1495static bool checkOrAndOpImpliedByOther(1496FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule,1497SmallVectorImpl<ReproducerEntry> &ReproducerCondStack,1498SmallVectorImpl<StackEntry> &DFSInStack) {14991500CmpInst::Predicate Pred;1501Value *A, *B;1502Instruction *JoinOp = CB.getContextInst();1503CmpInst *CmpToCheck = cast<CmpInst>(CB.getInstructionToSimplify());1504unsigned OtherOpIdx = JoinOp->getOperand(0) == CmpToCheck ? 1 : 0;15051506// Don't try to simplify the first condition of a select by the second, as1507// this may make the select more poisonous than the original one.1508// TODO: check if the first operand may be poison.1509if (OtherOpIdx != 0 && isa<SelectInst>(JoinOp))1510return false;15111512if (!match(JoinOp->getOperand(OtherOpIdx),1513m_ICmp(Pred, m_Value(A), m_Value(B))))1514return false;15151516// For OR, check if the negated condition implies CmpToCheck.1517bool IsOr = match(JoinOp, m_LogicalOr());1518if (IsOr)1519Pred = CmpInst::getInversePredicate(Pred);15201521// Optimistically add fact from first condition.1522unsigned OldSize = DFSInStack.size();1523Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);1524if (OldSize == DFSInStack.size())1525return false;15261527bool Changed = false;1528// Check if the second condition can be simplified now.1529if (auto ImpliedCondition =1530checkCondition(CmpToCheck->getPredicate(), CmpToCheck->getOperand(0),1531CmpToCheck->getOperand(1), CmpToCheck, Info)) {1532if (IsOr && isa<SelectInst>(JoinOp)) {1533JoinOp->setOperand(1534OtherOpIdx == 0 ? 2 : 0,1535ConstantInt::getBool(JoinOp->getType(), *ImpliedCondition));1536} else1537JoinOp->setOperand(15381 - OtherOpIdx,1539ConstantInt::getBool(JoinOp->getType(), *ImpliedCondition));15401541Changed = true;1542}15431544// Remove entries again.1545while (OldSize < DFSInStack.size()) {1546StackEntry E = DFSInStack.back();1547removeEntryFromStack(E, Info, ReproducerModule, ReproducerCondStack,1548DFSInStack);1549}1550return Changed;1551}15521553void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B,1554unsigned NumIn, unsigned NumOut,1555SmallVectorImpl<StackEntry> &DFSInStack) {1556// If the constraint has a pre-condition, skip the constraint if it does not1557// hold.1558SmallVector<Value *> NewVariables;1559auto R = getConstraint(Pred, A, B, NewVariables);15601561// TODO: Support non-equality for facts as well.1562if (!R.isValid(*this) || R.isNe())1563return;15641565LLVM_DEBUG(dbgs() << "Adding '"; dumpUnpackedICmp(dbgs(), Pred, A, B);1566dbgs() << "'\n");1567bool Added = false;1568auto &CSToUse = getCS(R.IsSigned);1569if (R.Coefficients.empty())1570return;15711572Added |= CSToUse.addVariableRowFill(R.Coefficients);15731574// If R has been added to the system, add the new variables and queue it for1575// removal once it goes out-of-scope.1576if (Added) {1577SmallVector<Value *, 2> ValuesToRelease;1578auto &Value2Index = getValue2Index(R.IsSigned);1579for (Value *V : NewVariables) {1580Value2Index.insert({V, Value2Index.size() + 1});1581ValuesToRelease.push_back(V);1582}15831584LLVM_DEBUG({1585dbgs() << " constraint: ";1586dumpConstraint(R.Coefficients, getValue2Index(R.IsSigned));1587dbgs() << "\n";1588});15891590DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,1591std::move(ValuesToRelease));15921593if (!R.IsSigned) {1594for (Value *V : NewVariables) {1595ConstraintTy VarPos(SmallVector<int64_t, 8>(Value2Index.size() + 1, 0),1596false, false, false);1597VarPos.Coefficients[Value2Index[V]] = -1;1598CSToUse.addVariableRow(VarPos.Coefficients);1599DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,1600SmallVector<Value *, 2>());1601}1602}16031604if (R.isEq()) {1605// Also add the inverted constraint for equality constraints.1606for (auto &Coeff : R.Coefficients)1607Coeff *= -1;1608CSToUse.addVariableRowFill(R.Coefficients);16091610DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,1611SmallVector<Value *, 2>());1612}1613}1614}16151616static bool replaceSubOverflowUses(IntrinsicInst *II, Value *A, Value *B,1617SmallVectorImpl<Instruction *> &ToRemove) {1618bool Changed = false;1619IRBuilder<> Builder(II->getParent(), II->getIterator());1620Value *Sub = nullptr;1621for (User *U : make_early_inc_range(II->users())) {1622if (match(U, m_ExtractValue<0>(m_Value()))) {1623if (!Sub)1624Sub = Builder.CreateSub(A, B);1625U->replaceAllUsesWith(Sub);1626Changed = true;1627} else if (match(U, m_ExtractValue<1>(m_Value()))) {1628U->replaceAllUsesWith(Builder.getFalse());1629Changed = true;1630} else1631continue;16321633if (U->use_empty()) {1634auto *I = cast<Instruction>(U);1635ToRemove.push_back(I);1636I->setOperand(0, PoisonValue::get(II->getType()));1637Changed = true;1638}1639}16401641if (II->use_empty()) {1642II->eraseFromParent();1643Changed = true;1644}1645return Changed;1646}16471648static bool1649tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,1650SmallVectorImpl<Instruction *> &ToRemove) {1651auto DoesConditionHold = [](CmpInst::Predicate Pred, Value *A, Value *B,1652ConstraintInfo &Info) {1653auto R = Info.getConstraintForSolving(Pred, A, B);1654if (R.size() < 2 || !R.isValid(Info))1655return false;16561657auto &CSToUse = Info.getCS(R.IsSigned);1658return CSToUse.isConditionImplied(R.Coefficients);1659};16601661bool Changed = false;1662if (II->getIntrinsicID() == Intrinsic::ssub_with_overflow) {1663// If A s>= B && B s>= 0, ssub.with.overflow(a, b) should not overflow and1664// can be simplified to a regular sub.1665Value *A = II->getArgOperand(0);1666Value *B = II->getArgOperand(1);1667if (!DoesConditionHold(CmpInst::ICMP_SGE, A, B, Info) ||1668!DoesConditionHold(CmpInst::ICMP_SGE, B,1669ConstantInt::get(A->getType(), 0), Info))1670return false;1671Changed = replaceSubOverflowUses(II, A, B, ToRemove);1672}1673return Changed;1674}16751676static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,1677ScalarEvolution &SE,1678OptimizationRemarkEmitter &ORE) {1679bool Changed = false;1680DT.updateDFSNumbers();1681SmallVector<Value *> FunctionArgs;1682for (Value &Arg : F.args())1683FunctionArgs.push_back(&Arg);1684ConstraintInfo Info(F.getDataLayout(), FunctionArgs);1685State S(DT, LI, SE);1686std::unique_ptr<Module> ReproducerModule(1687DumpReproducers ? new Module(F.getName(), F.getContext()) : nullptr);16881689// First, collect conditions implied by branches and blocks with their1690// Dominator DFS in and out numbers.1691for (BasicBlock &BB : F) {1692if (!DT.getNode(&BB))1693continue;1694S.addInfoFor(BB);1695}16961697// Next, sort worklist by dominance, so that dominating conditions to check1698// and facts come before conditions and facts dominated by them. If a1699// condition to check and a fact have the same numbers, conditional facts come1700// first. Assume facts and checks are ordered according to their relative1701// order in the containing basic block. Also make sure conditions with1702// constant operands come before conditions without constant operands. This1703// increases the effectiveness of the current signed <-> unsigned fact1704// transfer logic.1705stable_sort(S.WorkList, [](const FactOrCheck &A, const FactOrCheck &B) {1706auto HasNoConstOp = [](const FactOrCheck &B) {1707Value *V0 = B.isConditionFact() ? B.Cond.Op0 : B.Inst->getOperand(0);1708Value *V1 = B.isConditionFact() ? B.Cond.Op1 : B.Inst->getOperand(1);1709return !isa<ConstantInt>(V0) && !isa<ConstantInt>(V1);1710};1711// If both entries have the same In numbers, conditional facts come first.1712// Otherwise use the relative order in the basic block.1713if (A.NumIn == B.NumIn) {1714if (A.isConditionFact() && B.isConditionFact()) {1715bool NoConstOpA = HasNoConstOp(A);1716bool NoConstOpB = HasNoConstOp(B);1717return NoConstOpA < NoConstOpB;1718}1719if (A.isConditionFact())1720return true;1721if (B.isConditionFact())1722return false;1723auto *InstA = A.getContextInst();1724auto *InstB = B.getContextInst();1725return InstA->comesBefore(InstB);1726}1727return A.NumIn < B.NumIn;1728});17291730SmallVector<Instruction *> ToRemove;17311732// Finally, process ordered worklist and eliminate implied conditions.1733SmallVector<StackEntry, 16> DFSInStack;1734SmallVector<ReproducerEntry> ReproducerCondStack;1735for (FactOrCheck &CB : S.WorkList) {1736// First, pop entries from the stack that are out-of-scope for CB. Remove1737// the corresponding entry from the constraint system.1738while (!DFSInStack.empty()) {1739auto &E = DFSInStack.back();1740LLVM_DEBUG(dbgs() << "Top of stack : " << E.NumIn << " " << E.NumOut1741<< "\n");1742LLVM_DEBUG(dbgs() << "CB: " << CB.NumIn << " " << CB.NumOut << "\n");1743assert(E.NumIn <= CB.NumIn);1744if (CB.NumOut <= E.NumOut)1745break;1746LLVM_DEBUG({1747dbgs() << "Removing ";1748dumpConstraint(Info.getCS(E.IsSigned).getLastConstraint(),1749Info.getValue2Index(E.IsSigned));1750dbgs() << "\n";1751});1752removeEntryFromStack(E, Info, ReproducerModule.get(), ReproducerCondStack,1753DFSInStack);1754}17551756// For a block, check if any CmpInsts become known based on the current set1757// of constraints.1758if (CB.isCheck()) {1759Instruction *Inst = CB.getInstructionToSimplify();1760if (!Inst)1761continue;1762LLVM_DEBUG(dbgs() << "Processing condition to simplify: " << *Inst1763<< "\n");1764if (auto *II = dyn_cast<WithOverflowInst>(Inst)) {1765Changed |= tryToSimplifyOverflowMath(II, Info, ToRemove);1766} else if (auto *Cmp = dyn_cast<ICmpInst>(Inst)) {1767bool Simplified = checkAndReplaceCondition(1768Cmp, Info, CB.NumIn, CB.NumOut, CB.getContextInst(),1769ReproducerModule.get(), ReproducerCondStack, S.DT, ToRemove);1770if (!Simplified &&1771match(CB.getContextInst(), m_LogicalOp(m_Value(), m_Value()))) {1772Simplified =1773checkOrAndOpImpliedByOther(CB, Info, ReproducerModule.get(),1774ReproducerCondStack, DFSInStack);1775}1776Changed |= Simplified;1777} else if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(Inst)) {1778Changed |= checkAndReplaceMinMax(MinMax, Info, ToRemove);1779} else if (auto *CmpIntr = dyn_cast<CmpIntrinsic>(Inst)) {1780Changed |= checkAndReplaceCmp(CmpIntr, Info, ToRemove);1781}1782continue;1783}17841785auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) {1786LLVM_DEBUG(dbgs() << "Processing fact to add to the system: ";1787dumpUnpackedICmp(dbgs(), Pred, A, B); dbgs() << "\n");1788if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) {1789LLVM_DEBUG(1790dbgs()1791<< "Skip adding constraint because system has too many rows.\n");1792return;1793}17941795Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);1796if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size())1797ReproducerCondStack.emplace_back(Pred, A, B);17981799Info.transferToOtherSystem(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);1800if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) {1801// Add dummy entries to ReproducerCondStack to keep it in sync with1802// DFSInStack.1803for (unsigned I = 0,1804E = (DFSInStack.size() - ReproducerCondStack.size());1805I < E; ++I) {1806ReproducerCondStack.emplace_back(ICmpInst::BAD_ICMP_PREDICATE,1807nullptr, nullptr);1808}1809}1810};18111812ICmpInst::Predicate Pred;1813if (!CB.isConditionFact()) {1814Value *X;1815if (match(CB.Inst, m_Intrinsic<Intrinsic::abs>(m_Value(X)))) {1816// If is_int_min_poison is true then we may assume llvm.abs >= 0.1817if (cast<ConstantInt>(CB.Inst->getOperand(1))->isOne())1818AddFact(CmpInst::ICMP_SGE, CB.Inst,1819ConstantInt::get(CB.Inst->getType(), 0));1820AddFact(CmpInst::ICMP_SGE, CB.Inst, X);1821continue;1822}18231824if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {1825Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());1826AddFact(Pred, MinMax, MinMax->getLHS());1827AddFact(Pred, MinMax, MinMax->getRHS());1828continue;1829}1830}18311832Value *A = nullptr, *B = nullptr;1833if (CB.isConditionFact()) {1834Pred = CB.Cond.Pred;1835A = CB.Cond.Op0;1836B = CB.Cond.Op1;1837if (CB.DoesHold.Pred != CmpInst::BAD_ICMP_PREDICATE &&1838!Info.doesHold(CB.DoesHold.Pred, CB.DoesHold.Op0, CB.DoesHold.Op1)) {1839LLVM_DEBUG({1840dbgs() << "Not adding fact ";1841dumpUnpackedICmp(dbgs(), Pred, A, B);1842dbgs() << " because precondition ";1843dumpUnpackedICmp(dbgs(), CB.DoesHold.Pred, CB.DoesHold.Op0,1844CB.DoesHold.Op1);1845dbgs() << " does not hold.\n";1846});1847continue;1848}1849} else {1850bool Matched = match(CB.Inst, m_Intrinsic<Intrinsic::assume>(1851m_ICmp(Pred, m_Value(A), m_Value(B))));1852(void)Matched;1853assert(Matched && "Must have an assume intrinsic with a icmp operand");1854}1855AddFact(Pred, A, B);1856}18571858if (ReproducerModule && !ReproducerModule->functions().empty()) {1859std::string S;1860raw_string_ostream StringS(S);1861ReproducerModule->print(StringS, nullptr);1862StringS.flush();1863OptimizationRemark Rem(DEBUG_TYPE, "Reproducer", &F);1864Rem << ore::NV("module") << S;1865ORE.emit(Rem);1866}18671868#ifndef NDEBUG1869unsigned SignedEntries =1870count_if(DFSInStack, [](const StackEntry &E) { return E.IsSigned; });1871assert(Info.getCS(false).size() - FunctionArgs.size() ==1872DFSInStack.size() - SignedEntries &&1873"updates to CS and DFSInStack are out of sync");1874assert(Info.getCS(true).size() == SignedEntries &&1875"updates to CS and DFSInStack are out of sync");1876#endif18771878for (Instruction *I : ToRemove)1879I->eraseFromParent();1880return Changed;1881}18821883PreservedAnalyses ConstraintEliminationPass::run(Function &F,1884FunctionAnalysisManager &AM) {1885auto &DT = AM.getResult<DominatorTreeAnalysis>(F);1886auto &LI = AM.getResult<LoopAnalysis>(F);1887auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);1888auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);1889if (!eliminateConstraints(F, DT, LI, SE, ORE))1890return PreservedAnalyses::all();18911892PreservedAnalyses PA;1893PA.preserve<DominatorTreeAnalysis>();1894PA.preserve<LoopAnalysis>();1895PA.preserve<ScalarEvolutionAnalysis>();1896PA.preserveSet<CFGAnalyses>();1897return PA;1898}189919001901