diff options
Diffstat (limited to 'llvm/lib/Analysis')
-rw-r--r-- | llvm/lib/Analysis/ConstantFolding.cpp | 139 | ||||
-rw-r--r-- | llvm/lib/Analysis/InstructionSimplify.cpp | 116 | ||||
-rw-r--r-- | llvm/lib/Analysis/Lint.cpp | 24 | ||||
-rw-r--r-- | llvm/lib/Analysis/Loads.cpp | 11 | ||||
-rw-r--r-- | llvm/lib/Analysis/MemoryProfileInfo.cpp | 17 | ||||
-rw-r--r-- | llvm/lib/Analysis/ScalarEvolution.cpp | 3 | ||||
-rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 77 |
7 files changed, 328 insertions, 59 deletions
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 88533f2..031d675 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -45,8 +45,10 @@ #include "llvm/IR/IntrinsicsAArch64.h" #include "llvm/IR/IntrinsicsAMDGPU.h" #include "llvm/IR/IntrinsicsARM.h" +#include "llvm/IR/IntrinsicsNVPTX.h" #include "llvm/IR/IntrinsicsWebAssembly.h" #include "llvm/IR/IntrinsicsX86.h" +#include "llvm/IR/NVVMIntrinsicUtils.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" @@ -1687,6 +1689,58 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) { case Intrinsic::x86_avx512_cvttsd2usi64: return !Call->isStrictFP(); + // NVVM float/double to int32/uint32 conversion intrinsics + case Intrinsic::nvvm_f2i_rm: + case Intrinsic::nvvm_f2i_rn: + case Intrinsic::nvvm_f2i_rp: + case Intrinsic::nvvm_f2i_rz: + case Intrinsic::nvvm_f2i_rm_ftz: + case Intrinsic::nvvm_f2i_rn_ftz: + case Intrinsic::nvvm_f2i_rp_ftz: + case Intrinsic::nvvm_f2i_rz_ftz: + case Intrinsic::nvvm_f2ui_rm: + case Intrinsic::nvvm_f2ui_rn: + case Intrinsic::nvvm_f2ui_rp: + case Intrinsic::nvvm_f2ui_rz: + case Intrinsic::nvvm_f2ui_rm_ftz: + case Intrinsic::nvvm_f2ui_rn_ftz: + case Intrinsic::nvvm_f2ui_rp_ftz: + case Intrinsic::nvvm_f2ui_rz_ftz: + case Intrinsic::nvvm_d2i_rm: + case Intrinsic::nvvm_d2i_rn: + case Intrinsic::nvvm_d2i_rp: + case Intrinsic::nvvm_d2i_rz: + case Intrinsic::nvvm_d2ui_rm: + case Intrinsic::nvvm_d2ui_rn: + case Intrinsic::nvvm_d2ui_rp: + case Intrinsic::nvvm_d2ui_rz: + + // NVVM float/double to int64/uint64 conversion intrinsics + case Intrinsic::nvvm_f2ll_rm: + case Intrinsic::nvvm_f2ll_rn: + case Intrinsic::nvvm_f2ll_rp: + case Intrinsic::nvvm_f2ll_rz: + case Intrinsic::nvvm_f2ll_rm_ftz: + case Intrinsic::nvvm_f2ll_rn_ftz: + case Intrinsic::nvvm_f2ll_rp_ftz: + case Intrinsic::nvvm_f2ll_rz_ftz: + case Intrinsic::nvvm_f2ull_rm: + case Intrinsic::nvvm_f2ull_rn: + case Intrinsic::nvvm_f2ull_rp: + case Intrinsic::nvvm_f2ull_rz: + case Intrinsic::nvvm_f2ull_rm_ftz: + case Intrinsic::nvvm_f2ull_rn_ftz: + case Intrinsic::nvvm_f2ull_rp_ftz: + case Intrinsic::nvvm_f2ull_rz_ftz: + case Intrinsic::nvvm_d2ll_rm: + case Intrinsic::nvvm_d2ll_rn: + case Intrinsic::nvvm_d2ll_rp: + case Intrinsic::nvvm_d2ll_rz: + case Intrinsic::nvvm_d2ull_rm: + case Intrinsic::nvvm_d2ull_rn: + case Intrinsic::nvvm_d2ull_rp: + case Intrinsic::nvvm_d2ull_rz: + // Sign operations are actually bitwise operations, they do not raise // exceptions even for SNANs. case Intrinsic::fabs: @@ -1849,6 +1903,12 @@ inline bool llvm_fenv_testexcept() { return false; } +static const APFloat FTZPreserveSign(const APFloat &V) { + if (V.isDenormal()) + return APFloat::getZero(V.getSemantics(), V.isNegative()); + return V; +} + Constant *ConstantFoldFP(double (*NativeFP)(double), const APFloat &V, Type *Ty) { llvm_fenv_clearexcept(); @@ -2309,6 +2369,85 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, return ConstantFP::get(Ty->getContext(), U); } + // NVVM float/double to signed/unsigned int32/int64 conversions: + switch (IntrinsicID) { + // f2i + case Intrinsic::nvvm_f2i_rm: + case Intrinsic::nvvm_f2i_rn: + case Intrinsic::nvvm_f2i_rp: + case Intrinsic::nvvm_f2i_rz: + case Intrinsic::nvvm_f2i_rm_ftz: + case Intrinsic::nvvm_f2i_rn_ftz: + case Intrinsic::nvvm_f2i_rp_ftz: + case Intrinsic::nvvm_f2i_rz_ftz: + // f2ui + case Intrinsic::nvvm_f2ui_rm: + case Intrinsic::nvvm_f2ui_rn: + case Intrinsic::nvvm_f2ui_rp: + case Intrinsic::nvvm_f2ui_rz: + case Intrinsic::nvvm_f2ui_rm_ftz: + case Intrinsic::nvvm_f2ui_rn_ftz: + case Intrinsic::nvvm_f2ui_rp_ftz: + case Intrinsic::nvvm_f2ui_rz_ftz: + // d2i + case Intrinsic::nvvm_d2i_rm: + case Intrinsic::nvvm_d2i_rn: + case Intrinsic::nvvm_d2i_rp: + case Intrinsic::nvvm_d2i_rz: + // d2ui + case Intrinsic::nvvm_d2ui_rm: + case Intrinsic::nvvm_d2ui_rn: + case Intrinsic::nvvm_d2ui_rp: + case Intrinsic::nvvm_d2ui_rz: + // f2ll + case Intrinsic::nvvm_f2ll_rm: + case Intrinsic::nvvm_f2ll_rn: + case Intrinsic::nvvm_f2ll_rp: + case Intrinsic::nvvm_f2ll_rz: + case Intrinsic::nvvm_f2ll_rm_ftz: + case Intrinsic::nvvm_f2ll_rn_ftz: + case Intrinsic::nvvm_f2ll_rp_ftz: + case Intrinsic::nvvm_f2ll_rz_ftz: + // f2ull + case Intrinsic::nvvm_f2ull_rm: + case Intrinsic::nvvm_f2ull_rn: + case Intrinsic::nvvm_f2ull_rp: + case Intrinsic::nvvm_f2ull_rz: + case Intrinsic::nvvm_f2ull_rm_ftz: + case Intrinsic::nvvm_f2ull_rn_ftz: + case Intrinsic::nvvm_f2ull_rp_ftz: + case Intrinsic::nvvm_f2ull_rz_ftz: + // d2ll + case Intrinsic::nvvm_d2ll_rm: + case Intrinsic::nvvm_d2ll_rn: + case Intrinsic::nvvm_d2ll_rp: + case Intrinsic::nvvm_d2ll_rz: + // d2ull + case Intrinsic::nvvm_d2ull_rm: + case Intrinsic::nvvm_d2ull_rn: + case Intrinsic::nvvm_d2ull_rp: + case Intrinsic::nvvm_d2ull_rz: { + // In float-to-integer conversion, NaN inputs are converted to 0. + if (U.isNaN()) + return ConstantInt::get(Ty, 0); + + APFloat::roundingMode RMode = nvvm::IntrinsicGetRoundingMode(IntrinsicID); + bool IsFTZ = nvvm::IntrinsicShouldFTZ(IntrinsicID); + bool IsSigned = nvvm::IntrinsicConvertsToSignedInteger(IntrinsicID); + + APSInt ResInt(Ty->getIntegerBitWidth(), !IsSigned); + auto FloatToRound = IsFTZ ? FTZPreserveSign(U) : U; + + bool IsExact = false; + APFloat::opStatus Status = + FloatToRound.convertToInteger(ResInt, RMode, &IsExact); + + if (Status != APFloat::opInvalidOp) + return ConstantInt::get(Ty, ResInt); + return nullptr; + } + } + /// We only fold functions with finite arguments. Folding NaN and inf is /// likely to be aborted with an exception anyway, and some host libms /// have known errors raising exceptions. diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 8567a05..999386c 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4275,25 +4275,27 @@ Value *llvm::simplifyFCmpInst(CmpPredicate Predicate, Value *LHS, Value *RHS, return ::simplifyFCmpInst(Predicate, LHS, RHS, FMF, Q, RecursionLimit); } -static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, - const SimplifyQuery &Q, - bool AllowRefinement, - SmallVectorImpl<Instruction *> *DropFlags, - unsigned MaxRecurse) { +static Value *simplifyWithOpsReplaced(Value *V, + ArrayRef<std::pair<Value *, Value *>> Ops, + const SimplifyQuery &Q, + bool AllowRefinement, + SmallVectorImpl<Instruction *> *DropFlags, + unsigned MaxRecurse) { assert((AllowRefinement || !Q.CanUseUndef) && "If AllowRefinement=false then CanUseUndef=false"); + for (const auto &OpAndRepOp : Ops) { + // We cannot replace a constant, and shouldn't even try. + if (isa<Constant>(OpAndRepOp.first)) + return nullptr; - // Trivial replacement. - if (V == Op) - return RepOp; + // Trivial replacement. + if (V == OpAndRepOp.first) + return OpAndRepOp.second; + } if (!MaxRecurse--) return nullptr; - // We cannot replace a constant, and shouldn't even try. - if (isa<Constant>(Op)) - return nullptr; - auto *I = dyn_cast<Instruction>(V); if (!I) return nullptr; @@ -4303,11 +4305,6 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, if (isa<PHINode>(I)) return nullptr; - // For vector types, the simplification must hold per-lane, so forbid - // potentially cross-lane operations like shufflevector. - if (Op->getType()->isVectorTy() && !isNotCrossLaneOperation(I)) - return nullptr; - // Don't fold away llvm.is.constant checks based on assumptions. if (match(I, m_Intrinsic<Intrinsic::is_constant>())) return nullptr; @@ -4316,12 +4313,20 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, if (isa<FreezeInst>(I)) return nullptr; + for (const auto &OpAndRepOp : Ops) { + // For vector types, the simplification must hold per-lane, so forbid + // potentially cross-lane operations like shufflevector. + if (OpAndRepOp.first->getType()->isVectorTy() && + !isNotCrossLaneOperation(I)) + return nullptr; + } + // Replace Op with RepOp in instruction operands. SmallVector<Value *, 8> NewOps; bool AnyReplaced = false; for (Value *InstOp : I->operands()) { - if (Value *NewInstOp = simplifyWithOpReplaced( - InstOp, Op, RepOp, Q, AllowRefinement, DropFlags, MaxRecurse)) { + if (Value *NewInstOp = simplifyWithOpsReplaced( + InstOp, Ops, Q, AllowRefinement, DropFlags, MaxRecurse)) { NewOps.push_back(NewInstOp); AnyReplaced = InstOp != NewInstOp; } else { @@ -4372,7 +4377,8 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, // by assumption and this case never wraps, so nowrap flags can be // ignored. if ((Opcode == Instruction::Sub || Opcode == Instruction::Xor) && - NewOps[0] == RepOp && NewOps[1] == RepOp) + NewOps[0] == NewOps[1] && + any_of(Ops, [=](const auto &Rep) { return NewOps[0] == Rep.second; })) return Constant::getNullValue(I->getType()); // If we are substituting an absorber constant into a binop and extra @@ -4382,10 +4388,10 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, // (Op == 0) ? 0 : (Op & -Op) --> Op & -Op // (Op == 0) ? 0 : (Op * (binop Op, C)) --> Op * (binop Op, C) // (Op == -1) ? -1 : (Op | (binop C, Op) --> Op | (binop C, Op) - Constant *Absorber = - ConstantExpr::getBinOpAbsorber(Opcode, I->getType()); + Constant *Absorber = ConstantExpr::getBinOpAbsorber(Opcode, I->getType()); if ((NewOps[0] == Absorber || NewOps[1] == Absorber) && - impliesPoison(BO, Op)) + any_of(Ops, + [=](const auto &Rep) { return impliesPoison(BO, Rep.first); })) return Absorber; } @@ -4453,6 +4459,15 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, /*AllowNonDeterministic=*/false); } +static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, + const SimplifyQuery &Q, + bool AllowRefinement, + SmallVectorImpl<Instruction *> *DropFlags, + unsigned MaxRecurse) { + return simplifyWithOpsReplaced(V, {{Op, RepOp}}, Q, AllowRefinement, + DropFlags, MaxRecurse); +} + Value *llvm::simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, const SimplifyQuery &Q, bool AllowRefinement, @@ -4595,17 +4610,24 @@ static Value *simplifySelectWithFakeICmpEq(Value *CmpLHS, Value *CmpRHS, /// Try to simplify a select instruction when its condition operand is an /// integer equality or floating-point equivalence comparison. -static Value *simplifySelectWithEquivalence(Value *CmpLHS, Value *CmpRHS, - Value *TrueVal, Value *FalseVal, - const SimplifyQuery &Q, - unsigned MaxRecurse) { - if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q.getWithoutUndef(), - /* AllowRefinement */ false, - /* DropFlags */ nullptr, MaxRecurse) == TrueVal) - return FalseVal; - if (simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q, - /* AllowRefinement */ true, - /* DropFlags */ nullptr, MaxRecurse) == FalseVal) +static Value *simplifySelectWithEquivalence( + ArrayRef<std::pair<Value *, Value *>> Replacements, Value *TrueVal, + Value *FalseVal, const SimplifyQuery &Q, unsigned MaxRecurse) { + Value *SimplifiedFalseVal = + simplifyWithOpsReplaced(FalseVal, Replacements, Q.getWithoutUndef(), + /* AllowRefinement */ false, + /* DropFlags */ nullptr, MaxRecurse); + if (!SimplifiedFalseVal) + SimplifiedFalseVal = FalseVal; + + Value *SimplifiedTrueVal = + simplifyWithOpsReplaced(TrueVal, Replacements, Q, + /* AllowRefinement */ true, + /* DropFlags */ nullptr, MaxRecurse); + if (!SimplifiedTrueVal) + SimplifiedTrueVal = TrueVal; + + if (SimplifiedFalseVal == SimplifiedTrueVal) return FalseVal; return nullptr; @@ -4699,10 +4721,10 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal, // the arms of the select. See if substituting this value into the arm and // simplifying the result yields the same value as the other arm. if (Pred == ICmpInst::ICMP_EQ) { - if (Value *V = simplifySelectWithEquivalence(CmpLHS, CmpRHS, TrueVal, + if (Value *V = simplifySelectWithEquivalence({{CmpLHS, CmpRHS}}, TrueVal, FalseVal, Q, MaxRecurse)) return V; - if (Value *V = simplifySelectWithEquivalence(CmpRHS, CmpLHS, TrueVal, + if (Value *V = simplifySelectWithEquivalence({{CmpRHS, CmpLHS}}, TrueVal, FalseVal, Q, MaxRecurse)) return V; @@ -4712,11 +4734,8 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal, if (match(CmpLHS, m_Or(m_Value(X), m_Value(Y))) && match(CmpRHS, m_Zero())) { // (X | Y) == 0 implies X == 0 and Y == 0. - if (Value *V = simplifySelectWithEquivalence(X, CmpRHS, TrueVal, FalseVal, - Q, MaxRecurse)) - return V; - if (Value *V = simplifySelectWithEquivalence(Y, CmpRHS, TrueVal, FalseVal, - Q, MaxRecurse)) + if (Value *V = simplifySelectWithEquivalence( + {{X, CmpRHS}, {Y, CmpRHS}}, TrueVal, FalseVal, Q, MaxRecurse)) return V; } @@ -4724,11 +4743,8 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal, if (match(CmpLHS, m_And(m_Value(X), m_Value(Y))) && match(CmpRHS, m_AllOnes())) { // (X & Y) == -1 implies X == -1 and Y == -1. - if (Value *V = simplifySelectWithEquivalence(X, CmpRHS, TrueVal, FalseVal, - Q, MaxRecurse)) - return V; - if (Value *V = simplifySelectWithEquivalence(Y, CmpRHS, TrueVal, FalseVal, - Q, MaxRecurse)) + if (Value *V = simplifySelectWithEquivalence( + {{X, CmpRHS}, {Y, CmpRHS}}, TrueVal, FalseVal, Q, MaxRecurse)) return V; } } @@ -4757,11 +4773,11 @@ static Value *simplifySelectWithFCmp(Value *Cond, Value *T, Value *F, // This transforms is safe if at least one operand is known to not be zero. // Otherwise, the select can change the sign of a zero operand. if (IsEquiv) { - if (Value *V = - simplifySelectWithEquivalence(CmpLHS, CmpRHS, T, F, Q, MaxRecurse)) + if (Value *V = simplifySelectWithEquivalence({{CmpLHS, CmpRHS}}, T, F, Q, + MaxRecurse)) return V; - if (Value *V = - simplifySelectWithEquivalence(CmpRHS, CmpLHS, T, F, Q, MaxRecurse)) + if (Value *V = simplifySelectWithEquivalence({{CmpRHS, CmpLHS}}, T, F, Q, + MaxRecurse)) return V; } diff --git a/llvm/lib/Analysis/Lint.cpp b/llvm/lib/Analysis/Lint.cpp index 4689451..e9d96a0c 100644 --- a/llvm/lib/Analysis/Lint.cpp +++ b/llvm/lib/Analysis/Lint.cpp @@ -266,6 +266,30 @@ void Lint::visitCallBase(CallBase &I) { visitMemoryReference(I, Loc, DL->getABITypeAlign(Ty), Ty, MemRef::Read | MemRef::Write); } + + // Check that ABI attributes for the function and call-site match. + unsigned ArgNo = AI->getOperandNo(); + Attribute::AttrKind ABIAttributes[] = { + Attribute::ZExt, Attribute::SExt, Attribute::InReg, + Attribute::ByVal, Attribute::ByRef, Attribute::InAlloca, + Attribute::Preallocated, Attribute::StructRet}; + AttributeList CallAttrs = I.getAttributes(); + for (Attribute::AttrKind Attr : ABIAttributes) { + Attribute CallAttr = CallAttrs.getParamAttr(ArgNo, Attr); + Attribute FnAttr = F->getParamAttribute(ArgNo, Attr); + Check(CallAttr.isValid() == FnAttr.isValid(), + Twine("Undefined behavior: ABI attribute ") + + Attribute::getNameFromAttrKind(Attr) + + " not present on both function and call-site", + &I); + if (CallAttr.isValid() && FnAttr.isValid()) { + Check(CallAttr == FnAttr, + Twine("Undefined behavior: ABI attribute ") + + Attribute::getNameFromAttrKind(Attr) + + " does not have same argument for function and call-site", + &I); + } + } } } } diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp index 54b9521..bc03e40 100644 --- a/llvm/lib/Analysis/Loads.cpp +++ b/llvm/lib/Analysis/Loads.cpp @@ -25,10 +25,9 @@ using namespace llvm; -static bool isAligned(const Value *Base, const APInt &Offset, Align Alignment, +static bool isAligned(const Value *Base, Align Alignment, const DataLayout &DL) { - Align BA = Base->getPointerAlignment(DL); - return BA >= Alignment && Offset.isAligned(BA); + return Base->getPointerAlignment(DL) >= Alignment; } /// Test if V is always a pointer to allocated and suitably aligned memory for @@ -118,8 +117,7 @@ static bool isDereferenceableAndAlignedPointer( // As we recursed through GEPs to get here, we've incrementally checked // that each step advanced by a multiple of the alignment. If our base is // properly aligned, then the original offset accessed must also be. - APInt Offset(DL.getTypeStoreSizeInBits(V->getType()), 0); - return isAligned(V, Offset, Alignment, DL); + return isAligned(V, Alignment, DL); } /// TODO refactor this function to be able to search independently for @@ -154,8 +152,7 @@ static bool isDereferenceableAndAlignedPointer( // checked that each step advanced by a multiple of the alignment. If // our base is properly aligned, then the original offset accessed // must also be. - APInt Offset(DL.getTypeStoreSizeInBits(V->getType()), 0); - return isAligned(V, Offset, Alignment, DL); + return isAligned(V, Alignment, DL); } } } diff --git a/llvm/lib/Analysis/MemoryProfileInfo.cpp b/llvm/lib/Analysis/MemoryProfileInfo.cpp index 1c3f589..2f3c87a 100644 --- a/llvm/lib/Analysis/MemoryProfileInfo.cpp +++ b/llvm/lib/Analysis/MemoryProfileInfo.cpp @@ -347,3 +347,20 @@ template <> uint64_t CallStack<MDNode, MDNode::op_iterator>::back() const { return mdconst::dyn_extract<ConstantInt>(N->operands().back()) ->getZExtValue(); } + +MDNode *MDNode::getMergedMemProfMetadata(MDNode *A, MDNode *B) { + // TODO: Support more sophisticated merging, such as selecting the one with + // more bytes allocated, or implement support for carrying multiple allocation + // leaf contexts. For now, keep the first one. + if (A) + return A; + return B; +} + +MDNode *MDNode::getMergedCallsiteMetadata(MDNode *A, MDNode *B) { + // TODO: Support more sophisticated merging, which will require support for + // carrying multiple contexts. For now, keep the first one. + if (A) + return A; + return B; +} diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index 8ab5602..7e18f7c 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -226,7 +226,7 @@ static cl::opt<unsigned> RangeIterThreshold( static cl::opt<unsigned> MaxLoopGuardCollectionDepth( "scalar-evolution-max-loop-guard-collection-depth", cl::Hidden, - cl::desc("Maximum depth for recrusive loop guard collection"), cl::init(1)); + cl::desc("Maximum depth for recursive loop guard collection"), cl::init(1)); static cl::opt<bool> ClassifyExpressions("scalar-evolution-classify-expressions", @@ -15765,6 +15765,7 @@ void ScalarEvolution::LoopGuards::collectFromBlock( // original header. // TODO: share this logic with isLoopEntryGuardedByCond. unsigned NumCollectedConditions = 0; + VisitedBlocks.insert(Block); std::pair<const BasicBlock *, const BasicBlock *> Pair(Pred, Block); for (; Pair.first; Pair = SE.getPredecessorWithUniqueSuccessorForBB(Pair.first)) { diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 78fec25..0eb43dd 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1119,7 +1119,8 @@ static void unionWithMinMaxIntrinsicClamp(const IntrinsicInst *II, KnownBits &Known) { const APInt *CLow, *CHigh; if (isSignedMinMaxIntrinsicClamp(II, CLow, CHigh)) - Known = Known.unionWith(ConstantRange(*CLow, *CHigh + 1).toKnownBits()); + Known = Known.unionWith( + ConstantRange::getNonEmpty(*CLow, *CHigh + 1).toKnownBits()); } static void computeKnownBitsFromOperator(const Operator *I, @@ -8640,6 +8641,80 @@ SelectPatternResult llvm::getSelectPattern(CmpInst::Predicate Pred, } } +std::optional<std::pair<CmpPredicate, Constant *>> +llvm::getFlippedStrictnessPredicateAndConstant(CmpPredicate Pred, Constant *C) { + assert(ICmpInst::isRelational(Pred) && ICmpInst::isIntPredicate(Pred) && + "Only for relational integer predicates."); + if (isa<UndefValue>(C)) + return std::nullopt; + + Type *Type = C->getType(); + bool IsSigned = ICmpInst::isSigned(Pred); + + CmpInst::Predicate UnsignedPred = ICmpInst::getUnsignedPredicate(Pred); + bool WillIncrement = + UnsignedPred == ICmpInst::ICMP_ULE || UnsignedPred == ICmpInst::ICMP_UGT; + + // Check if the constant operand can be safely incremented/decremented + // without overflowing/underflowing. + auto ConstantIsOk = [WillIncrement, IsSigned](ConstantInt *C) { + return WillIncrement ? !C->isMaxValue(IsSigned) : !C->isMinValue(IsSigned); + }; + + Constant *SafeReplacementConstant = nullptr; + if (auto *CI = dyn_cast<ConstantInt>(C)) { + // Bail out if the constant can't be safely incremented/decremented. + if (!ConstantIsOk(CI)) + return std::nullopt; + } else if (auto *FVTy = dyn_cast<FixedVectorType>(Type)) { + unsigned NumElts = FVTy->getNumElements(); + for (unsigned i = 0; i != NumElts; ++i) { + Constant *Elt = C->getAggregateElement(i); + if (!Elt) + return std::nullopt; + + if (isa<UndefValue>(Elt)) + continue; + + // Bail out if we can't determine if this constant is min/max or if we + // know that this constant is min/max. + auto *CI = dyn_cast<ConstantInt>(Elt); + if (!CI || !ConstantIsOk(CI)) + return std::nullopt; + + if (!SafeReplacementConstant) + SafeReplacementConstant = CI; + } + } else if (isa<VectorType>(C->getType())) { + // Handle scalable splat + Value *SplatC = C->getSplatValue(); + auto *CI = dyn_cast_or_null<ConstantInt>(SplatC); + // Bail out if the constant can't be safely incremented/decremented. + if (!CI || !ConstantIsOk(CI)) + return std::nullopt; + } else { + // ConstantExpr? + return std::nullopt; + } + + // It may not be safe to change a compare predicate in the presence of + // undefined elements, so replace those elements with the first safe constant + // that we found. + // TODO: in case of poison, it is safe; let's replace undefs only. + if (C->containsUndefOrPoisonElement()) { + assert(SafeReplacementConstant && "Replacement constant not set"); + C = Constant::replaceUndefsWith(C, SafeReplacementConstant); + } + + CmpInst::Predicate NewPred = CmpInst::getFlippedStrictnessPredicate(Pred); + + // Increment or decrement the constant. + Constant *OneOrNegOne = ConstantInt::get(Type, WillIncrement ? 1 : -1, true); + Constant *NewC = ConstantExpr::getAdd(C, OneOrNegOne); + + return std::make_pair(NewPred, NewC); +} + static SelectPatternResult matchSelectPattern(CmpInst::Predicate Pred, FastMathFlags FMF, Value *CmpLHS, Value *CmpRHS, |