55#define DEBUG_TYPE "constraint-elimination"
57STATISTIC(NumCondsRemoved,
"Number of instructions removed");
59 "Controls which conditions are eliminated");
67 UserI = Phi->getIncomingBlock(U)->getTerminator();
76 for (
Use &U :
I.uses()) {
102 : Pred(Pred), Op0(Op0), Op1(Op1) {}
140 FactOrCheck(EntryTy Ty,
DomTreeNode *DTN, Instruction *Inst,
141 Instruction *ContextInst =
nullptr)
142 : Inst(Inst), ContextInst(ContextInst ? ContextInst : Inst),
143 NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), Ty(Ty) {}
146 :
U(
U), ContextInst(nullptr), NumIn(DTN->getDFSNumIn()),
147 NumOut(DTN->getDFSNumOut()), Ty(EntryTy::UseCheck) {}
151 :
Cond(Pred, Op0, Op1), DoesHold(Precond), NumIn(DTN->getDFSNumIn()),
152 NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {}
154 static FactOrCheck getConditionFact(
DomTreeNode *DTN, CmpPredicate Pred,
157 return FactOrCheck(DTN, Pred, Op0, Op1, Precond);
160 static FactOrCheck getInstFact(
DomTreeNode *DTN, Instruction *Inst) {
161 return FactOrCheck(EntryTy::InstFact, DTN, Inst);
164 static FactOrCheck getCheck(
DomTreeNode *DTN, Use *U) {
165 return FactOrCheck(DTN, U);
168 static FactOrCheck getCheck(
DomTreeNode *DTN, Instruction *
I,
169 Instruction *ContextInst =
nullptr) {
171 "anchoring instruction must be in DTN's block");
172 return FactOrCheck(EntryTy::InstCheck, DTN,
I, ContextInst);
175 bool isCheck()
const {
176 return Ty == EntryTy::InstCheck || Ty == EntryTy::UseCheck;
180 assert(!isConditionFact());
181 if (Ty == EntryTy::UseCheck)
188 if (Ty == EntryTy::InstCheck)
194 bool isConditionFact()
const {
return Ty == EntryTy::ConditionFact; }
199struct MonotonicInfo {
201 bool Decreasing =
false;
203 bool Unsigned =
false;
214 TargetLibraryInfo &TLI;
217 State(DominatorTree &DT, LoopInfo &LI, ScalarEvolution *SE,
218 TargetLibraryInfo &TLI)
219 : DT(DT), LI(LI), SE(SE), TLI(TLI) {}
222 void addInfoFor(BasicBlock &BB);
226 void addBoundsForHeaderInductions(BasicBlock &BB);
230 void addInfoForInductions(BasicBlock &BB);
234 MonotonicInfo getMonotonicityInfo(PHINode &PN,
Value *Step);
238 bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ)
const {
239 return DT.dominates(BasicBlockEdge(&BB, Succ), Succ);
248 bool IsSigned =
false;
251 SmallVector<Value *, 2> ValuesToRelease;
253 StackEntry(
unsigned NumIn,
unsigned NumOut,
bool IsSigned,
254 SmallVector<Value *, 2> ValuesToRelease)
255 : NumIn(NumIn), NumOut(NumOut), IsSigned(IsSigned),
256 ValuesToRelease(std::
move(ValuesToRelease)) {}
263 unsigned NumVars = 0;
265 bool IsSigned =
false;
267 ConstraintTy() =
default;
269 ConstraintTy(RowTy Coefficients,
unsigned NumVars,
bool IsSigned,
bool IsEq,
271 : Coefficients(std::
move(Coefficients)), NumVars(NumVars),
272 IsSigned(IsSigned), IsEq(IsEq), IsNe(IsNe) {}
274 bool empty()
const {
return Coefficients.empty(); }
276 bool isEq()
const {
return IsEq; }
278 bool isNe()
const {
return IsNe; }
285 std::optional<bool> isImpliedBy(
const ConstraintSystem &CS)
const;
297 DecompEntry(int64_t Coefficient,
Value *Variable)
298 : Coefficient(Coefficient), Variable(Variable) {}
302struct Decomposition {
306 Decomposition(int64_t Offset) : Offset(Offset) {}
307 Decomposition(
Value *V) { Vars.emplace_back(1, V); }
309 : Offset(Offset), Vars(Vars) {}
313 [[nodiscard]]
bool add(int64_t OtherOffset) {
319 [[nodiscard]]
bool add(
const Decomposition &
Other) {
328 [[nodiscard]]
bool sub(
const Decomposition &
Other) {
329 Decomposition Tmp =
Other;
340 [[nodiscard]]
bool mul(int64_t Factor) {
343 for (
auto &Var : Vars)
344 if (
MulOverflow(Var.Coefficient, Factor, Var.Coefficient))
356class ConstraintInfo {
358 ConstraintSystem UnsignedCS;
359 ConstraintSystem SignedCS;
361 const DataLayout &DL;
365 DenseMap<PointerIntPair<Value *, 1, bool>, Decomposition> DecomposeCache;
368 DenseMap<PointerIntPair<Value *, 1, bool>, Decomposition> &
369 getDecomposeCache() {
370 return DecomposeCache;
374 : UnsignedCS(FunctionArgs), SignedCS(FunctionArgs), DL(DL) {
375 auto &Value2Index = getValue2Index(
false);
377 for (
Value *Arg : FunctionArgs)
378 UnsignedCS.addRow({
Entry(0, 0),
Entry(-1, Value2Index.at(Arg))},
382 DenseMap<Value *, unsigned> &getValue2Index(
bool Signed) {
383 return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
385 const DenseMap<Value *, unsigned> &getValue2Index(
bool Signed)
const {
386 return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
389 ConstraintSystem &getCS(
bool Signed) {
390 return Signed ? SignedCS : UnsignedCS;
392 const ConstraintSystem &getCS(
bool Signed)
const {
393 return Signed ? SignedCS : UnsignedCS;
396 void popLastConstraint(
bool Signed) {
397 assert(DecomposeCache.empty() &&
"Cache must be cleared");
398 getCS(
Signed).popLastConstraint();
400 void popLastNVariables(
bool Signed,
unsigned N) {
401 assert(DecomposeCache.empty() &&
"Cache must be cleared");
402 getCS(
Signed).popLastNVariables(
N);
416 unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack);
423 SmallVectorImpl<Value *> &NewVariables,
424 bool ForceSignedSystem =
false);
439 unsigned NumIn,
unsigned NumOut,
440 SmallVectorImpl<StackEntry> &DFSInStack);
447 unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack,
448 bool ForceSignedSystem);
452 void tightenBoundUsingNe(
Value *
A,
Value *
B,
unsigned NumIn,
unsigned NumOut,
453 SmallVectorImpl<StackEntry> &DFSInStack);
459 APInt ConstantOffset;
460 SmallMapVector<Value *, APInt, 4> VariableOffsets;
465 OffsetResult(GEPOperator &
GEP,
const DataLayout &
DL)
467 ConstantOffset = APInt(
DL.getIndexTypeSizeInBits(
BasePtr->getType()), 0);
477 unsigned BitWidth = Result.ConstantOffset.getBitWidth();
479 Result.ConstantOffset))
487 bool CanCollectInner = InnerGEP->collectOffset(
488 DL,
BitWidth, VariableOffsets2, ConstantOffset2);
490 if (!CanCollectInner || Result.VariableOffsets.size() > 1 ||
491 VariableOffsets2.
size() > 1 ||
492 (Result.VariableOffsets.size() >= 1 && VariableOffsets2.
size() >= 1)) {
498 bool Overflow =
false;
499 APInt CombinedOffset =
500 Result.ConstantOffset.sadd_ov(ConstantOffset2, Overflow);
504 Result.BasePtr = InnerGEP->getPointerOperand();
505 Result.ConstantOffset = CombinedOffset;
506 if (Result.VariableOffsets.size() == 0 && VariableOffsets2.
size() == 1)
507 Result.VariableOffsets = std::move(VariableOffsets2);
508 Result.NW &= InnerGEP->getNoWrapFlags();
513static Decomposition
decompose(
Value *V, ConstraintInfo &Info,
bool IsSigned,
525 if (R.isEmptySet() || (
Signed ? R.isSignWrappedSet() : R.isWrappedSet()))
531 unsigned BitWidth = R.getBitWidth();
532 APInt Min =
Signed ? R.getSignedMin() : R.getUnsignedMin();
533 APInt Max =
Signed ? R.getSignedMax() : R.getUnsignedMax();
545 ConstantInt::get(Ty, Min)))
549 ConstantInt::get(Ty, Max)))
557 unsigned NoWrapFlags, ConstraintInfo &Info,
561 if (NoWrapFlags & (
Signed ? OBO::NoSignedWrap : OBO::NoUnsignedWrap))
564 if (Opcode == Instruction::Sub) {
570 if (Info.isKnownNonNegative(Op1) &&
575 if (!
Signed && (NoWrapFlags & OBO::NoSignedWrap) &&
576 (Opcode == Instruction::Shl || Info.isKnownNonNegative(Op1)) &&
577 Info.isKnownNonNegative(Op0))
588 Opcode,
C->getValue(),
589 Signed ? OBO::NoSignedWrap : OBO::NoUnsignedWrap),
600 return isKnownNoWrap(WO->getBinaryOp(), WO->getLHS(), WO->getRHS(),
605 return Trunc->hasNoSignedWrap();
609 return Trunc->hasNoUnsignedWrap() ||
610 (Trunc->hasNoSignedWrap() &&
611 Info.isKnownNonNegative(Trunc->getOperand(0)));
617 BO->getOperand(0), BO->getOperand(1),
618 BO->getNoWrapKind(), Info,
Signed);
625 if (
DL.getIndexTypeSizeInBits(
GEP.getPointerOperand()->getType()) > 64)
628 assert(!IsSigned &&
"The logic below only supports decomposition for "
629 "unsigned predicates at the moment.");
630 const auto &[BasePtr, ConstantOffset, VariableOffsets, NW] =
639 if (!NW.hasNoUnsignedSignedWrap() && ConstantOffset.isNegative())
642 Decomposition Result(ConstantOffset.getSExtValue(), DecompEntry(1, BasePtr));
643 for (
auto [Index, Scale] : VariableOffsets) {
646 if (Index->getType()->getScalarSizeInBits() != Scale.getBitWidth())
648 if (!NW.hasNoUnsignedWrap()) {
651 assert(NW.hasNoUnsignedSignedWrap() &&
"Must have nusw flag");
652 if (!Info.isKnownNonNegative(Index))
654 }
else if (!NW.hasNoUnsignedSignedWrap()) {
657 if (Scale.isNegative())
661 auto IdxResult =
decompose(Index, Info, IsSigned,
DL);
662 if (IdxResult.mul(Scale.getSExtValue()))
664 if (Result.add(IdxResult))
684 switch (
Op->getOpcode()) {
685 case Instruction::GetElementPtr:
686 case Instruction::Add:
687 case Instruction::Sub:
688 case Instruction::Mul:
689 case Instruction::Shl:
690 case Instruction::LShr:
691 case Instruction::AShr:
692 case Instruction::ZExt:
693 case Instruction::SExt:
694 case Instruction::Trunc:
695 case Instruction::Or:
696 case Instruction::Xor:
709 auto &Cache = Info.getDecomposeCache();
710 auto It = Cache.find(
Key);
711 if (It != Cache.end())
715 Info.getDecomposeCache().insert({
Key, Result});
721 auto MergeResults = [&Info, IsSigned,
723 bool IsSignedB) -> std::optional<Decomposition> {
732 if (Ty->isPointerTy() && !IsSigned) {
744 if (!Ty->isIntegerTy() || Ty->getIntegerBitWidth() > 64)
750 return CI->getSExtValue();
752 return int64_t(CI->getZExtValue());
768 if (!IsSigned && !Info.isKnownNonNegative(Op0))
772 if (Trunc->getSrcTy()->getScalarSizeInBits() <= 64 &&
774 V = Trunc->getOperand(0);
779 if (
auto Decomp = MergeResults(Op0, Op1, IsSigned))
789 if (
auto Decomp = MergeResults(Op0, CI,
true))
796 Decomposition Result(-1);
797 if (!Result.sub(
decompose(Op0, Info, IsSigned,
DL)))
825 bool IsAShr =
cast<Operator>(V)->getOpcode() == Instruction::AShr;
827 (IsSigned == IsAShr || Info.isKnownNonNegative(Op0))) {
830 if (Result.Offset % Factor == 0 &&
831 all_of(Result.Vars, [Factor](
const DecompEntry &
E) {
832 return E.Coefficient % Factor == 0;
834 Result.Offset /= Factor;
835 for (
auto &
E : Result.Vars)
836 E.Coefficient /= Factor;
847 int64_t MaxShift = IsSigned ? Ty->getIntegerBitWidth() - 1 : 63;
865 const Decomposition &BDec,
871 if (
SubOverflow(BDec.Offset, ADec.Offset, OffsetSum))
873 RowTy R(1, Entry(OffsetSum, 0));
874 auto GetCoefficient = [&R](
unsigned Idx) -> int64_t & {
879 if (
I == R.end() ||
I->Id != Idx)
880 I = R.insert(
I, Entry(0, Idx));
881 return I->Coefficient;
885 auto GetOrAddIndex = [&Value2Index, &NewVariables](
Value *V) ->
unsigned {
886 auto V2I = Value2Index.
find(V);
887 if (V2I != Value2Index.
end())
889 unsigned Idx =
find(NewVariables, V) - NewVariables.
begin();
890 if (Idx == NewVariables.
size())
892 return Value2Index.
size() + Idx + 1;
894 for (
const DecompEntry &KV : ADec.Vars)
895 GetCoefficient(GetOrAddIndex(KV.Variable)) += KV.Coefficient;
897 for (
const DecompEntry &KV : BDec.Vars) {
898 auto &Coeff = GetCoefficient(GetOrAddIndex(KV.Variable));
904 erase_if(R, [](
const Entry &
E) {
return E.Id != 0 &&
E.Coefficient == 0; });
911 bool ForceSignedSystem) {
912 assert(NewVariables.
empty() &&
"NewVariables must be empty when passed in");
914 "signed system can only be forced on eq/ne");
955 auto &Value2Index = getValue2Index(IsSigned);
965 if (
AddOverflow(R[0].Coefficient, int64_t(-1), R[0].Coefficient))
969 unsigned NumV2I = Value2Index.size();
970 NewVariables.
truncate(
R.back().Id > NumV2I ?
R.back().Id - NumV2I : 0);
972 return ConstraintTy(std::move(R), Value2Index.size() + NewVariables.
size(),
973 IsSigned, IsEq, IsNe);
984 return ConstraintTy(RowTy(1,
Entry(0, 0)), 0,
985 false,
false,
false);
997 ConstraintTy
R = getConstraint(Pred, Op0, Op1, NewVariables);
998 if (!NewVariables.
empty())
1004ConstraintTy::isImpliedBy(
const ConstraintSystem &CS)
const {
1005 const auto &[SubCS, NewCoefficients] = CS.
getSubSystem(Coefficients);
1006 bool IsConditionImplied = SubCS.isConditionImplied(NewCoefficients);
1010 bool IsNegatedOrEqualImplied =
1011 !NegatedOrEqual.empty() && SubCS.isConditionImplied(NegatedOrEqual);
1016 if (IsConditionImplied && IsNegatedOrEqualImplied)
1020 bool IsNegatedImplied =
1021 !Negated.empty() && SubCS.isConditionImplied(Negated);
1024 bool IsStrictLessThanImplied =
1025 !StrictLessThan.empty() && SubCS.isConditionImplied(StrictLessThan);
1031 if (IsNegatedImplied || IsStrictLessThanImplied)
1034 return std::nullopt;
1037 if (IsConditionImplied)
1041 auto IsNegatedImplied = !Negated.empty() && SubCS.isConditionImplied(Negated);
1042 if (IsNegatedImplied)
1046 return std::nullopt;
1050 auto R = getConstraintForSolving(Pred,
A,
B);
1051 return !
R.empty() &&
1052 getCS(
R.IsSigned).isConditionImpliedInSubSystem(
R.Coefficients);
1055bool ConstraintInfo::isKnownNonNegative(
Value *V) {
1057 return !CI->isNegative();
1058 return ::isKnownNonNegative(V,
DL) ||
1062bool ConstraintInfo::isKnownPositive(
Value *V) {
1064 return CI->getValue().isStrictlyPositive();
1065 return ::isKnownPositive(V,
DL) ||
1069void ConstraintInfo::transferToOtherSystem(
1071 unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack) {
1074 if (!
A->getType()->isIntegerTy())
1087 NumOut, DFSInStack);
1097 NumOut, DFSInStack);
1111 NumOut, DFSInStack);
1137static std::pair<Value *, Value *>
1140 "LoopPred must be a predecessor of the phi's block");
1142 return {
nullptr,
nullptr};
1149template <
typename PhiMatchTy>
1158MonotonicInfo State::getMonotonicityInfo(PHINode &PN,
Value *Step) {
1160 const APInt *StepOffset =
nullptr;
1164 Info.Unsigned = !
Info.Decreasing &&
Add->hasNoUnsignedWrap();
1165 Info.Signed =
Add->hasNoSignedWrap();
1171 APInt GEPOffset(
DL.getIndexTypeSizeInBits(
GEP->getType()), 0);
1172 Info.Unsigned =
GEP->getPointerOperand() == &PN &&
1173 (
GEP->hasNoUnsignedWrap() ||
1174 ((
GEP->hasNoUnsignedSignedWrap() &&
1175 GEP->accumulateConstantOffset(
DL, GEPOffset) &&
1176 !GEPOffset.isNegative())));
1181 if (
Info.Unsigned ||
Info.Signed || !StepOffset)
1198void State::addBoundsForHeaderInductions(BasicBlock &BB) {
1200 if (!L ||
L->getHeader() != &BB)
1207 for (PHINode &PN : BB.
phis()) {
1215 MonotonicInfo
Info = getMonotonicityInfo(PN, Step);
1219 Info.Unsigned =
false;
1220 if (!
Info.Unsigned && !
Info.Signed)
1226 if (
Info.Decreasing)
1230 WorkList.
push_back(FactOrCheck::getConditionFact(DTN, Pred,
LHS,
RHS));
1234void State::addInfoForInductions(BasicBlock &BB) {
1241 if (Header != &BB && Latch != &BB)
1248 PHINode *PN =
nullptr;
1249 const APInt *IncStep =
nullptr;
1259 std::optional<bool> PeeledOnEdge;
1260 if (!
match(Br->getCondition(), CountingCmp)) {
1264 PeeledOnEdge =
true;
1266 PeeledOnEdge =
false;
1275 bool ContinueOnTrue =
1279 BasicBlock *InLoopSucc = Br->getSuccessor(ContinueOnTrue ? 0 : 1);
1283 if (PeeledOnEdge && *PeeledOnEdge != ContinueOnTrue)
1286 if (!
L->contains(InLoopSucc) || !
L->isLoopExiting(&BB))
1290 if (!LoopPred || !
L->isLoopInvariant(
B))
1302 bool HasHeaderBound =
1306 if (HasHeaderBound) {
1308 WorkList.
push_back(FactOrCheck::getConditionFact(
1309 HeaderDTN, BoundPred, PN,
B,
ConditionTy(BoundPred, StartValue,
B)));
1318 if (&BB == Latch && !IncStep)
1328 WorkList.
push_back(FactOrCheck::getConditionFact(
1329 HeaderDTN, ContinuePred, PN,
B,
1335 if (ICmpInst::isSigned(ContinuePred)) {
1338 "Expected a signed less-than continuation predicate");
1339 MonotonicInfo
Info = getMonotonicityInfo(*PN, Backedge);
1340 if (
Info.Signed && !
Info.Decreasing) {
1342 WorkList.
push_back(FactOrCheck::getConditionFact(
1343 HeaderDTN, UPred, PN,
B,
ConditionTy(UPred, StartValue,
B)));
1352 const APInt *StepOffset =
nullptr;
1353 const SCEV *StartSCEV =
nullptr;
1355 if (StepOffset->
isZero())
1358 const SCEV *Expr = SE->
getSCEV(PN);
1367 if (IncStep && *IncStep != *StepOffset)
1370 MonotonicInfo
Info = getMonotonicityInfo(*PN, Backedge);
1375 if (!(-*StepOffset).isOne())
1385 ConditionTy BBeforeStartUnsigned = {UPrecond,
B, StartValue};
1391 WorkList.
push_back(FactOrCheck::getConditionFact(
1393 if (!(
Info.Decreasing &&
Info.Signed))
1394 WorkList.
push_back(FactOrCheck::getConditionFact(
1398 B, BBeforeStartUnsigned));
1400 B, BBeforeStartSigned));
1410 if (!StepOffset->
isOne()) {
1413 StartSCEV = SE->
getSCEV(StartValue);
1427 ConditionTy StartBeforeBoundUnsigned = {UPrecond, StartValue,
B};
1433 WorkList.
push_back(FactOrCheck::getConditionFact(
1436 WorkList.
push_back(FactOrCheck::getConditionFact(
1441 if (!HasHeaderBound || !canAddSuccessor(BB, InLoopSucc)) {
1442 WorkList.
push_back(FactOrCheck::getConditionFact(
1444 WorkList.
push_back(FactOrCheck::getConditionFact(
1457 L->getExitBlocks(ExitBBs);
1458 for (BasicBlock *EB : ExitBBs) {
1472 if (!
GEP.hasNoUnsignedWrap())
1477 Base = InnerGEP->getPointerOperand();
1493 if (
Offset.VariableOffsets.size() != 1)
1497 auto &[Index, Scale] =
Offset.VariableOffsets.front();
1499 if (Index->getType()->getScalarSizeInBits() !=
BitWidth)
1512 B = ConstantInt::get(Index->getType(), MaxIndex);
1520 return Trunc->getType()->isIntegerTy() && Trunc->hasNoSignedWrap() &&
1521 !Trunc->hasNoUnsignedWrap();
1524 if (!BO || !BO->getType()->isIntegerTy())
1527 switch (BO->getOpcode()) {
1528 case Instruction::Sub:
1529 if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())
1534 case Instruction::Add:
1535 case Instruction::Mul:
1536 case Instruction::Shl:
1537 if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())
1556 I->setHasNoSignedWrap();
1561 I->setHasNoUnsignedWrap();
1567void State::addInfoFor(BasicBlock &BB) {
1568 addBoundsForHeaderInductions(BB);
1569 addInfoForInductions(BB);
1575 bool GuaranteedToExecute =
true;
1577 for (Instruction &
I : BB) {
1579 for (Use &U :
I.uses()) {
1581 auto *DTN = DT.
getNode(UserI->getParent());
1584 WorkList.
push_back(FactOrCheck::getCheck(DTN, &U));
1589 auto AddFactFromMemoryAccess = [&](
Value *Ptr,
Type *AccessType) {
1593 TypeSize AccessSize =
DL.getTypeStoreSize(AccessType);
1596 if (GuaranteedToExecute) {
1598 Pred,
A,
B,
DL, TLI)) {
1606 FactOrCheck::getInstFact(DT.
getNode(
I.getParent()), &
I));
1611 if (!LI->isVolatile())
1612 AddFactFromMemoryAccess(LI->getPointerOperand(), LI->getAccessType());
1615 if (!
SI->isVolatile())
1616 AddFactFromMemoryAccess(
SI->getPointerOperand(),
SI->getAccessType());
1622 case Intrinsic::assume: {
1625 if (GuaranteedToExecute) {
1632 FactOrCheck::getInstFact(DT.
getNode(
I.getParent()), &
I));
1637 case Intrinsic::uadd_with_overflow:
1638 case Intrinsic::sadd_with_overflow:
1639 case Intrinsic::usub_with_overflow:
1640 case Intrinsic::ssub_with_overflow:
1641 case Intrinsic::umul_with_overflow:
1642 case Intrinsic::smul_with_overflow:
1643 case Intrinsic::ucmp:
1644 case Intrinsic::scmp:
1649 case Intrinsic::umin:
1650 case Intrinsic::umax:
1651 case Intrinsic::smin:
1652 case Intrinsic::smax:
1653 case Intrinsic::usub_sat:
1658 case Intrinsic::uadd_sat:
1664 case Intrinsic::abs:
1679 if ((BO->getOpcode() == Instruction::URem ||
1680 BO->getOpcode() == Instruction::UDiv ||
1681 BO->getOpcode() == Instruction::LShr ||
1682 BO->getOpcode() == Instruction::SRem ||
1683 BO->getOpcode() == Instruction::SDiv) &&
1692 WorkList.
push_back(FactOrCheck::getCheck(
1700 for (
auto &Case :
Switch->cases()) {
1702 Value *
V = Case.getCaseValue();
1703 if (!canAddSuccessor(BB, Succ))
1732 SmallPtrSet<Value *, 8> SeenCond;
1733 auto QueueValue = [&CondWorkList, &SeenCond](
Value *
V) {
1734 if (SeenCond.
insert(V).second)
1739 while (!CondWorkList.
empty()) {
1764 if (canAddSuccessor(BB, Br->getSuccessor(0)))
1766 DT.
getNode(Br->getSuccessor(0)), Pred,
A,
B));
1767 if (canAddSuccessor(BB, Br->getSuccessor(1)))
1775 OS <<
"icmp " << Pred <<
' ';
1776 LHS->printAsOperand(OS,
true);
1778 RHS->printAsOperand(OS,
false);
1787struct ReproducerEntry {
1788 ICmpInst::Predicate Pred;
1823 auto &Value2Index = Info.getValue2Index(IsSigned);
1825 while (!WorkList.
empty()) {
1827 if (!Seen.
insert(V).second)
1829 if (Old2New.
find(V) != Old2New.
end())
1835 if (Value2Index.contains(V) || !
I ||
1846 for (
auto &Entry : Stack)
1849 CollectArguments(
Cond, IsSigned);
1852 for (
auto *
P : Args)
1858 Cond->getModule()->getName() +
1859 Cond->getFunction()->getName() +
"repro",
1862 for (
unsigned I = 0;
I < Args.size(); ++
I) {
1864 Old2New[Args[
I]] =
F->getArg(
I);
1869 Builder.CreateRet(Builder.getTrue());
1870 Builder.SetInsertPoint(Entry->getTerminator());
1879 auto &Value2Index = Info.getValue2Index(IsSigned);
1880 while (!WorkList.
empty()) {
1882 if (Old2New.
find(V) != Old2New.
end())
1886 if (!Value2Index.contains(V) &&
I) {
1887 Old2New[V] =
nullptr;
1897 Old2New[
I] = Cloned;
1898 Old2New[
I]->setName(
I->getName());
1910 for (
auto &Entry : Stack) {
1919 auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS);
1920 Builder.CreateAssumption(Cmp);
1925 CloneInstructions(
Cond, IsSigned);
1926 Entry->getTerminator()->setOperand(0,
Cond);
1937 ConstraintInfo &Info,
1939 const auto &Value2Index = Info.getValue2Index(
C.IsSigned);
1940 auto It = Value2Index.find(V);
1941 if (It == Value2Index.end() ||
1943 [Id = It->second](
const Entry &
E) { return E.Id == Id; }))
1949 Value2Index, NewVariables);
1950 return NewVariables.
empty() ? Row : RowTy();
1955 ConstraintInfo &Info) {
1958 auto TryWithConstraint = [&](
const ConstraintTy &R) -> std::optional<bool> {
1961 return std::nullopt;
1964 auto &CSToUse = Info.getCS(R.IsSigned);
1965 if (
auto ImpliedCondition = R.isImpliedBy(CSToUse)) {
1967 return std::nullopt;
1969 dbgs() <<
"Condition ";
1971 *ImpliedCondition ? Pred
1974 dbgs() <<
" implied by dominating constraints\n";
1977 return ImpliedCondition;
1979 return std::nullopt;
1984 auto TryWithLinkedDecomposition =
1985 [&](
const ConstraintTy &
C) -> std::optional<bool> {
1987 return std::nullopt;
1989 auto &CS = Info.getCS(
C.IsSigned);
1990 unsigned NumVars = Info.getValue2Index(
C.IsSigned).size();
1991 unsigned NumPushed = 0;
1996 if (Row.empty() || Negated.empty())
1998 NumPushed += CS.
addRow(Row, NumVars);
1999 NumPushed += CS.
addRow(Negated, NumVars);
2002 return std::nullopt;
2004 std::optional<bool> Res = TryWithConstraint(
C);
2010 auto R = Info.getConstraintForSolving(Pred,
A,
B);
2011 if (
auto ImpliedCondition = TryWithConstraint(R))
2012 return ImpliedCondition;
2013 if (
auto ImpliedCondition = TryWithLinkedDecomposition(R))
2014 return ImpliedCondition;
2022 if (NewVariables.
empty() && !SR.empty() && Info.isKnownNonNegative(
A) &&
2023 Info.isKnownNonNegative(
B))
2024 if (
auto ImpliedCondition = TryWithConstraint(SR))
2025 return ImpliedCondition;
2031 const auto &Value2Index = Info.getValue2Index(
true);
2032 if (!Value2Index.contains(
A) && !Value2Index.contains(
B))
2033 return std::nullopt;
2036 auto SR = Info.getConstraint(Pred,
A,
B, NewVariables,
2038 if (NewVariables.
empty()) {
2039 if (
auto ImpliedCondition = TryWithConstraint(SR))
2040 return ImpliedCondition;
2041 if (
auto ImpliedCondition = TryWithLinkedDecomposition(SR))
2042 return ImpliedCondition;
2045 return std::nullopt;
2050 ConstraintInfo &Info,
unsigned NumIn,
unsigned NumOut,
2054 auto ReplaceCmpWithConstant = [&](
Instruction *CheckInst,
bool IsTrue) {
2056 ReproducerCondStack, Info, DT);
2061 auto *DTN = DT.
getNode(UserI->getParent());
2064 if (UserI->getParent() == ContextInst->
getParent() &&
2065 UserI->comesBefore(ContextInst))
2071 return !
II ||
II->getIntrinsicID() != Intrinsic::assume;
2080 for (
auto *DVR : DVRUsers) {
2081 auto *DTN = DT.
getNode(DVR->getParent());
2085 auto *MarkedI = DVR->getInstruction();
2086 if (MarkedI->getParent() == ContextInst->
getParent() &&
2087 MarkedI->comesBefore(ContextInst))
2090 DVR->replaceVariableLocationOp(CheckInst, ConstantC);
2100 return ReplaceCmpWithConstant(CheckInst, *ImpliedCondition);
2107 return ReplaceCmpWithConstant(CheckInst, *ImpliedCondition);
2116 MinMax->replaceAllUsesWith(
MinMax->getOperand(UseLHS ? 0 : 1));
2125 return ReplaceMinMaxWithOperand(
MinMax, *ImpliedCondition);
2128 return ReplaceMinMaxWithOperand(
MinMax, !*ImpliedCondition);
2137 I->replaceAllUsesWith(ConstantInt::get(
I->getType(), 1));
2147 I->replaceAllUsesWith(ConstantInt::get(
I->getType(), 0));
2165 Value *
Sub = Builder.CreateSub(
A,
B,
"",
true,
2166 Info.isKnownNonNegative(
A));
2168 Sub->takeName(USub);
2175 Module *ReproducerModule,
2178 Info.getDecomposeCache().clear();
2179 Info.popLastConstraint(
E.IsSigned);
2181 auto &Mapping = Info.getValue2Index(
E.IsSigned);
2182 for (
Value *V :
E.ValuesToRelease)
2184 Info.popLastNVariables(
E.IsSigned,
E.ValuesToRelease.size());
2186 if (ReproducerModule)
2193 FactOrCheck &CB, ConstraintInfo &Info,
Module *ReproducerModule,
2202 unsigned OtherOpIdx = JoinOp->
getOperand(0) == CmpToCheck ? 1 : 0;
2210 unsigned OldSize = DFSInStack.
size();
2213 while (OldSize < DFSInStack.
size()) {
2214 StackEntry
E = DFSInStack.
back();
2222 while (!Worklist.empty()) {
2223 Value *Val = Worklist.pop_back_val();
2231 Info.addFact(Pred,
LHS,
RHS, CB.NumIn, CB.NumOut, DFSInStack);
2236 Worklist.push_back(
LHS);
2237 Worklist.push_back(
RHS);
2240 if (OldSize == DFSInStack.
size())
2245 [[maybe_unused]]
bool Matched =
2247 assert(Matched &&
"expected icmp-like match");
2249 if (
auto ImpliedCondition =
checkCondition(Pred,
A,
B, CmpToCheck, Info)) {
2250 if (IsOr == *ImpliedCondition)
2263 unsigned NumIn,
unsigned NumOut,
2264 SmallVectorImpl<StackEntry> &DFSInStack) {
2265 addFactImpl(Pred,
A,
B, NumIn, NumOut, DFSInStack,
false);
2268 addFactImpl(Pred,
A,
B, NumIn, NumOut, DFSInStack,
true);
2270 tightenBoundUsingNe(
A,
B, NumIn, NumOut, DFSInStack);
2273void ConstraintInfo::tightenBoundUsingNe(
2275 SmallVectorImpl<StackEntry> &DFSInStack) {
2276 if (!
A->getType()->isIntOrPtrTy())
2279 for (
bool IsSigned : {
false,
true}) {
2286 const auto &Value2Index = getValue2Index(IsSigned);
2288 [&Value2Index](
const DecompEntry &
E) {
2289 return !Value2Index.contains(
E.Variable);
2300 if (!doesHold(NonStrict,
A,
B))
2306 dbgs() <<
"' using inequality\n");
2307 addFactImpl(
Strict,
A,
B, NumIn, NumOut, DFSInStack,
2315 unsigned NumIn,
unsigned NumOut,
2316 SmallVectorImpl<StackEntry> &DFSInStack,
2317 bool ForceSignedSystem) {
2319 auto R = getConstraint(Pred,
A,
B, NewVariables, ForceSignedSystem);
2322 if (
R.empty() ||
R.isNe())
2325 auto &CSToUse = getCS(
R.IsSigned);
2329 if (!
R.isEq() && NewVariables.
empty()) {
2331 if (CSToUse.isImpliedBySingleRow(
R.Coefficients))
2336 bool Added = CSToUse.addRow(
R.Coefficients,
R.NumVars);
2340 DecomposeCache.
clear();
2344 SmallVector<Value *, 2> ValuesToRelease;
2345 auto &Value2Index = getValue2Index(
R.IsSigned);
2346 for (
Value *V : NewVariables) {
2347 Value2Index.try_emplace(V, Value2Index.size() + 1);
2352 dbgs() <<
" constraint: ";
2358 std::move(ValuesToRelease));
2361 for (
Value *V : NewVariables) {
2363 CSToUse.addRow({
Entry(0, 0),
Entry(-1, Value2Index.at(V))},
2364 Value2Index.size());
2366 SmallVector<Value *, 2>());
2372 for (Entry &
E :
R.Coefficients)
2375 CSToUse.addRow(
R.Coefficients,
R.NumVars);
2378 SmallVector<Value *, 2>());
2388 Value *Res =
nullptr;
2392 Res = Builder.CreateNoWrapBinOp(
II->getBinaryOp(),
II->getLHS(),
2399 U->replaceAllUsesWith(Builder.getFalse());
2404 if (U->use_empty()) {
2412 if (
II->use_empty()) {
2414 for (
Use &Arg :
II->args())
2438 ConstraintInfo Info(
F.getDataLayout(), FunctionArgs);
2439 State S(DT, LI, SE, TLI);
2440 std::unique_ptr<Module> ReproducerModule(
2441 Opts.constraint_elimination_dump_reproducers
2442 ?
new Module(
F.getName(),
F.getContext())
2461 stable_sort(S.WorkList, [](
const FactOrCheck &
A,
const FactOrCheck &
B) {
2462 auto HasNoConstOp = [](const FactOrCheck &B) {
2463 Value *V0 = B.isConditionFact() ? B.Cond.Op0 : B.Inst->getOperand(0);
2464 Value *V1 = B.isConditionFact() ? B.Cond.Op1 : B.Inst->getOperand(1);
2465 return !isa<ConstantInt>(V0) && !isa<ConstantInt>(V1);
2469 if (
A.NumIn ==
B.NumIn) {
2470 if (A.isConditionFact() && B.isConditionFact()) {
2471 bool NoConstOpA = HasNoConstOp(A);
2472 bool NoConstOpB = HasNoConstOp(B);
2473 return NoConstOpA < NoConstOpB;
2475 if (
A.isConditionFact())
2477 if (
B.isConditionFact())
2479 auto *InstA =
A.getContextInst();
2480 auto *InstB =
B.getContextInst();
2481 return InstA->comesBefore(InstB);
2483 return A.NumIn <
B.NumIn;
2486 SmallVector<Instruction *>
ToRemove;
2491 for (FactOrCheck &CB : S.WorkList) {
2494 while (!DFSInStack.
empty()) {
2495 auto &
E = DFSInStack.
back();
2498 LLVM_DEBUG(
dbgs() <<
"CB: " << CB.NumIn <<
" " << CB.NumOut <<
"\n");
2500 if (CB.NumOut <=
E.NumOut)
2503 dbgs() <<
"Removing ";
2505 Info.getValue2Index(
E.IsSigned));
2517 Instruction *Inst = CB.getInstructionToSimplify();
2524 LLVM_DEBUG(
dbgs() <<
"Processing condition to simplify: " << *Inst
2530 Pred,
A,
B, Inst, Info, CB.NumIn, CB.NumOut, CB.getContextInst(),
2531 ReproducerModule.get(), ReproducerCondStack, S.DT,
ToRemove);
2535 CB, Info, ReproducerModule.get(), ReproducerCondStack, DFSInStack,
2550 auto AddFact = [&](CmpPredicate Pred,
Value *
A,
Value *
B) {
2554 Opts.constraint_elimination_max_rows) {
2557 <<
"Skip adding constraint because system has too many rows.\n");
2561 Info.addFact(Pred,
A,
B, CB.NumIn, CB.NumOut, DFSInStack);
2562 if (ReproducerModule && DFSInStack.
size() > ReproducerCondStack.
size())
2571 CB.NumIn, CB.NumOut, DFSInStack);
2573 Info.transferToOtherSystem(Pred,
A,
B, CB.NumIn, CB.NumOut,
2587 SmallPtrSet<Value *, 4> Seen;
2588 while (!Worklist.
empty()) {
2591 if (!BO || BO->getOpcode() !=
Opc)
2593 for (
Value *
Op : {BO->getOperand(0), BO->getOperand(1)}) {
2597 Info.addFact(Pred,
Op,
B, CB.NumIn, CB.NumOut, DFSInStack);
2602 if (ReproducerModule && DFSInStack.
size() > ReproducerCondStack.
size()) {
2605 for (
unsigned I = 0,
2606 E = (DFSInStack.
size() - ReproducerCondStack.
size());
2608 ReproducerCondStack.
emplace_back(ICmpInst::BAD_ICMP_PREDICATE,
2614 if (!CB.isConditionFact()) {
2620 ConstantInt::get(CB.Inst->getType(), 0));
2626 Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
2627 AddFact(Pred, MinMax, MinMax->getLHS());
2628 AddFact(Pred, MinMax, MinMax->getRHS());
2632 switch (USatI->getIntrinsicID()) {
2635 case Intrinsic::uadd_sat:
2636 AddFact(ICmpInst::ICMP_UGE, USatI, USatI->getLHS());
2637 AddFact(ICmpInst::ICMP_UGE, USatI, USatI->getRHS());
2639 case Intrinsic::usub_sat:
2640 AddFact(ICmpInst::ICMP_ULE, USatI, USatI->getLHS());
2647 if (BO->getOpcode() == Instruction::URem) {
2654 if (BO->getOpcode() == Instruction::UDiv) {
2659 if (BO->getOpcode() == Instruction::LShr) {
2664 if (BO->getOpcode() == Instruction::SRem) {
2665 Value *
X = BO->getOperand(0);
2666 Value *
N = BO->getOperand(1);
2684 if (BO->getOpcode() == Instruction::SDiv) {
2685 Value *
X = BO->getOperand(0);
2686 Value *
N = BO->getOperand(1);
2687 if (!
Info.isKnownNonNegative(
X) || !
Info.isKnownPositive(
N))
2690 bool IsStrict =
Info.isKnownPositive(
X) &&
2692 ConstantInt::get(
N->getType(), 1));
2699 auto &
DL =
F.getDataLayout();
2700 auto AddFactsAboutIndices = [&](
Value *Ptr,
Type *AccessType) {
2705 DL.getTypeStoreSize(AccessType).getFixedValue(), Pred,
A,
B,
DL,
2707 AddFact(Pred,
A,
B);
2711 AddFactsAboutIndices(LI->getPointerOperand(), LI->getAccessType());
2715 AddFactsAboutIndices(
SI->getPointerOperand(),
SI->getAccessType());
2720 if (CB.isConditionFact()) {
2721 Pred = CB.Cond.Pred;
2725 !
Info.doesHold(CB.DoesHold.Pred, CB.DoesHold.Op0, CB.DoesHold.Op1)) {
2727 dbgs() <<
"Not adding fact ";
2729 dbgs() <<
" because precondition ";
2732 dbgs() <<
" does not hold.\n";
2737 [[maybe_unused]]
bool Matched =
2741 "Must have an assume intrinsic with a icmp like operand");
2743 AddFact(Pred,
A,
B);
2746 if (ReproducerModule && !ReproducerModule->functions().empty()) {
2748 raw_string_ostream StringS(S);
2749 ReproducerModule->print(StringS,
nullptr);
2750 OptimizationRemark Rem(
DEBUG_TYPE,
"Reproducer", &
F);
2751 Rem <<
ore::NV(
"module") << S;
2756 unsigned SignedEntries =
2757 count_if(DFSInStack, [](
const StackEntry &
E) {
return E.IsSigned; });
2758 assert(
Info.getCS(
false).size() - FunctionArgs.size() ==
2759 DFSInStack.
size() - SignedEntries &&
2760 "updates to CS and DFSInStack are out of sync");
2761 assert(
Info.getCS(
true).size() == SignedEntries &&
2762 "updates to CS and DFSInStack are out of sync");
2766 I->eraseFromParent();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static const Function * getParent(const Value *V)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
std::pair< ICmpInst *, unsigned > ConditionTy
static int64_t MaxConstraintValue
static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI, ScalarEvolution *SE, OptimizationRemarkEmitter &ORE, TargetLibraryInfo &TLI)
static bool canStrengthenFlags(Instruction *I)
Returns true if I is a candidate whose poison-generating flags may be strengthened using the constrai...
static bool doesHoldInRange(ConstraintInfo &Info, Value *Op, const ConstantRange &R, bool Signed)
Returns true if Info implies that Op is in R, interpreting R as a signed range if Signed is set and a...
static RowTy getDecompositionLinkRow(Value *V, const ConstraintTy &C, ConstraintInfo &Info, const DataLayout &DL)
If V is a variable in the system and constraint C does not contain V, we managed to decompose V at th...
static int64_t MinSignedConstraintValue
static bool tryToSimplifyOverflowMath(WithOverflowInst *II, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
static auto m_IncrementOf(const PhiMatchTy &PhiM, const APInt *&Off)
Matches an increment of PhiM by a constant offset, captured in Off.
static Instruction * getContextInstForUse(Use &U)
static bool isKnownNoWrap(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1, unsigned NoWrapFlags, ConstraintInfo &Info, bool Signed)
Returns true if Opcode applied to Op0 and Op1 with NoWrapFlags is known to not wrap in signed or unsi...
static bool mayLookThrough(Value *V)
Returns true if V is an operation decomposeImpl can look through.
static bool canUseSExt(ConstantInt *CI)
static void removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info, Module *ReproducerModule, SmallVectorImpl< ReproducerEntry > &ReproducerCondStack, SmallVectorImpl< StackEntry > &DFSInStack)
static std::optional< bool > checkCondition(CmpInst::Predicate Pred, Value *A, Value *B, Instruction *CheckInst, ConstraintInfo &Info)
static Decomposition decompose(Value *V, ConstraintInfo &Info, bool IsSigned, const DataLayout &DL)
static bool checkOrAndOpImpliedByOther(FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule, SmallVectorImpl< ReproducerEntry > &ReproducerCondStack, SmallVectorImpl< StackEntry > &DFSInStack, SmallVectorImpl< Instruction * > &ToRemove)
Check if either the first condition of an AND or OR is implied by the (negated in case of OR) second ...
static OffsetResult collectOffsets(GEPOperator &GEP, const DataLayout &DL)
static bool checkAndReplaceMinMax(MinMaxIntrinsic *MinMax, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
static bool tryToStrengthenFlags(Instruction *I, ConstraintInfo &Info)
Try to strengthen I's poison generating flags using Info.
static RowTy getRowForLessEqual(const Decomposition &ADec, const Decomposition &BDec, const DenseMap< Value *, unsigned > &Value2Index, SmallVectorImpl< Value * > &NewVariables)
Build the row for 'ADec <= BDec', using the indices from Value2Index.
static void dumpConstraint(ArrayRef< Entry > C, const DenseMap< Value *, unsigned > &Value2Index)
static bool replaceOverflowUses(WithOverflowInst *II, SmallVectorImpl< Instruction * > &ToRemove)
Replace the uses of II, which is known not to overflow, by the corresponding plain binary operation a...
static bool getConstraintFromMemoryAccess(GetElementPtrInst &GEP, uint64_t AccessSize, CmpPredicate &Pred, Value *&A, Value *&B, const DataLayout &DL, const TargetLibraryInfo &TLI)
static void dumpUnpackedICmp(raw_ostream &OS, ICmpInst::Predicate Pred, Value *LHS, Value *RHS)
static void generateReproducer(Instruction *Cond, bool IsSigned, Module *M, ArrayRef< ReproducerEntry > Stack, ConstraintInfo &Info, DominatorTree &DT)
Helper function to generate a reproducer function for simplifying Cond.
static bool checkAndReplaceUSubSat(SaturatingInst *USub, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
Try to replace USub by a plain subtract, if Info proves it cannot saturate.
static bool checkAndReplaceCondition(CmpPredicate Pred, Value *A, Value *B, Instruction *CheckInst, ConstraintInfo &Info, unsigned NumIn, unsigned NumOut, Instruction *ContextInst, Module *ReproducerModule, ArrayRef< ReproducerEntry > ReproducerCondStack, DominatorTree &DT, SmallVectorImpl< Instruction * > &ToRemove)
static Instruction * findCommonDominatorOfUses(Instruction &I, DominatorTree &DT)
Returns the closest program point dominating all uses of I.
static Decomposition decomposeImpl(Value *V, ConstraintInfo &Info, bool IsSigned, const DataLayout &DL)
static bool checkAndReplaceCmp(CmpIntrinsic *I, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
static std::pair< Value *, Value * > getStartAndBackedgeValue(const PHINode &PN, const BasicBlock *LoopPred)
Splits the induction phi PN into the start value, coming from the loop predecessor LoopPred,...
static Decomposition decomposeGEP(GEPOperator &GEP, ConstraintInfo &Info, bool IsSigned, const DataLayout &DL)
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
This is the interface for a simple mod/ref and alias analysis over globals.
Module.h This file contains the declarations for the Module class.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
uint64_t IntrinsicInst * II
This file defines the PointerIntPair class.
static StringRef getName(Value *V)
const SmallVectorImpl< MachineOperand > & Cond
This file defines the scope_exit class, which executes user-defined cleanup logic at scope exit.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Class for arbitrary precision integers.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool sgt(const APInt &RHS) const
Signed greater than comparison.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
static APInt getMinValue(unsigned numBits)
Gets minimum unsigned value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
bool slt(const APInt &RHS) const
Signed less than comparison.
bool isOne() const
Determine if this is a value of 1.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this basic block belongs to.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Represents analyses that only rely on functions' control flow.
static Type * makeCmpResultType(Type *opnd_type)
Create a result type for fcmp/icmp.
Predicate getStrictPredicate() const
For example, SGE -> SGT, SLE -> SLT, ULE -> ULT, UGE -> UGT.
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ ICMP_ULT
unsigned less than
@ ICMP_SGE
signed greater or equal
@ ICMP_ULE
unsigned less or equal
static LLVM_ABI bool isEquality(Predicate pred)
Determine if this is an equals/not equals predicate.
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getNonStrictPredicate() const
For example, SGT -> SGE, SLT -> SLE, ULT -> ULE, UGT -> UGE.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
This class represents a ucmp/scmp intrinsic.
An abstraction over a floating-point predicate, and a pack of an integer predicate with samesign info...
static LLVM_ABI CmpPredicate getInverse(CmpPredicate P)
Get the inverse predicate of a CmpPredicate.
CmpInst::Predicate dropSameSign() const
Drops samesign information.
bool hasSameSign() const
Query samesign information, for optimizations.
This is the shared class of boolean and integer constants.
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
const APInt & getValue() const
Return the constant as an APInt value reference.
static LLVM_ABI ConstantInt * getBool(LLVMContext &Context, bool V)
This class represents a range of values.
static LLVM_ABI ConstantRange makeExactNoWrapRegion(Instruction::BinaryOps BinOp, const APInt &Other, unsigned NoWrapKind)
Produce the range that contains X if and only if "X BinOp Other" does not wrap.
This is an important base class in LLVM.
static LLVM_ABI Constant * getAllOnesValue(Type *Ty)
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &)
bool addRow(ArrayRef< Entry > R, size_t NumVars)
static RowTy negate(RowTy R)
LLVM_ABI std::pair< ConstraintSystem, RowTy > getSubSystem(ArrayRef< Entry > R) const
Build and return a sub-system of constraints connected (transitively) to query R, with variables comp...
static RowTy toStrictLessThan(RowTy R)
Converts the given row to form a strict less than inequality.
static LLVM_ABI void normalizeByGCD(MutableArrayRef< Entry > R)
Divide the variable coefficients of R by their greatest common divisor G and round the constant down ...
SmallVector< Entry, 8 > RowTy
A single constraint of the form 'c >= v1 * c1 + ... + vn * cn'.
static RowTy negateOrEqual(RowTy R)
Multiplies each coefficient in the given row by -1.
LLVM_ABI void dump() const
Print the constraints in the system.
A parsed version of the target data layout string in and methods for querying it.
static bool shouldExecute(CounterInfo &Counter)
iterator find(const_arg_type_t< KeyT > Val)
unsigned getDFSNumIn() const
getDFSNumIn/getDFSNumOut - These return the DFS visitation order for nodes in the dominator tree.
unsigned getDFSNumOut() const
Analysis pass which computes a DominatorTree.
void updateDFSNumbers() const
updateDFSNumbers - Assign In and Out numbers to the nodes while walking dominator tree in dfs order.
DomTreeNodeBase< NodeT > * getNode(const NodeT *BB) const
getNode - return the (Post)DominatorTree node for the specified basic block.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI Instruction * findNearestCommonDominator(Instruction *I1, Instruction *I2) const
Find the nearest instruction I that dominates both I1 and I2, in the sense that a result produced bef...
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
static GEPNoWrapFlags none()
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
@ ExternalLinkage
Externally visible function.
static bool isLT(Predicate P)
Return true if the predicate is SLT or ULT.
Predicate getFlippedSignednessPredicate() const
For example, SLT->ULT, ULT->SLT, SLE->ULE, ULE->SLE, EQ->EQ.
Predicate getSignedPredicate() const
For example, EQ->EQ, SLE->SLE, UGT->SGT, etc.
bool isRelational() const
Return true if the predicate is relational (not EQ or NE).
Predicate getUnsignedPredicate() const
For example, EQ->EQ, SLE->ULE, UGT->UGT, etc.
static bool isLE(Predicate P)
Return true if the predicate is SLE or ULE.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI void dropUnknownNonDebugMetadata(ArrayRef< unsigned > KnownIDs={})
Drop all unknown metadata except for debug locations.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
This is an important class for using LLVM in a threaded context.
Analysis pass that exposes the LoopInfo for a function.
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
This class represents min/max intrinsics.
A Module instance is used to store all the information related to an LLVM module.
Utility class for integer operators which may exhibit overflow - Add, Sub, Mul, and Shl.
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
int getBasicBlockIndex(const BasicBlock *BB) const
Return the first index of the specified basic block in the value list for this PHI.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
PointerIntPair - This class implements a pair of a pointer and small integer.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Represents a saturating add/sub intrinsic.
Analysis pass that exposes the ScalarEvolution for a function.
The main scalar evolution driver.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEVFlags Flags=SCEV::FlagNone, unsigned Depth=0)
Return LHS-RHS.
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI bool isSCEVable(Type *Ty) const
Test if values of the given type are analyzable within the SCEV framework.
MonotonicPredicateType
A predicate is said to be monotonically increasing if may go from being false to being true as the lo...
@ MonotonicallyDecreasing
@ MonotonicallyIncreasing
LLVM_ABI APInt getConstantMultiple(const SCEV *S, const Instruction *CtxI=nullptr)
Returns the max constant multiple of S.
LLVM_ABI std::optional< MonotonicPredicateType > getMonotonicPredicateType(const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred)
If, for all loop invariant X, the predicate "LHS `Pred` X" is monotonically increasing or decreasing,...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void truncate(size_type N)
Like resize, but requires that N is less than size().
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
bool isIntegerTy() const
True if this is an instance of IntegerType.
A Use represents the edge between a Value definition and its users.
Value * getOperand(unsigned i) const
iterator find(const KeyT &Val)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI const Value * stripPointerCastsSameRepresentation() const
Strip off pointer casts, all-zero GEPs and address space casts but ensures the representation of the ...
LLVM_ABI bool replaceUsesWithIf(Value *New, llvm::function_ref< bool(Use &U)> ShouldReplace)
Go through the uses list for this definition and make each use point to "V" if the callback ShouldRep...
Represents an op.with.overflow intrinsic.
constexpr ScalarTy getFixedValue() const
constexpr bool isFixed() const
Returns true if the quantity is not scaled by vscale.
const ParentTy * getParent() const
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BasicBlock
Various leaf nodes.
AllOnesConstantMatch m_AllOnes()
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
match_combine_or< Ty... > m_CombineOr(const Ty &...Ps)
Combine pattern matchers matching any of Ps patterns.
match_bind< PHINode > m_Phi(PHINode *&PN)
Match a PHI node, capturing it if we match.
auto m_LogicalOp()
Matches either L && R or L || R where L and R are arbitrary values.
CommutativeBinaryIntrinsic_match< IntrID, T0, T1 > m_c_Intrinsic(const T0 &Op0, const T1 &Op1)
ap_match< APInt > m_APInt(const APInt *&Res)
Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
DisjointOr_match< LHS, RHS > m_DisjointOr(const LHS &L, const RHS &R)
BinOpPred_match< LHS, RHS, is_right_shift_op > m_Shr(const LHS &L, const RHS &R)
Matches logical shift operations.
CmpClass_match< LHS, RHS, ICmpInst, true > m_c_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
Matches an ICmp with a predicate over LHS and RHS in either order.
ExtractValue_match< Ind, Val_t > m_ExtractValue(const Val_t &V)
Match a single index ExtractValue instruction.
ICmpLike_match< LHS, RHS > m_ICmpLike(CmpPredicate &Pred, const LHS &L, const RHS &R)
auto m_Value()
Match an arbitrary value and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
CastInst_match< OpTy, ZExtInst > m_ZExt(const OpTy &Op)
Matches ZExt.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
BinaryOp_match< LHS, RHS, Instruction::Add, true > m_c_Add(const LHS &L, const RHS &R)
Matches a Add with LHS and RHS in either order.
match_combine_or< BinaryOp_match< LHS, RHS, Instruction::Add >, DisjointOr_match< LHS, RHS > > m_AddLike(const LHS &L, const RHS &R)
Match either "add" or "or disjoint".
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
Exact_match< T > m_Exact(const T &SubPattern)
LogicalOp_match< LHS, RHS, Instruction::And, true > m_c_LogicalAnd(const LHS &L, const RHS &R)
Matches L && R with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)
Matches SExt.
LogicalOp_match< LHS, RHS, Instruction::Or, true > m_c_LogicalOr(const LHS &L, const RHS &R)
Matches L || R with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Sub > m_Sub(const LHS &L, const RHS &R)
auto m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
bind_cst_ty m_scev_APInt(const APInt *&C)
Match an SCEV constant and bind it to an APInt.
specificloop_ty m_SpecificLoop(const Loop *L)
bool match(const SCEV *S, const Pattern &P)
SCEVAffineAddRec_match< Op0_t, Op1_t, match_isa< const Loop > > m_scev_AffineAddRec(const Op0_t &Op0, const Op1_t &Op1)
@ Switch
The "resume-switch" lowering, where there are separate resume and destroy functions that are shared b...
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
void stable_sort(R &&Range)
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI bool verifyFunction(const Function &F, raw_ostream *OS=nullptr)
Check a function for errors, useful for use when debugging a pass.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
constexpr std::enable_if_t< std::is_signed_v< T >, std::pair< T, bool > > AddOverflow(T X, T Y)
Add two signed integers, computing the two's complement truncated result, returning a pair {result,...
const ScalarOptions & getScalarOptions(const LLVMContext &C)
LLVM_ABI std::optional< TypeSize > getBaseObjectSize(const Value *Ptr, const DataLayout &DL, const TargetLibraryInfo *TLI, ObjectSizeOpts Opts={})
Like getObjectSize(), but only returns the size of base objects (like allocas, global variables and a...
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
DomTreeNodeBase< BasicBlock > DomTreeNode
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
constexpr std::enable_if_t< std::is_signed_v< T >, std::pair< T, bool > > SubOverflow(T X, T Y)
Subtract two signed integers, computing the two's complement truncated result, returning a pair {resu...
constexpr unsigned MaxAnalysisRecursionDepth
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
LLVM_ABI void remapInstructionsInBlocks(ArrayRef< BasicBlock * > Blocks, ValueToValueMapTy &VMap)
Remaps instructions in Blocks using the mapping in VMap.
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr unsigned BitWidth
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI bool isGuaranteedToTransferExecutionToSuccessor(const Instruction *I)
Return true if this function can prove that the instruction I will always transfer execution to one o...
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
constexpr std::enable_if_t< std::is_signed_v< T >, std::pair< T, bool > > MulOverflow(T X, T Y)
Multiply two signed integers, computing the two's complement truncated result, returning a pair {resu...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI bool isGuaranteedNotToBePoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Returns true if V cannot be poison, but may be undef.
LLVM_ABI bool isKnownPositive(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Returns true if the given value is known be positive (i.e.
LLVM_ABI bool isKnownNonNegative(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Returns true if the give value is known to be non-negative.
LLVM_ABI void findDbgUsers(Value *V, SmallVectorImpl< DbgVariableRecord * > &DbgVariableRecords)
Finds the debug info records describing a value.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Various options to control the behavior of getObjectSize.
bool NullIsUnknownSize
If this is true, null pointers in address space 0 will be treated as though they can't be evaluated.
bool RoundToAlign
Whether to round the result up to the alignment of allocas, byval arguments, and global variables.
A MapVector that performs no allocations if smaller than a certain size.