55#define DEBUG_TYPE "constraint-elimination"
57STATISTIC(NumCondsRemoved,
"Number of instructions removed");
59 "Controls which conditions are eliminated");
63 cl::desc(
"Maximum number of rows to keep in constraint system"));
67 cl::desc(
"Dump IR to reproduce successful transformations."));
75 UserI = Phi->getIncomingBlock(U)->getTerminator();
84 for (
Use &U :
I.uses()) {
105 Value *Op0 =
nullptr;
106 Value *Op1 =
nullptr;
110 : Pred(Pred), Op0(Op0), Op1(Op1) {}
148 FactOrCheck(EntryTy Ty,
DomTreeNode *DTN, Instruction *Inst,
149 Instruction *ContextInst =
nullptr)
150 : Inst(Inst), ContextInst(ContextInst ? ContextInst : Inst),
151 NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), Ty(Ty) {}
154 :
U(
U), ContextInst(nullptr), NumIn(DTN->getDFSNumIn()),
155 NumOut(DTN->getDFSNumOut()), Ty(EntryTy::UseCheck) {}
159 :
Cond(Pred, Op0, Op1), DoesHold(Precond), NumIn(DTN->getDFSNumIn()),
160 NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {}
162 static FactOrCheck getConditionFact(
DomTreeNode *DTN, CmpPredicate Pred,
165 return FactOrCheck(DTN, Pred, Op0, Op1, Precond);
168 static FactOrCheck getInstFact(
DomTreeNode *DTN, Instruction *Inst) {
169 return FactOrCheck(EntryTy::InstFact, DTN, Inst);
172 static FactOrCheck getCheck(
DomTreeNode *DTN, Use *U) {
173 return FactOrCheck(DTN, U);
176 static FactOrCheck getCheck(
DomTreeNode *DTN, Instruction *
I,
177 Instruction *ContextInst =
nullptr) {
179 "anchoring instruction must be in DTN's block");
180 return FactOrCheck(EntryTy::InstCheck, DTN,
I, ContextInst);
183 bool isCheck()
const {
184 return Ty == EntryTy::InstCheck || Ty == EntryTy::UseCheck;
188 assert(!isConditionFact());
189 if (Ty == EntryTy::UseCheck)
196 if (Ty == EntryTy::InstCheck)
202 bool isConditionFact()
const {
return Ty == EntryTy::ConditionFact; }
207struct MonotonicInfo {
209 bool Decreasing =
false;
211 bool Unsigned =
false;
221 TargetLibraryInfo &TLI;
224 State(DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE,
225 TargetLibraryInfo &TLI)
226 : DT(DT), LI(LI), SE(SE), TLI(TLI) {}
229 void addInfoFor(BasicBlock &BB);
233 void addBoundsForHeaderInductions(BasicBlock &BB);
237 void addInfoForInductions(BasicBlock &BB);
241 MonotonicInfo getMonotonicityInfo(PHINode &PN,
Value *Step);
245 bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ)
const {
246 return DT.dominates(BasicBlockEdge(&BB, Succ), Succ);
255 bool IsSigned =
false;
258 SmallVector<Value *, 2> ValuesToRelease;
260 StackEntry(
unsigned NumIn,
unsigned NumOut,
bool IsSigned,
261 SmallVector<Value *, 2> ValuesToRelease)
262 : NumIn(NumIn), NumOut(NumOut), IsSigned(IsSigned),
263 ValuesToRelease(std::
move(ValuesToRelease)) {}
270 unsigned NumVars = 0;
272 bool IsSigned =
false;
274 ConstraintTy() =
default;
276 ConstraintTy(RowTy Coefficients,
unsigned NumVars,
bool IsSigned,
bool IsEq,
278 : Coefficients(std::
move(Coefficients)), NumVars(NumVars),
279 IsSigned(IsSigned), IsEq(IsEq), IsNe(IsNe) {}
281 bool empty()
const {
return Coefficients.empty(); }
283 bool isEq()
const {
return IsEq; }
285 bool isNe()
const {
return IsNe; }
292 std::optional<bool> isImpliedBy(
const ConstraintSystem &CS)
const;
304 DecompEntry(int64_t Coefficient,
Value *Variable)
305 : Coefficient(Coefficient), Variable(Variable) {}
309struct Decomposition {
313 Decomposition(int64_t Offset) : Offset(Offset) {}
314 Decomposition(
Value *V) { Vars.emplace_back(1, V); }
316 : Offset(Offset), Vars(Vars) {}
320 [[nodiscard]]
bool add(int64_t OtherOffset) {
326 [[nodiscard]]
bool add(
const Decomposition &
Other) {
335 [[nodiscard]]
bool sub(
const Decomposition &
Other) {
336 Decomposition Tmp =
Other;
347 [[nodiscard]]
bool mul(int64_t Factor) {
350 for (
auto &Var : Vars)
351 if (
MulOverflow(Var.Coefficient, Factor, Var.Coefficient))
363class ConstraintInfo {
365 ConstraintSystem UnsignedCS;
366 ConstraintSystem SignedCS;
368 const DataLayout &DL;
372 DenseMap<PointerIntPair<Value *, 1, bool>, Decomposition> DecomposeCache;
375 DenseMap<PointerIntPair<Value *, 1, bool>, Decomposition> &
376 getDecomposeCache() {
377 return DecomposeCache;
381 : UnsignedCS(FunctionArgs), SignedCS(FunctionArgs), DL(DL) {
382 auto &Value2Index = getValue2Index(
false);
384 for (
Value *Arg : FunctionArgs)
385 UnsignedCS.addRow({
Entry(0, 0),
Entry(-1, Value2Index.at(Arg))},
389 DenseMap<Value *, unsigned> &getValue2Index(
bool Signed) {
390 return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
392 const DenseMap<Value *, unsigned> &getValue2Index(
bool Signed)
const {
393 return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
396 ConstraintSystem &getCS(
bool Signed) {
397 return Signed ? SignedCS : UnsignedCS;
399 const ConstraintSystem &getCS(
bool Signed)
const {
400 return Signed ? SignedCS : UnsignedCS;
403 void popLastConstraint(
bool Signed) {
404 assert(DecomposeCache.empty() &&
"Cache must be cleared");
405 getCS(
Signed).popLastConstraint();
407 void popLastNVariables(
bool Signed,
unsigned N) {
408 assert(DecomposeCache.empty() &&
"Cache must be cleared");
409 getCS(
Signed).popLastNVariables(
N);
423 unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack);
430 SmallVectorImpl<Value *> &NewVariables,
431 bool ForceSignedSystem =
false);
446 unsigned NumIn,
unsigned NumOut,
447 SmallVectorImpl<StackEntry> &DFSInStack);
454 unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack,
455 bool ForceSignedSystem);
459 void tightenBoundUsingNe(
Value *
A,
Value *
B,
unsigned NumIn,
unsigned NumOut,
460 SmallVectorImpl<StackEntry> &DFSInStack);
466 APInt ConstantOffset;
467 SmallMapVector<Value *, APInt, 4> VariableOffsets;
472 OffsetResult(GEPOperator &
GEP,
const DataLayout &
DL)
474 ConstantOffset = APInt(
DL.getIndexTypeSizeInBits(
BasePtr->getType()), 0);
484 unsigned BitWidth = Result.ConstantOffset.getBitWidth();
486 Result.ConstantOffset))
494 bool CanCollectInner = InnerGEP->collectOffset(
495 DL,
BitWidth, VariableOffsets2, ConstantOffset2);
497 if (!CanCollectInner || Result.VariableOffsets.size() > 1 ||
498 VariableOffsets2.
size() > 1 ||
499 (Result.VariableOffsets.size() >= 1 && VariableOffsets2.
size() >= 1)) {
503 Result.BasePtr = InnerGEP->getPointerOperand();
504 Result.ConstantOffset += ConstantOffset2;
505 if (Result.VariableOffsets.size() == 0 && VariableOffsets2.
size() == 1)
506 Result.VariableOffsets = std::move(VariableOffsets2);
507 Result.NW &= InnerGEP->getNoWrapFlags();
512static Decomposition
decompose(
Value *V, ConstraintInfo &Info,
bool IsSigned,
524 if (R.isEmptySet() || (
Signed ? R.isSignWrappedSet() : R.isWrappedSet()))
530 unsigned BitWidth = R.getBitWidth();
531 APInt Min =
Signed ? R.getSignedMin() : R.getUnsignedMin();
532 APInt Max =
Signed ? R.getSignedMax() : R.getUnsignedMax();
544 ConstantInt::get(Ty, Min)))
548 ConstantInt::get(Ty, Max)))
556 unsigned NoWrapFlags, ConstraintInfo &Info,
560 if (NoWrapFlags & (
Signed ? OBO::NoSignedWrap : OBO::NoUnsignedWrap))
563 if (Opcode == Instruction::Sub) {
569 if (Info.isKnownNonNegative(Op1) &&
574 if (!
Signed && (NoWrapFlags & OBO::NoSignedWrap) &&
575 (Opcode == Instruction::Shl || Info.isKnownNonNegative(Op1)) &&
576 Info.isKnownNonNegative(Op0))
587 Opcode,
C->getValue(),
588 Signed ? OBO::NoSignedWrap : OBO::NoUnsignedWrap),
599 return isKnownNoWrap(WO->getBinaryOp(), WO->getLHS(), WO->getRHS(),
604 return Trunc->hasNoSignedWrap();
608 return Trunc->hasNoUnsignedWrap() ||
609 (Trunc->hasNoSignedWrap() &&
610 Info.isKnownNonNegative(Trunc->getOperand(0)));
616 BO->getOperand(0), BO->getOperand(1),
617 BO->getNoWrapKind(), Info,
Signed);
624 if (
DL.getIndexTypeSizeInBits(
GEP.getPointerOperand()->getType()) > 64)
627 assert(!IsSigned &&
"The logic below only supports decomposition for "
628 "unsigned predicates at the moment.");
629 const auto &[BasePtr, ConstantOffset, VariableOffsets, NW] =
638 if (!NW.hasNoUnsignedSignedWrap() && ConstantOffset.isNegative())
641 Decomposition Result(ConstantOffset.getSExtValue(), DecompEntry(1, BasePtr));
642 for (
auto [Index, Scale] : VariableOffsets) {
643 if (!NW.hasNoUnsignedWrap()) {
646 assert(NW.hasNoUnsignedSignedWrap() &&
"Must have nusw flag");
647 if (!Info.isKnownNonNegative(Index))
651 auto IdxResult =
decompose(Index, Info, IsSigned,
DL);
652 if (IdxResult.mul(Scale.getSExtValue()))
654 if (Result.add(IdxResult))
674 switch (
Op->getOpcode()) {
675 case Instruction::GetElementPtr:
676 case Instruction::Add:
677 case Instruction::Sub:
678 case Instruction::Mul:
679 case Instruction::Shl:
680 case Instruction::ZExt:
681 case Instruction::SExt:
682 case Instruction::Trunc:
683 case Instruction::Or:
684 case Instruction::Xor:
697 auto &Cache = Info.getDecomposeCache();
698 auto It = Cache.find(
Key);
699 if (It != Cache.end())
703 Info.getDecomposeCache().insert({
Key, Result});
709 auto MergeResults = [&Info, IsSigned,
711 bool IsSignedB) -> std::optional<Decomposition> {
720 if (Ty->isPointerTy() && !IsSigned) {
732 if (!Ty->isIntegerTy() || Ty->getIntegerBitWidth() > 64)
738 return CI->getSExtValue();
740 return int64_t(CI->getZExtValue());
756 if (!IsSigned && !Info.isKnownNonNegative(Op0))
760 if (Trunc->getSrcTy()->getScalarSizeInBits() <= 64 &&
762 V = Trunc->getOperand(0);
767 if (
auto Decomp = MergeResults(Op0, Op1, IsSigned))
777 if (
auto Decomp = MergeResults(Op0, CI,
true))
784 Decomposition Result(-1);
785 if (!Result.sub(
decompose(Op0, Info, IsSigned,
DL)))
816 int64_t MaxShift = IsSigned ? Ty->getIntegerBitWidth() - 1 : 63;
834 const Decomposition &BDec,
840 if (
SubOverflow(BDec.Offset, ADec.Offset, OffsetSum))
842 RowTy R(1, Entry(OffsetSum, 0));
843 auto GetCoefficient = [&R](
unsigned Idx) -> int64_t & {
848 if (
I == R.end() ||
I->Id != Idx)
849 I = R.insert(
I, Entry(0, Idx));
850 return I->Coefficient;
854 auto GetOrAddIndex = [&Value2Index, &NewVariables](
Value *V) ->
unsigned {
855 auto V2I = Value2Index.
find(V);
856 if (V2I != Value2Index.
end())
858 unsigned Idx =
find(NewVariables, V) - NewVariables.
begin();
859 if (Idx == NewVariables.
size())
861 return Value2Index.
size() + Idx + 1;
863 for (
const DecompEntry &KV : ADec.Vars)
864 GetCoefficient(GetOrAddIndex(KV.Variable)) += KV.Coefficient;
866 for (
const DecompEntry &KV : BDec.Vars) {
867 auto &Coeff = GetCoefficient(GetOrAddIndex(KV.Variable));
873 erase_if(R, [](
const Entry &
E) {
return E.Id != 0 &&
E.Coefficient == 0; });
880 bool ForceSignedSystem) {
881 assert(NewVariables.
empty() &&
"NewVariables must be empty when passed in");
883 "signed system can only be forced on eq/ne");
924 auto &Value2Index = getValue2Index(IsSigned);
934 if (
AddOverflow(R[0].Coefficient, int64_t(-1), R[0].Coefficient))
938 unsigned NumV2I = Value2Index.size();
939 NewVariables.
truncate(
R.back().Id > NumV2I ?
R.back().Id - NumV2I : 0);
941 return ConstraintTy(std::move(R), Value2Index.size() + NewVariables.
size(),
942 IsSigned, IsEq, IsNe);
953 return ConstraintTy(RowTy(1,
Entry(0, 0)), 0,
954 false,
false,
false);
966 ConstraintTy
R = getConstraint(Pred, Op0, Op1, NewVariables);
967 if (!NewVariables.
empty())
973ConstraintTy::isImpliedBy(
const ConstraintSystem &CS)
const {
974 const auto &[SubCS, NewCoefficients] = CS.
getSubSystem(Coefficients);
975 bool IsConditionImplied = SubCS.isConditionImplied(NewCoefficients);
979 bool IsNegatedOrEqualImplied =
980 !NegatedOrEqual.empty() && SubCS.isConditionImplied(NegatedOrEqual);
985 if (IsConditionImplied && IsNegatedOrEqualImplied)
989 bool IsNegatedImplied =
990 !Negated.empty() && SubCS.isConditionImplied(Negated);
993 bool IsStrictLessThanImplied =
994 !StrictLessThan.empty() && SubCS.isConditionImplied(StrictLessThan);
1000 if (IsNegatedImplied || IsStrictLessThanImplied)
1003 return std::nullopt;
1006 if (IsConditionImplied)
1010 auto IsNegatedImplied = !Negated.empty() && SubCS.isConditionImplied(Negated);
1011 if (IsNegatedImplied)
1015 return std::nullopt;
1019 auto R = getConstraintForSolving(Pred,
A,
B);
1020 return !
R.empty() &&
1021 getCS(
R.IsSigned).isConditionImpliedInSubSystem(
R.Coefficients);
1024bool ConstraintInfo::isKnownNonNegative(
Value *V) {
1026 return !CI->isNegative();
1027 return ::isKnownNonNegative(V,
DL) ||
1031bool ConstraintInfo::isKnownPositive(
Value *V) {
1033 return CI->getValue().isStrictlyPositive();
1034 return ::isKnownPositive(V,
DL) ||
1038void ConstraintInfo::transferToOtherSystem(
1040 unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack) {
1043 if (!
A->getType()->isIntegerTy())
1056 NumOut, DFSInStack);
1066 NumOut, DFSInStack);
1080 NumOut, DFSInStack);
1106static std::pair<Value *, Value *>
1109 "LoopPred must be a predecessor of the phi's block");
1111 return {
nullptr,
nullptr};
1118template <
typename PhiMatchTy>
1127MonotonicInfo State::getMonotonicityInfo(PHINode &PN,
Value *Step) {
1129 const APInt *StepOffset =
nullptr;
1133 Info.Unsigned = !
Info.Decreasing &&
Add->hasNoUnsignedWrap();
1134 Info.Signed =
Add->hasNoSignedWrap();
1140 APInt GEPOffset(
DL.getIndexTypeSizeInBits(
GEP->getType()), 0);
1141 Info.Unsigned =
GEP->getPointerOperand() == &PN &&
1142 (
GEP->hasNoUnsignedWrap() ||
1143 ((
GEP->hasNoUnsignedSignedWrap() &&
1144 GEP->accumulateConstantOffset(
DL, GEPOffset) &&
1145 !GEPOffset.isNegative())));
1150 if (
Info.Unsigned ||
Info.Signed || !StepOffset)
1167void State::addBoundsForHeaderInductions(BasicBlock &BB) {
1169 if (!L ||
L->getHeader() != &BB)
1176 for (PHINode &PN : BB.
phis()) {
1184 MonotonicInfo
Info = getMonotonicityInfo(PN, Step);
1188 Info.Unsigned =
false;
1189 if (!
Info.Unsigned && !
Info.Signed)
1195 if (
Info.Decreasing)
1199 WorkList.
push_back(FactOrCheck::getConditionFact(DTN, Pred,
LHS,
RHS));
1203void State::addInfoForInductions(BasicBlock &BB) {
1210 if (Header != &BB && Latch != &BB)
1217 PHINode *PN =
nullptr;
1218 const APInt *IncStep =
nullptr;
1228 std::optional<bool> PeeledOnEdge;
1229 if (!
match(Br->getCondition(), CountingCmp)) {
1233 PeeledOnEdge =
true;
1235 PeeledOnEdge =
false;
1250 if (&BB == Latch && !IncStep)
1253 bool ContinueOnTrue =
1257 BasicBlock *InLoopSucc = Br->getSuccessor(ContinueOnTrue ? 0 : 1);
1261 if (PeeledOnEdge && *PeeledOnEdge != ContinueOnTrue)
1264 if (!
L->contains(InLoopSucc) || !
L->isLoopExiting(&BB))
1268 if (!LoopPred || !
L->isLoopInvariant(
B))
1281 WorkList.
push_back(FactOrCheck::getConditionFact(
1282 DTN, ContinuePred, PN,
B,
ConditionTy(ContinuePred, StartValue,
B)));
1287 if (ICmpInst::isSigned(ContinuePred)) {
1290 "Expected a signed less-than continuation predicate");
1291 MonotonicInfo
Info = getMonotonicityInfo(*PN, Backedge);
1292 if (
Info.Signed && !
Info.Decreasing) {
1294 WorkList.
push_back(FactOrCheck::getConditionFact(
1304 const APInt *StepOffset =
nullptr;
1305 const SCEV *StartSCEV =
nullptr;
1307 if (StepOffset->
isZero())
1310 const SCEV *Expr = SE.
getSCEV(PN);
1319 if (IncStep && *IncStep != *StepOffset)
1322 MonotonicInfo
Info = getMonotonicityInfo(*PN, Backedge);
1327 if (!(-*StepOffset).isOne())
1337 ConditionTy BBeforeStartUnsigned = {UPrecond,
B, StartValue};
1343 WorkList.
push_back(FactOrCheck::getConditionFact(
1345 if (!(
Info.Decreasing &&
Info.Signed))
1346 WorkList.
push_back(FactOrCheck::getConditionFact(
1350 B, BBeforeStartUnsigned));
1352 B, BBeforeStartSigned));
1362 if (!StepOffset->
isOne()) {
1365 StartSCEV = SE.
getSCEV(StartValue);
1379 ConditionTy StartBeforeBoundUnsigned = {UPrecond, StartValue,
B};
1385 WorkList.
push_back(FactOrCheck::getConditionFact(
1388 WorkList.
push_back(FactOrCheck::getConditionFact(
1392 B, StartBeforeBoundSigned));
1393 WorkList.
push_back(FactOrCheck::getConditionFact(
1402 L->getExitBlocks(ExitBBs);
1403 for (BasicBlock *EB : ExitBBs) {
1418 if (!
Offset.NW.hasNoUnsignedWrap())
1421 if (
Offset.VariableOffsets.size() != 1)
1425 auto &[Index, Scale] =
Offset.VariableOffsets.front();
1427 if (Index->getType()->getScalarSizeInBits() !=
BitWidth)
1436 std::optional<TypeSize>
Size =
1451 B = ConstantInt::get(Index->getType(), MaxIndex);
1459 return Trunc->getType()->isIntegerTy() && Trunc->hasNoSignedWrap() &&
1460 !Trunc->hasNoUnsignedWrap();
1463 if (!BO || !BO->getType()->isIntegerTy())
1466 switch (BO->getOpcode()) {
1467 case Instruction::Sub:
1468 if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())
1473 case Instruction::Add:
1474 case Instruction::Mul:
1475 case Instruction::Shl:
1476 if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())
1495 I->setHasNoSignedWrap();
1500 I->setHasNoUnsignedWrap();
1506void State::addInfoFor(BasicBlock &BB) {
1507 addBoundsForHeaderInductions(BB);
1508 addInfoForInductions(BB);
1514 bool GuaranteedToExecute =
true;
1516 for (Instruction &
I : BB) {
1518 for (Use &U :
I.uses()) {
1520 auto *DTN = DT.
getNode(UserI->getParent());
1523 WorkList.
push_back(FactOrCheck::getCheck(DTN, &U));
1528 auto AddFactFromMemoryAccess = [&](
Value *Ptr,
Type *AccessType) {
1532 TypeSize AccessSize =
DL.getTypeStoreSize(AccessType);
1535 if (GuaranteedToExecute) {
1537 Pred,
A,
B,
DL, TLI)) {
1545 FactOrCheck::getInstFact(DT.
getNode(
I.getParent()), &
I));
1550 if (!LI->isVolatile())
1551 AddFactFromMemoryAccess(LI->getPointerOperand(), LI->getAccessType());
1554 if (!
SI->isVolatile())
1555 AddFactFromMemoryAccess(
SI->getPointerOperand(),
SI->getAccessType());
1561 case Intrinsic::assume: {
1564 if (GuaranteedToExecute) {
1571 FactOrCheck::getInstFact(DT.
getNode(
I.getParent()), &
I));
1576 case Intrinsic::uadd_with_overflow:
1577 case Intrinsic::sadd_with_overflow:
1578 case Intrinsic::usub_with_overflow:
1579 case Intrinsic::ssub_with_overflow:
1580 case Intrinsic::umul_with_overflow:
1581 case Intrinsic::smul_with_overflow:
1582 case Intrinsic::ucmp:
1583 case Intrinsic::scmp:
1588 case Intrinsic::umin:
1589 case Intrinsic::umax:
1590 case Intrinsic::smin:
1591 case Intrinsic::smax:
1592 case Intrinsic::usub_sat:
1597 case Intrinsic::uadd_sat:
1603 case Intrinsic::abs:
1618 if ((BO->getOpcode() == Instruction::URem ||
1619 BO->getOpcode() == Instruction::UDiv ||
1620 BO->getOpcode() == Instruction::LShr ||
1621 BO->getOpcode() == Instruction::SRem ||
1622 BO->getOpcode() == Instruction::SDiv) &&
1631 WorkList.
push_back(FactOrCheck::getCheck(
1639 for (
auto &Case :
Switch->cases()) {
1641 Value *
V = Case.getCaseValue();
1642 if (!canAddSuccessor(BB, Succ))
1671 SmallPtrSet<Value *, 8> SeenCond;
1672 auto QueueValue = [&CondWorkList, &SeenCond](
Value *
V) {
1673 if (SeenCond.
insert(V).second)
1678 while (!CondWorkList.
empty()) {
1703 if (canAddSuccessor(BB, Br->getSuccessor(0)))
1705 DT.
getNode(Br->getSuccessor(0)), Pred,
A,
B));
1706 if (canAddSuccessor(BB, Br->getSuccessor(1)))
1714 OS <<
"icmp " << Pred <<
' ';
1715 LHS->printAsOperand(OS,
true);
1717 RHS->printAsOperand(OS,
false);
1726struct ReproducerEntry {
1727 ICmpInst::Predicate Pred;
1762 auto &Value2Index = Info.getValue2Index(IsSigned);
1764 while (!WorkList.
empty()) {
1766 if (!Seen.
insert(V).second)
1768 if (Old2New.
find(V) != Old2New.
end())
1774 if (Value2Index.contains(V) || !
I ||
1785 for (
auto &Entry : Stack)
1788 CollectArguments(
Cond, IsSigned);
1791 for (
auto *
P : Args)
1797 Cond->getModule()->getName() +
1798 Cond->getFunction()->getName() +
"repro",
1801 for (
unsigned I = 0;
I < Args.size(); ++
I) {
1803 Old2New[Args[
I]] =
F->getArg(
I);
1808 Builder.CreateRet(Builder.getTrue());
1809 Builder.SetInsertPoint(Entry->getTerminator());
1818 auto &Value2Index = Info.getValue2Index(IsSigned);
1819 while (!WorkList.
empty()) {
1821 if (Old2New.
find(V) != Old2New.
end())
1825 if (!Value2Index.contains(V) &&
I) {
1826 Old2New[V] =
nullptr;
1836 Old2New[
I] = Cloned;
1837 Old2New[
I]->setName(
I->getName());
1849 for (
auto &Entry : Stack) {
1858 auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS);
1859 Builder.CreateAssumption(Cmp);
1864 CloneInstructions(
Cond, IsSigned);
1865 Entry->getTerminator()->setOperand(0,
Cond);
1876 ConstraintInfo &Info,
1878 const auto &Value2Index = Info.getValue2Index(
C.IsSigned);
1879 auto It = Value2Index.find(V);
1880 if (It == Value2Index.end() ||
1882 [Id = It->second](
const Entry &
E) { return E.Id == Id; }))
1888 Value2Index, NewVariables);
1889 return NewVariables.
empty() ? Row : RowTy();
1894 ConstraintInfo &Info) {
1897 auto TryWithConstraint = [&](
const ConstraintTy &R) -> std::optional<bool> {
1900 return std::nullopt;
1903 auto &CSToUse = Info.getCS(R.IsSigned);
1904 if (
auto ImpliedCondition = R.isImpliedBy(CSToUse)) {
1906 return std::nullopt;
1908 dbgs() <<
"Condition ";
1910 *ImpliedCondition ? Pred
1913 dbgs() <<
" implied by dominating constraints\n";
1916 return ImpliedCondition;
1918 return std::nullopt;
1923 auto TryWithLinkedDecomposition =
1924 [&](
const ConstraintTy &
C) -> std::optional<bool> {
1926 return std::nullopt;
1928 auto &CS = Info.getCS(
C.IsSigned);
1929 unsigned NumVars = Info.getValue2Index(
C.IsSigned).size();
1930 unsigned NumPushed = 0;
1935 if (Row.empty() || Negated.empty())
1937 NumPushed += CS.
addRow(Row, NumVars);
1938 NumPushed += CS.
addRow(Negated, NumVars);
1941 return std::nullopt;
1943 std::optional<bool> Res = TryWithConstraint(
C);
1949 auto R = Info.getConstraintForSolving(Pred,
A,
B);
1950 if (
auto ImpliedCondition = TryWithConstraint(R))
1951 return ImpliedCondition;
1952 if (
auto ImpliedCondition = TryWithLinkedDecomposition(R))
1953 return ImpliedCondition;
1961 if (NewVariables.
empty() && !SR.empty() && Info.isKnownNonNegative(
A) &&
1962 Info.isKnownNonNegative(
B))
1963 if (
auto ImpliedCondition = TryWithConstraint(SR))
1964 return ImpliedCondition;
1970 const auto &Value2Index = Info.getValue2Index(
true);
1971 if (!Value2Index.contains(
A) && !Value2Index.contains(
B))
1972 return std::nullopt;
1975 auto SR = Info.getConstraint(Pred,
A,
B, NewVariables,
1977 if (NewVariables.
empty()) {
1978 if (
auto ImpliedCondition = TryWithConstraint(SR))
1979 return ImpliedCondition;
1980 if (
auto ImpliedCondition = TryWithLinkedDecomposition(SR))
1981 return ImpliedCondition;
1984 return std::nullopt;
1989 ConstraintInfo &Info,
unsigned NumIn,
unsigned NumOut,
1993 auto ReplaceCmpWithConstant = [&](
Instruction *CheckInst,
bool IsTrue) {
1995 ReproducerCondStack, Info, DT);
2000 auto *DTN = DT.
getNode(UserI->getParent());
2003 if (UserI->getParent() == ContextInst->
getParent() &&
2004 UserI->comesBefore(ContextInst))
2010 return !
II ||
II->getIntrinsicID() != Intrinsic::assume;
2019 for (
auto *DVR : DVRUsers) {
2020 auto *DTN = DT.
getNode(DVR->getParent());
2024 auto *MarkedI = DVR->getInstruction();
2025 if (MarkedI->getParent() == ContextInst->
getParent() &&
2026 MarkedI->comesBefore(ContextInst))
2029 DVR->replaceVariableLocationOp(CheckInst, ConstantC);
2039 return ReplaceCmpWithConstant(CheckInst, *ImpliedCondition);
2046 return ReplaceCmpWithConstant(CheckInst, *ImpliedCondition);
2055 MinMax->replaceAllUsesWith(
MinMax->getOperand(UseLHS ? 0 : 1));
2064 return ReplaceMinMaxWithOperand(
MinMax, *ImpliedCondition);
2067 return ReplaceMinMaxWithOperand(
MinMax, !*ImpliedCondition);
2076 I->replaceAllUsesWith(ConstantInt::get(
I->getType(), 1));
2086 I->replaceAllUsesWith(ConstantInt::get(
I->getType(), 0));
2104 Value *
Sub = Builder.CreateSub(
A,
B,
"",
true,
2105 Info.isKnownNonNegative(
A));
2107 Sub->takeName(USub);
2114 Module *ReproducerModule,
2117 Info.getDecomposeCache().clear();
2118 Info.popLastConstraint(
E.IsSigned);
2120 auto &Mapping = Info.getValue2Index(
E.IsSigned);
2121 for (
Value *V :
E.ValuesToRelease)
2123 Info.popLastNVariables(
E.IsSigned,
E.ValuesToRelease.size());
2125 if (ReproducerModule)
2132 FactOrCheck &CB, ConstraintInfo &Info,
Module *ReproducerModule,
2141 unsigned OtherOpIdx = JoinOp->
getOperand(0) == CmpToCheck ? 1 : 0;
2149 unsigned OldSize = DFSInStack.
size();
2152 while (OldSize < DFSInStack.
size()) {
2153 StackEntry
E = DFSInStack.
back();
2161 while (!Worklist.empty()) {
2162 Value *Val = Worklist.pop_back_val();
2170 Info.addFact(Pred,
LHS,
RHS, CB.NumIn, CB.NumOut, DFSInStack);
2175 Worklist.push_back(
LHS);
2176 Worklist.push_back(
RHS);
2179 if (OldSize == DFSInStack.
size())
2184 [[maybe_unused]]
bool Matched =
2186 assert(Matched &&
"expected icmp-like match");
2188 if (
auto ImpliedCondition =
checkCondition(Pred,
A,
B, CmpToCheck, Info)) {
2189 if (IsOr == *ImpliedCondition)
2202 unsigned NumIn,
unsigned NumOut,
2203 SmallVectorImpl<StackEntry> &DFSInStack) {
2204 addFactImpl(Pred,
A,
B, NumIn, NumOut, DFSInStack,
false);
2207 addFactImpl(Pred,
A,
B, NumIn, NumOut, DFSInStack,
true);
2209 tightenBoundUsingNe(
A,
B, NumIn, NumOut, DFSInStack);
2212void ConstraintInfo::tightenBoundUsingNe(
2214 SmallVectorImpl<StackEntry> &DFSInStack) {
2215 if (!
A->getType()->isIntOrPtrTy())
2218 for (
bool IsSigned : {
false,
true}) {
2225 const auto &Value2Index = getValue2Index(IsSigned);
2227 [&Value2Index](
const DecompEntry &
E) {
2228 return !Value2Index.contains(
E.Variable);
2239 if (!doesHold(NonStrict,
A,
B))
2245 dbgs() <<
"' using inequality\n");
2246 addFactImpl(
Strict,
A,
B, NumIn, NumOut, DFSInStack,
2254 unsigned NumIn,
unsigned NumOut,
2255 SmallVectorImpl<StackEntry> &DFSInStack,
2256 bool ForceSignedSystem) {
2258 auto R = getConstraint(Pred,
A,
B, NewVariables, ForceSignedSystem);
2261 if (
R.empty() ||
R.isNe())
2266 auto &CSToUse = getCS(
R.IsSigned);
2267 bool Added = CSToUse.addRow(
R.Coefficients,
R.NumVars);
2271 DecomposeCache.
clear();
2275 SmallVector<Value *, 2> ValuesToRelease;
2276 auto &Value2Index = getValue2Index(
R.IsSigned);
2277 for (
Value *V : NewVariables) {
2278 Value2Index.try_emplace(V, Value2Index.size() + 1);
2283 dbgs() <<
" constraint: ";
2289 std::move(ValuesToRelease));
2292 for (
Value *V : NewVariables) {
2294 CSToUse.addRow({
Entry(0, 0),
Entry(-1, Value2Index.at(V))},
2295 Value2Index.size());
2297 SmallVector<Value *, 2>());
2303 for (Entry &
E :
R.Coefficients)
2306 CSToUse.addRow(
R.Coefficients,
R.NumVars);
2309 SmallVector<Value *, 2>());
2319 Value *Res =
nullptr;
2323 Res = Builder.CreateNoWrapBinOp(
II->getBinaryOp(),
II->getLHS(),
2330 U->replaceAllUsesWith(Builder.getFalse());
2335 if (U->use_empty()) {
2343 if (
II->use_empty()) {
2345 for (
Use &Arg :
II->args())
2368 ConstraintInfo Info(
F.getDataLayout(), FunctionArgs);
2369 State S(DT, LI, SE, TLI);
2370 std::unique_ptr<Module> ReproducerModule(
2389 stable_sort(S.WorkList, [](
const FactOrCheck &
A,
const FactOrCheck &
B) {
2390 auto HasNoConstOp = [](const FactOrCheck &B) {
2391 Value *V0 = B.isConditionFact() ? B.Cond.Op0 : B.Inst->getOperand(0);
2392 Value *V1 = B.isConditionFact() ? B.Cond.Op1 : B.Inst->getOperand(1);
2393 return !isa<ConstantInt>(V0) && !isa<ConstantInt>(V1);
2397 if (
A.NumIn ==
B.NumIn) {
2398 if (A.isConditionFact() && B.isConditionFact()) {
2399 bool NoConstOpA = HasNoConstOp(A);
2400 bool NoConstOpB = HasNoConstOp(B);
2401 return NoConstOpA < NoConstOpB;
2403 if (
A.isConditionFact())
2405 if (
B.isConditionFact())
2407 auto *InstA =
A.getContextInst();
2408 auto *InstB =
B.getContextInst();
2409 return InstA->comesBefore(InstB);
2411 return A.NumIn <
B.NumIn;
2414 SmallVector<Instruction *>
ToRemove;
2419 for (FactOrCheck &CB : S.WorkList) {
2422 while (!DFSInStack.
empty()) {
2423 auto &
E = DFSInStack.
back();
2426 LLVM_DEBUG(
dbgs() <<
"CB: " << CB.NumIn <<
" " << CB.NumOut <<
"\n");
2428 if (CB.NumOut <=
E.NumOut)
2431 dbgs() <<
"Removing ";
2433 Info.getValue2Index(
E.IsSigned));
2445 Instruction *Inst = CB.getInstructionToSimplify();
2452 LLVM_DEBUG(
dbgs() <<
"Processing condition to simplify: " << *Inst
2458 Pred,
A,
B, Inst, Info, CB.NumIn, CB.NumOut, CB.getContextInst(),
2459 ReproducerModule.get(), ReproducerCondStack, S.DT,
ToRemove);
2463 CB, Info, ReproducerModule.get(), ReproducerCondStack, DFSInStack,
2478 auto AddFact = [&](CmpPredicate Pred,
Value *
A,
Value *
B) {
2484 <<
"Skip adding constraint because system has too many rows.\n");
2488 Info.addFact(Pred,
A,
B, CB.NumIn, CB.NumOut, DFSInStack);
2489 if (ReproducerModule && DFSInStack.
size() > ReproducerCondStack.
size())
2498 CB.NumIn, CB.NumOut, DFSInStack);
2500 Info.transferToOtherSystem(Pred,
A,
B, CB.NumIn, CB.NumOut,
2514 SmallPtrSet<Value *, 4> Seen;
2515 while (!Worklist.
empty()) {
2518 if (!BO || BO->getOpcode() !=
Opc)
2520 for (
Value *
Op : {BO->getOperand(0), BO->getOperand(1)}) {
2524 Info.addFact(Pred,
Op,
B, CB.NumIn, CB.NumOut, DFSInStack);
2529 if (ReproducerModule && DFSInStack.
size() > ReproducerCondStack.
size()) {
2532 for (
unsigned I = 0,
2533 E = (DFSInStack.
size() - ReproducerCondStack.
size());
2535 ReproducerCondStack.
emplace_back(ICmpInst::BAD_ICMP_PREDICATE,
2541 if (!CB.isConditionFact()) {
2547 ConstantInt::get(CB.Inst->getType(), 0));
2553 Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
2554 AddFact(Pred, MinMax, MinMax->getLHS());
2555 AddFact(Pred, MinMax, MinMax->getRHS());
2559 switch (USatI->getIntrinsicID()) {
2562 case Intrinsic::uadd_sat:
2563 AddFact(ICmpInst::ICMP_UGE, USatI, USatI->getLHS());
2564 AddFact(ICmpInst::ICMP_UGE, USatI, USatI->getRHS());
2566 case Intrinsic::usub_sat:
2567 AddFact(ICmpInst::ICMP_ULE, USatI, USatI->getLHS());
2574 if (BO->getOpcode() == Instruction::URem) {
2581 if (BO->getOpcode() == Instruction::UDiv) {
2586 if (BO->getOpcode() == Instruction::LShr) {
2591 if (BO->getOpcode() == Instruction::SRem) {
2592 Value *
X = BO->getOperand(0);
2593 Value *
N = BO->getOperand(1);
2611 if (BO->getOpcode() == Instruction::SDiv) {
2612 Value *
X = BO->getOperand(0);
2613 Value *
N = BO->getOperand(1);
2614 if (!
Info.isKnownNonNegative(
X) || !
Info.isKnownPositive(
N))
2617 bool IsStrict =
Info.isKnownPositive(
X) &&
2619 ConstantInt::get(
N->getType(), 1));
2626 auto &
DL =
F.getDataLayout();
2627 auto AddFactsAboutIndices = [&](
Value *Ptr,
Type *AccessType) {
2632 DL.getTypeStoreSize(AccessType).getFixedValue(), Pred,
A,
B,
DL,
2634 AddFact(Pred,
A,
B);
2638 AddFactsAboutIndices(LI->getPointerOperand(), LI->getAccessType());
2642 AddFactsAboutIndices(
SI->getPointerOperand(),
SI->getAccessType());
2647 if (CB.isConditionFact()) {
2648 Pred = CB.Cond.Pred;
2652 !
Info.doesHold(CB.DoesHold.Pred, CB.DoesHold.Op0, CB.DoesHold.Op1)) {
2654 dbgs() <<
"Not adding fact ";
2656 dbgs() <<
" because precondition ";
2659 dbgs() <<
" does not hold.\n";
2664 [[maybe_unused]]
bool Matched =
2668 "Must have an assume intrinsic with a icmp like operand");
2670 AddFact(Pred,
A,
B);
2673 if (ReproducerModule && !ReproducerModule->functions().empty()) {
2675 raw_string_ostream StringS(S);
2676 ReproducerModule->print(StringS,
nullptr);
2677 OptimizationRemark Rem(
DEBUG_TYPE,
"Reproducer", &
F);
2678 Rem <<
ore::NV(
"module") << S;
2683 unsigned SignedEntries =
2684 count_if(DFSInStack, [](
const StackEntry &
E) {
return E.IsSigned; });
2685 assert(
Info.getCS(
false).size() - FunctionArgs.size() ==
2686 DFSInStack.
size() - SignedEntries &&
2687 "updates to CS and DFSInStack are out of sync");
2688 assert(
Info.getCS(
true).size() == SignedEntries &&
2689 "updates to CS and DFSInStack are out of sync");
2693 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 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 cl::opt< unsigned > MaxRows("constraint-elimination-max-rows", cl::init(500), cl::Hidden, cl::desc("Maximum number of rows to keep in constraint system"))
static cl::opt< bool > DumpReproducers("constraint-elimination-dump-reproducers", cl::init(false), cl::Hidden, cl::desc("Dump IR to reproduce successful transformations."))
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 bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE, OptimizationRemarkEmitter &ORE, TargetLibraryInfo &TLI)
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[]
Machine Check Debug Module
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.
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 ...
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.
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 * 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,...
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEV::NoWrapFlags Flags=SCEV::FlagNone, unsigned Depth=0)
Return LHS-RHS.
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)
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.
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))
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.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
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)
initializer< Ty > init(const Ty &Val)
@ 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.
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,...
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.