54#define DEBUG_TYPE "constraint-elimination"
56STATISTIC(NumCondsRemoved,
"Number of instructions removed");
58 "Controls which conditions are eliminated");
62 cl::desc(
"Maximum number of rows to keep in constraint system"));
66 cl::desc(
"Dump IR to reproduce successful transformations."));
74 UserI = Phi->getIncomingBlock(U)->getTerminator();
83 for (
Use &U :
I.uses()) {
104 Value *Op0 =
nullptr;
105 Value *Op1 =
nullptr;
109 : Pred(Pred), Op0(Op0), Op1(Op1) {}
147 FactOrCheck(EntryTy Ty,
DomTreeNode *DTN, Instruction *Inst,
148 Instruction *ContextInst =
nullptr)
149 : Inst(Inst), ContextInst(ContextInst ? ContextInst : Inst),
150 NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), Ty(Ty) {}
153 :
U(
U), ContextInst(nullptr), NumIn(DTN->getDFSNumIn()),
154 NumOut(DTN->getDFSNumOut()), Ty(EntryTy::UseCheck) {}
158 :
Cond(Pred, Op0, Op1), DoesHold(Precond), NumIn(DTN->getDFSNumIn()),
159 NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {}
161 static FactOrCheck getConditionFact(
DomTreeNode *DTN, CmpPredicate Pred,
164 return FactOrCheck(DTN, Pred, Op0, Op1, Precond);
167 static FactOrCheck getInstFact(
DomTreeNode *DTN, Instruction *Inst) {
168 return FactOrCheck(EntryTy::InstFact, DTN, Inst);
171 static FactOrCheck getCheck(
DomTreeNode *DTN, Use *U) {
172 return FactOrCheck(DTN, U);
175 static FactOrCheck getCheck(
DomTreeNode *DTN, Instruction *
I,
176 Instruction *ContextInst =
nullptr) {
178 "anchoring instruction must be in DTN's block");
179 return FactOrCheck(EntryTy::InstCheck, DTN,
I, ContextInst);
182 bool isCheck()
const {
183 return Ty == EntryTy::InstCheck || Ty == EntryTy::UseCheck;
187 assert(!isConditionFact());
188 if (Ty == EntryTy::UseCheck)
195 if (Ty == EntryTy::InstCheck)
201 bool isConditionFact()
const {
return Ty == EntryTy::ConditionFact; }
206struct MonotonicInfo {
208 bool Decreasing =
false;
210 bool Unsigned =
false;
220 TargetLibraryInfo &TLI;
223 State(DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE,
224 TargetLibraryInfo &TLI)
225 : DT(DT), LI(LI), SE(SE), TLI(TLI) {}
228 void addInfoFor(BasicBlock &BB);
232 void addBoundsForHeaderInductions(BasicBlock &BB);
236 void addInfoForInductions(BasicBlock &BB);
240 MonotonicInfo getMonotonicityInfo(PHINode &PN,
Value *Step);
244 bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ)
const {
245 return DT.dominates(BasicBlockEdge(&BB, Succ), Succ);
254 bool IsSigned =
false;
257 SmallVector<Value *, 2> ValuesToRelease;
259 StackEntry(
unsigned NumIn,
unsigned NumOut,
bool IsSigned,
260 SmallVector<Value *, 2> ValuesToRelease)
261 : NumIn(NumIn), NumOut(NumOut), IsSigned(IsSigned),
262 ValuesToRelease(std::
move(ValuesToRelease)) {}
269 unsigned NumVars = 0;
271 bool IsSigned =
false;
273 ConstraintTy() =
default;
275 ConstraintTy(RowTy Coefficients,
unsigned NumVars,
bool IsSigned,
bool IsEq,
277 : Coefficients(std::
move(Coefficients)), NumVars(NumVars),
278 IsSigned(IsSigned), IsEq(IsEq), IsNe(IsNe) {}
280 bool empty()
const {
return Coefficients.empty(); }
284 bool isConstantOnly()
const {
return Coefficients.size() < 2; }
286 bool isEq()
const {
return IsEq; }
288 bool isNe()
const {
return IsNe; }
295 std::optional<bool> isImpliedBy(
const ConstraintSystem &CS)
const;
308class ConstraintInfo {
310 ConstraintSystem UnsignedCS;
311 ConstraintSystem SignedCS;
313 const DataLayout &DL;
317 : UnsignedCS(FunctionArgs), SignedCS(FunctionArgs), DL(DL) {
318 auto &Value2Index = getValue2Index(
false);
320 for (
Value *Arg : FunctionArgs)
321 UnsignedCS.addRow({
Entry(0, 0),
Entry(-1, Value2Index.at(Arg))},
325 DenseMap<Value *, unsigned> &getValue2Index(
bool Signed) {
326 return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
328 const DenseMap<Value *, unsigned> &getValue2Index(
bool Signed)
const {
329 return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
332 ConstraintSystem &getCS(
bool Signed) {
333 return Signed ? SignedCS : UnsignedCS;
335 const ConstraintSystem &getCS(
bool Signed)
const {
336 return Signed ? SignedCS : UnsignedCS;
339 void popLastConstraint(
bool Signed) { getCS(
Signed).popLastConstraint(); }
340 void popLastNVariables(
bool Signed,
unsigned N) {
341 getCS(
Signed).popLastNVariables(
N);
351 unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack);
358 SmallVectorImpl<Value *> &NewVariables,
359 bool ForceSignedSystem =
false)
const;
374 unsigned NumIn,
unsigned NumOut,
375 SmallVectorImpl<StackEntry> &DFSInStack);
382 unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack,
383 bool ForceSignedSystem);
387 void tightenBoundUsingNe(
Value *
A,
Value *
B,
unsigned NumIn,
unsigned NumOut,
388 SmallVectorImpl<StackEntry> &DFSInStack);
396 DecompEntry(int64_t Coefficient,
Value *Variable)
397 : Coefficient(Coefficient), Variable(Variable) {}
401struct Decomposition {
405 Decomposition(int64_t Offset) : Offset(Offset) {}
406 Decomposition(
Value *V) { Vars.emplace_back(1, V); }
408 : Offset(Offset), Vars(Vars) {}
412 [[nodiscard]]
bool add(int64_t OtherOffset) {
418 [[nodiscard]]
bool add(
const Decomposition &
Other) {
427 [[nodiscard]]
bool sub(
const Decomposition &
Other) {
428 Decomposition Tmp =
Other;
439 [[nodiscard]]
bool mul(int64_t Factor) {
442 for (
auto &Var : Vars)
443 if (
MulOverflow(Var.Coefficient, Factor, Var.Coefficient))
452 APInt ConstantOffset;
453 SmallMapVector<Value *, APInt, 4> VariableOffsets;
458 OffsetResult(GEPOperator &
GEP,
const DataLayout &
DL)
460 ConstantOffset = APInt(
DL.getIndexTypeSizeInBits(
BasePtr->getType()), 0);
470 unsigned BitWidth = Result.ConstantOffset.getBitWidth();
472 Result.ConstantOffset))
480 bool CanCollectInner = InnerGEP->collectOffset(
481 DL,
BitWidth, VariableOffsets2, ConstantOffset2);
483 if (!CanCollectInner || Result.VariableOffsets.size() > 1 ||
484 VariableOffsets2.
size() > 1 ||
485 (Result.VariableOffsets.size() >= 1 && VariableOffsets2.
size() >= 1)) {
489 Result.BasePtr = InnerGEP->getPointerOperand();
490 Result.ConstantOffset += ConstantOffset2;
491 if (Result.VariableOffsets.size() == 0 && VariableOffsets2.
size() == 1)
492 Result.VariableOffsets = std::move(VariableOffsets2);
493 Result.NW &= InnerGEP->getNoWrapFlags();
498static Decomposition
decompose(
Value *V,
const ConstraintInfo &Info,
510 return Info.doesHold(Pred,
Op, ConstantInt::get(
Op->getType(),
RHS));
517 if (
DL.getIndexTypeSizeInBits(
GEP.getPointerOperand()->getType()) > 64)
520 assert(!IsSigned &&
"The logic below only supports decomposition for "
521 "unsigned predicates at the moment.");
522 const auto &[BasePtr, ConstantOffset, VariableOffsets, NW] =
531 if (!NW.hasNoUnsignedSignedWrap() && ConstantOffset.isNegative())
534 Decomposition Result(ConstantOffset.getSExtValue(), DecompEntry(1, BasePtr));
535 for (
auto [Index, Scale] : VariableOffsets) {
536 if (!NW.hasNoUnsignedWrap()) {
539 assert(NW.hasNoUnsignedSignedWrap() &&
"Must have nusw flag");
545 auto IdxResult =
decompose(Index, Info, IsSigned,
DL);
546 if (IdxResult.mul(Scale.getSExtValue()))
548 if (Result.add(IdxResult))
562 auto MergeResults = [&Info, IsSigned,
564 bool IsSignedB) -> std::optional<Decomposition> {
573 if (Ty->isPointerTy() && !IsSigned) {
585 if (!Ty->isIntegerTy() || Ty->getIntegerBitWidth() > 64)
592 return CI->getSExtValue();
607 if (
auto Decomp = MergeResults(Op0, Op1, IsSigned))
614 Decomposition Result(-1);
615 if (!Result.sub(
decompose(Op0, Info, IsSigned,
DL)))
640 if (Shift < Ty->getIntegerBitWidth() - 1) {
641 assert(Shift < 64 &&
"Would overflow");
643 if (!Result.mul(int64_t(1) << Shift))
655 return int64_t(CI->getZExtValue());
667 if (Trunc->getSrcTy()->getScalarSizeInBits() <= 64 &&
668 (Trunc->hasNoUnsignedWrap() || Trunc->hasNoSignedWrap())) {
669 Value *Src = Trunc->getOperand(0);
672 if (!Trunc->hasNoUnsignedWrap() &&
682 if (
auto Decomp = MergeResults(Op0, Op1, IsSigned))
693 if (
auto Decomp = MergeResults(Op0, CI,
true))
707 if (
auto Decomp = MergeResults(Op0, Op1, IsSigned))
750 bool ForceSignedSystem)
const {
751 assert(NewVariables.
empty() &&
"NewVariables must be empty when passed in");
753 "signed system can only be forced on eq/ne");
794 auto &Value2Index = getValue2Index(IsSigned);
799 int64_t Offset1 = ADec.Offset;
800 int64_t Offset2 = BDec.Offset;
804 auto &VariablesA = ADec.Vars;
805 auto &VariablesB = BDec.Vars;
809 auto GetOrAddIndex = [&Value2Index, &NewVariables](
Value *
V) ->
unsigned {
810 auto V2I = Value2Index.find(V);
811 if (V2I != Value2Index.end())
813 unsigned Idx =
find(NewVariables, V) - NewVariables.
begin();
814 if (Idx == NewVariables.
size())
816 return Value2Index.size() + Idx + 1;
822 auto GetCoefficient = [&
R](
unsigned Idx) -> int64_t & {
827 if (
I ==
R.end() ||
I->Id != Idx)
829 return I->Coefficient;
831 for (
const auto &KV : VariablesA)
832 GetCoefficient(GetOrAddIndex(KV.Variable)) += KV.Coefficient;
834 for (
const auto &KV : VariablesB) {
835 auto &Coeff = GetCoefficient(GetOrAddIndex(KV.Variable));
844 if (
AddOverflow(OffsetSum, int64_t(-1), OffsetSum))
846 R[0].Coefficient = OffsetSum;
849 erase_if(R, [](
const Entry &
E) {
return E.Id != 0 &&
E.Coefficient == 0; });
852 unsigned NumV2I = Value2Index.size();
853 NewVariables.
truncate(
R.back().Id > NumV2I ?
R.back().Id - NumV2I : 0);
855 return ConstraintTy(std::move(R), Value2Index.size() + NewVariables.
size(),
856 IsSigned, IsEq, IsNe);
868 return ConstraintTy(RowTy(1,
Entry(0, 0)), 0,
869 false,
false,
false);
881 ConstraintTy
R = getConstraint(Pred, Op0, Op1, NewVariables);
882 if (!NewVariables.
empty())
888ConstraintTy::isImpliedBy(
const ConstraintSystem &CS)
const {
889 const auto &[SubCS, NewCoefficients] = CS.
getSubSystem(Coefficients);
890 bool IsConditionImplied = SubCS.isConditionImplied(NewCoefficients);
894 bool IsNegatedOrEqualImplied =
895 !NegatedOrEqual.empty() && SubCS.isConditionImplied(NegatedOrEqual);
900 if (IsConditionImplied && IsNegatedOrEqualImplied)
904 bool IsNegatedImplied =
905 !Negated.empty() && SubCS.isConditionImplied(Negated);
908 bool IsStrictLessThanImplied =
909 !StrictLessThan.empty() && SubCS.isConditionImplied(StrictLessThan);
915 if (IsNegatedImplied || IsStrictLessThanImplied)
921 if (IsConditionImplied)
925 auto IsNegatedImplied = !Negated.empty() && SubCS.isConditionImplied(Negated);
926 if (IsNegatedImplied)
935 auto R = getConstraintForSolving(Pred,
A,
B);
937 getCS(
R.IsSigned).isConditionImpliedInSubSystem(
R.Coefficients);
940bool ConstraintInfo::isKnownNonNegative(
Value *V)
const {
945void ConstraintInfo::transferToOtherSystem(
947 unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack) {
950 if (!
A->getType()->isIntegerTy())
1013static std::pair<Value *, Value *>
1016 "LoopPred must be a predecessor of the phi's block");
1018 return {
nullptr,
nullptr};
1025template <
typename PhiMatchTy>
1034MonotonicInfo State::getMonotonicityInfo(PHINode &PN,
Value *Step) {
1036 const APInt *StepOffset =
nullptr;
1040 Info.Unsigned = !
Info.Decreasing &&
Add->hasNoUnsignedWrap();
1041 Info.Signed =
Add->hasNoSignedWrap();
1047 APInt GEPOffset(
DL.getIndexTypeSizeInBits(
GEP->getType()), 0);
1048 Info.Unsigned =
GEP->getPointerOperand() == &PN &&
1049 (
GEP->hasNoUnsignedWrap() ||
1050 ((
GEP->hasNoUnsignedSignedWrap() &&
1051 GEP->accumulateConstantOffset(
DL, GEPOffset) &&
1052 !GEPOffset.isNegative())));
1057 if (
Info.Unsigned ||
Info.Signed || !StepOffset)
1074void State::addBoundsForHeaderInductions(BasicBlock &BB) {
1076 if (!L ||
L->getHeader() != &BB)
1083 for (PHINode &PN : BB.
phis()) {
1091 MonotonicInfo
Info = getMonotonicityInfo(PN, Step);
1095 Info.Unsigned =
false;
1096 if (!
Info.Unsigned && !
Info.Signed)
1102 if (
Info.Decreasing)
1106 WorkList.
push_back(FactOrCheck::getConditionFact(DTN, Pred,
LHS,
RHS));
1110void State::addInfoForInductions(BasicBlock &BB) {
1117 if (Header != &BB && Latch != &BB)
1124 PHINode *PN =
nullptr;
1125 const APInt *IncStep =
nullptr;
1135 std::optional<bool> PeeledOnEdge;
1136 if (!
match(Br->getCondition(), CountingCmp)) {
1140 PeeledOnEdge =
true;
1142 PeeledOnEdge =
false;
1157 if (&BB == Latch && !IncStep)
1160 bool ContinueOnTrue =
1164 BasicBlock *InLoopSucc = Br->getSuccessor(ContinueOnTrue ? 0 : 1);
1168 if (PeeledOnEdge && *PeeledOnEdge != ContinueOnTrue)
1171 if (!
L->contains(InLoopSucc) || !
L->isLoopExiting(&BB))
1175 if (!LoopPred || !
L->isLoopInvariant(
B))
1188 WorkList.
push_back(FactOrCheck::getConditionFact(
1189 DTN, ContinuePred, PN,
B,
ConditionTy(ContinuePred, StartValue,
B)));
1196 const APInt *StepOffset =
nullptr;
1197 const SCEV *StartSCEV =
nullptr;
1199 if (StepOffset->
isZero())
1202 const SCEV *Expr = SE.
getSCEV(PN);
1211 if (IncStep && *IncStep != *StepOffset)
1214 MonotonicInfo
Info = getMonotonicityInfo(*PN, Backedge);
1219 if (!(-*StepOffset).isOne())
1229 ConditionTy BBeforeStartUnsigned = {UPrecond,
B, StartValue};
1235 WorkList.
push_back(FactOrCheck::getConditionFact(
1237 if (!(
Info.Decreasing &&
Info.Signed))
1238 WorkList.
push_back(FactOrCheck::getConditionFact(
1242 B, BBeforeStartUnsigned));
1244 B, BBeforeStartSigned));
1254 if (!StepOffset->
isOne()) {
1257 StartSCEV = SE.
getSCEV(StartValue);
1271 ConditionTy StartBeforeBoundUnsigned = {UPrecond, StartValue,
B};
1277 WorkList.
push_back(FactOrCheck::getConditionFact(
1280 WorkList.
push_back(FactOrCheck::getConditionFact(
1284 B, StartBeforeBoundSigned));
1285 WorkList.
push_back(FactOrCheck::getConditionFact(
1294 L->getExitBlocks(ExitBBs);
1295 for (BasicBlock *EB : ExitBBs) {
1310 if (!
Offset.NW.hasNoUnsignedWrap())
1313 if (
Offset.VariableOffsets.size() != 1)
1317 auto &[Index, Scale] =
Offset.VariableOffsets.front();
1319 if (Index->getType()->getScalarSizeInBits() !=
BitWidth)
1328 std::optional<TypeSize>
Size =
1343 B = ConstantInt::get(Index->getType(), MaxIndex);
1351 if (!BO || !BO->getType()->isIntegerTy())
1354 switch (BO->getOpcode()) {
1355 case Instruction::Sub:
1358 return !BO->hasNoUnsignedWrap() && !
isa<Constant>(BO->getOperand(1));
1359 case Instruction::Add:
1361 return (!BO->hasNoUnsignedWrap() || !BO->hasNoSignedWrap()) &&
1363 case Instruction::Mul:
1364 case Instruction::Shl:
1365 if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())
1380 if (R.isEmptySet() || (
Signed ? R.isSignWrappedSet() : R.isWrappedSet()))
1386 unsigned BitWidth = R.getBitWidth();
1387 APInt Min =
Signed ? R.getSignedMin() : R.getUnsignedMin();
1388 APInt Max =
Signed ? R.getSignedMax() : R.getUnsignedMax();
1397 Type *Ty =
Op->getType();
1398 if (Min != MinVal &&
1400 ConstantInt::get(Ty, Min)))
1402 if (Max != MaxVal &&
1404 ConstantInt::get(Ty, Max)))
1410 ConstraintInfo &Info) {
1421 if (!
I->hasNoUnsignedWrap() &&
1424 Opcode,
Other, OBO::NoUnsignedWrap),
1427 I->setHasNoUnsignedWrap();
1430 if (!
I->hasNoSignedWrap() &&
1433 Opcode,
Other, OBO::NoSignedWrap),
1436 I->setHasNoSignedWrap();
1448 Value *Op0 =
I->getOperand(0), *Op1 =
I->getOperand(1);
1449 switch (
I->getOpcode()) {
1450 case Instruction::Sub: {
1455 I->setHasNoUnsignedWrap();
1458 case Instruction::Add:
1460 case Instruction::Mul:
1461 case Instruction::Shl: {
1464 if (!
I->hasNoUnsignedWrap() &&
I->hasNoSignedWrap() &&
1465 Info.isKnownNonNegative(Op0) &&
1466 (Opcode == Instruction::Shl || Info.isKnownNonNegative(Op1))) {
1468 I->setHasNoUnsignedWrap();
1478void State::addInfoFor(BasicBlock &BB) {
1479 addBoundsForHeaderInductions(BB);
1480 addInfoForInductions(BB);
1486 bool GuaranteedToExecute =
true;
1488 for (Instruction &
I : BB) {
1490 for (Use &U :
I.uses()) {
1492 auto *DTN = DT.
getNode(UserI->getParent());
1495 WorkList.
push_back(FactOrCheck::getCheck(DTN, &U));
1500 auto AddFactFromMemoryAccess = [&](
Value *Ptr,
Type *AccessType) {
1504 TypeSize AccessSize =
DL.getTypeStoreSize(AccessType);
1507 if (GuaranteedToExecute) {
1509 Pred,
A,
B,
DL, TLI)) {
1517 FactOrCheck::getInstFact(DT.
getNode(
I.getParent()), &
I));
1522 if (!LI->isVolatile())
1523 AddFactFromMemoryAccess(LI->getPointerOperand(), LI->getAccessType());
1526 if (!
SI->isVolatile())
1527 AddFactFromMemoryAccess(
SI->getPointerOperand(),
SI->getAccessType());
1533 case Intrinsic::assume: {
1536 if (GuaranteedToExecute) {
1543 FactOrCheck::getInstFact(DT.
getNode(
I.getParent()), &
I));
1548 case Intrinsic::sadd_with_overflow:
1549 case Intrinsic::ssub_with_overflow:
1550 case Intrinsic::ucmp:
1551 case Intrinsic::scmp:
1556 case Intrinsic::umin:
1557 case Intrinsic::umax:
1558 case Intrinsic::smin:
1559 case Intrinsic::smax:
1560 case Intrinsic::usub_sat:
1565 case Intrinsic::uadd_sat:
1571 case Intrinsic::abs:
1584 if ((BO->getOpcode() == Instruction::URem ||
1585 BO->getOpcode() == Instruction::UDiv ||
1586 BO->getOpcode() == Instruction::LShr ||
1587 BO->getOpcode() == Instruction::SRem) &&
1596 WorkList.
push_back(FactOrCheck::getCheck(
1604 for (
auto &Case :
Switch->cases()) {
1606 Value *
V = Case.getCaseValue();
1607 if (!canAddSuccessor(BB, Succ))
1636 SmallPtrSet<Value *, 8> SeenCond;
1637 auto QueueValue = [&CondWorkList, &SeenCond](
Value *
V) {
1638 if (SeenCond.
insert(V).second)
1643 while (!CondWorkList.
empty()) {
1668 if (canAddSuccessor(BB, Br->getSuccessor(0)))
1670 DT.
getNode(Br->getSuccessor(0)), Pred,
A,
B));
1671 if (canAddSuccessor(BB, Br->getSuccessor(1)))
1679 OS <<
"icmp " << Pred <<
' ';
1680 LHS->printAsOperand(OS,
true);
1682 RHS->printAsOperand(OS,
false);
1691struct ReproducerEntry {
1692 ICmpInst::Predicate Pred;
1727 auto &Value2Index = Info.getValue2Index(IsSigned);
1729 while (!WorkList.
empty()) {
1731 if (!Seen.
insert(V).second)
1733 if (Old2New.
find(V) != Old2New.
end())
1739 if (Value2Index.contains(V) || !
I ||
1750 for (
auto &Entry : Stack)
1753 CollectArguments(
Cond, IsSigned);
1756 for (
auto *
P : Args)
1762 Cond->getModule()->getName() +
1763 Cond->getFunction()->getName() +
"repro",
1766 for (
unsigned I = 0;
I < Args.size(); ++
I) {
1768 Old2New[Args[
I]] =
F->getArg(
I);
1773 Builder.CreateRet(Builder.getTrue());
1774 Builder.SetInsertPoint(Entry->getTerminator());
1783 auto &Value2Index = Info.getValue2Index(IsSigned);
1784 while (!WorkList.
empty()) {
1786 if (Old2New.
find(V) != Old2New.
end())
1790 if (!Value2Index.contains(V) &&
I) {
1791 Old2New[V] =
nullptr;
1801 Old2New[
I] = Cloned;
1802 Old2New[
I]->setName(
I->getName());
1814 for (
auto &Entry : Stack) {
1823 auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS);
1824 Builder.CreateAssumption(Cmp);
1829 CloneInstructions(
Cond, IsSigned);
1830 Entry->getTerminator()->setOperand(0,
Cond);
1838 ConstraintInfo &Info) {
1841 auto TryWithConstraint = [&](
const ConstraintTy &R) -> std::optional<bool> {
1844 return std::nullopt;
1847 auto &CSToUse = Info.getCS(R.IsSigned);
1848 if (
auto ImpliedCondition = R.isImpliedBy(CSToUse)) {
1850 return std::nullopt;
1852 dbgs() <<
"Condition ";
1854 *ImpliedCondition ? Pred
1857 dbgs() <<
" implied by dominating constraints\n";
1860 return ImpliedCondition;
1862 return std::nullopt;
1865 auto R = Info.getConstraintForSolving(Pred,
A,
B);
1866 if (
auto ImpliedCondition = TryWithConstraint(R))
1867 return ImpliedCondition;
1875 if (NewVariables.
empty() && !SR.empty() && Info.isKnownNonNegative(
A) &&
1876 Info.isKnownNonNegative(
B))
1877 if (
auto ImpliedCondition = TryWithConstraint(SR))
1878 return ImpliedCondition;
1884 const auto &Value2Index = Info.getValue2Index(
true);
1885 if (!Value2Index.contains(
A) && !Value2Index.contains(
B))
1886 return std::nullopt;
1889 auto SR = Info.getConstraint(Pred,
A,
B, NewVariables,
1891 if (NewVariables.
empty())
1892 if (
auto ImpliedCondition = TryWithConstraint(SR))
1893 return ImpliedCondition;
1895 return std::nullopt;
1900 ConstraintInfo &Info,
unsigned NumIn,
unsigned NumOut,
1904 auto ReplaceCmpWithConstant = [&](
Instruction *CheckInst,
bool IsTrue) {
1906 ReproducerCondStack, Info, DT);
1911 auto *DTN = DT.
getNode(UserI->getParent());
1914 if (UserI->getParent() == ContextInst->
getParent() &&
1915 UserI->comesBefore(ContextInst))
1921 return !
II ||
II->getIntrinsicID() != Intrinsic::assume;
1930 for (
auto *DVR : DVRUsers) {
1931 auto *DTN = DT.
getNode(DVR->getParent());
1935 auto *MarkedI = DVR->getInstruction();
1936 if (MarkedI->getParent() == ContextInst->
getParent() &&
1937 MarkedI->comesBefore(ContextInst))
1940 DVR->replaceVariableLocationOp(CheckInst, ConstantC);
1950 return ReplaceCmpWithConstant(CheckInst, *ImpliedCondition);
1957 return ReplaceCmpWithConstant(CheckInst, *ImpliedCondition);
1966 MinMax->replaceAllUsesWith(
MinMax->getOperand(UseLHS ? 0 : 1));
1975 return ReplaceMinMaxWithOperand(
MinMax, *ImpliedCondition);
1978 return ReplaceMinMaxWithOperand(
MinMax, !*ImpliedCondition);
1987 I->replaceAllUsesWith(ConstantInt::get(
I->getType(), 1));
1997 I->replaceAllUsesWith(ConstantInt::get(
I->getType(), 0));
2015 Value *
Sub = Builder.CreateSub(
A,
B,
"",
true,
2016 Info.isKnownNonNegative(
A));
2018 Sub->takeName(USub);
2025 Module *ReproducerModule,
2028 Info.popLastConstraint(
E.IsSigned);
2030 auto &Mapping = Info.getValue2Index(
E.IsSigned);
2031 for (
Value *V :
E.ValuesToRelease)
2033 Info.popLastNVariables(
E.IsSigned,
E.ValuesToRelease.size());
2035 if (ReproducerModule)
2042 FactOrCheck &CB, ConstraintInfo &Info,
Module *ReproducerModule,
2051 unsigned OtherOpIdx = JoinOp->
getOperand(0) == CmpToCheck ? 1 : 0;
2059 unsigned OldSize = DFSInStack.
size();
2062 while (OldSize < DFSInStack.
size()) {
2063 StackEntry
E = DFSInStack.
back();
2071 while (!Worklist.empty()) {
2072 Value *Val = Worklist.pop_back_val();
2080 Info.addFact(Pred,
LHS,
RHS, CB.NumIn, CB.NumOut, DFSInStack);
2085 Worklist.push_back(
LHS);
2086 Worklist.push_back(
RHS);
2089 if (OldSize == DFSInStack.
size())
2094 [[maybe_unused]]
bool Matched =
2096 assert(Matched &&
"expected icmp-like match");
2098 if (
auto ImpliedCondition =
checkCondition(Pred,
A,
B, CmpToCheck, Info)) {
2099 if (IsOr == *ImpliedCondition)
2112 unsigned NumIn,
unsigned NumOut,
2113 SmallVectorImpl<StackEntry> &DFSInStack) {
2114 addFactImpl(Pred,
A,
B, NumIn, NumOut, DFSInStack,
false);
2117 addFactImpl(Pred,
A,
B, NumIn, NumOut, DFSInStack,
true);
2119 tightenBoundUsingNe(
A,
B, NumIn, NumOut, DFSInStack);
2122void ConstraintInfo::tightenBoundUsingNe(
2124 SmallVectorImpl<StackEntry> &DFSInStack) {
2125 if (!
A->getType()->isIntegerTy())
2128 for (
bool IsSigned : {
false,
true}) {
2135 const auto &Value2Index = getValue2Index(IsSigned);
2137 [&Value2Index](
const DecompEntry &
E) {
2138 return !Value2Index.contains(
E.Variable);
2149 if (!doesHold(NonStrict,
A,
B))
2155 dbgs() <<
"' using inequality\n");
2156 addFactImpl(
Strict,
A,
B, NumIn, NumOut, DFSInStack,
2164 unsigned NumIn,
unsigned NumOut,
2165 SmallVectorImpl<StackEntry> &DFSInStack,
2166 bool ForceSignedSystem) {
2168 auto R = getConstraint(Pred,
A,
B, NewVariables, ForceSignedSystem);
2171 if (
R.empty() ||
R.isNe())
2176 auto &CSToUse = getCS(
R.IsSigned);
2177 bool Added = CSToUse.addRow(
R.Coefficients,
R.NumVars);
2183 SmallVector<Value *, 2> ValuesToRelease;
2184 auto &Value2Index = getValue2Index(
R.IsSigned);
2185 for (
Value *V : NewVariables) {
2186 Value2Index.try_emplace(V, Value2Index.size() + 1);
2191 dbgs() <<
" constraint: ";
2197 std::move(ValuesToRelease));
2200 for (
Value *V : NewVariables) {
2202 CSToUse.addRow({
Entry(0, 0),
Entry(-1, Value2Index.at(V))},
2203 Value2Index.size());
2205 SmallVector<Value *, 2>());
2211 for (Entry &
E :
R.Coefficients)
2214 CSToUse.addRow(
R.Coefficients,
R.NumVars);
2217 SmallVector<Value *, 2>());
2229 Value *Res =
nullptr;
2233 Res = Builder.CreateNoWrapBinOp(Opcode,
A,
B,
false,
2238 U->replaceAllUsesWith(Builder.getFalse());
2243 if (U->use_empty()) {
2251 if (
II->use_empty()) {
2253 for (
Use &Arg :
II->args())
2265 ConstraintInfo &Info) {
2266 auto R = Info.getConstraintForSolving(Pred,
A,
B);
2269 if (R.isConstantOnly())
2272 auto &CSToUse = Info.getCS(R.IsSigned);
2273 return CSToUse.isConditionImpliedInSubSystem(R.Coefficients);
2276 switch (
II->getIntrinsicID()) {
2277 case Intrinsic::ssub_with_overflow: {
2284 ConstantInt::get(
A->getType(), 0), Info))
2288 case Intrinsic::sadd_with_overflow: {
2313 ConstraintInfo Info(
F.getDataLayout(), FunctionArgs);
2314 State S(DT, LI, SE, TLI);
2315 std::unique_ptr<Module> ReproducerModule(
2334 stable_sort(S.WorkList, [](
const FactOrCheck &
A,
const FactOrCheck &
B) {
2335 auto HasNoConstOp = [](const FactOrCheck &B) {
2336 Value *V0 = B.isConditionFact() ? B.Cond.Op0 : B.Inst->getOperand(0);
2337 Value *V1 = B.isConditionFact() ? B.Cond.Op1 : B.Inst->getOperand(1);
2338 return !isa<ConstantInt>(V0) && !isa<ConstantInt>(V1);
2342 if (
A.NumIn ==
B.NumIn) {
2343 if (A.isConditionFact() && B.isConditionFact()) {
2344 bool NoConstOpA = HasNoConstOp(A);
2345 bool NoConstOpB = HasNoConstOp(B);
2346 return NoConstOpA < NoConstOpB;
2348 if (
A.isConditionFact())
2350 if (
B.isConditionFact())
2352 auto *InstA =
A.getContextInst();
2353 auto *InstB =
B.getContextInst();
2354 return InstA->comesBefore(InstB);
2356 return A.NumIn <
B.NumIn;
2359 SmallVector<Instruction *>
ToRemove;
2364 for (FactOrCheck &CB : S.WorkList) {
2367 while (!DFSInStack.
empty()) {
2368 auto &
E = DFSInStack.
back();
2371 LLVM_DEBUG(
dbgs() <<
"CB: " << CB.NumIn <<
" " << CB.NumOut <<
"\n");
2373 if (CB.NumOut <=
E.NumOut)
2376 dbgs() <<
"Removing ";
2378 Info.getValue2Index(
E.IsSigned));
2390 Instruction *Inst = CB.getInstructionToSimplify();
2397 LLVM_DEBUG(
dbgs() <<
"Processing condition to simplify: " << *Inst
2403 Pred,
A,
B, Inst, Info, CB.NumIn, CB.NumOut, CB.getContextInst(),
2404 ReproducerModule.get(), ReproducerCondStack, S.DT,
ToRemove);
2408 CB, Info, ReproducerModule.get(), ReproducerCondStack, DFSInStack,
2423 auto AddFact = [&](CmpPredicate Pred,
Value *
A,
Value *
B) {
2429 <<
"Skip adding constraint because system has too many rows.\n");
2433 Info.addFact(Pred,
A,
B, CB.NumIn, CB.NumOut, DFSInStack);
2434 if (ReproducerModule && DFSInStack.
size() > ReproducerCondStack.
size())
2443 CB.NumIn, CB.NumOut, DFSInStack);
2445 Info.transferToOtherSystem(Pred,
A,
B, CB.NumIn, CB.NumOut,
2459 SmallPtrSet<Value *, 4> Seen;
2460 while (!Worklist.
empty()) {
2463 if (!BO || BO->getOpcode() !=
Opc)
2465 for (
Value *
Op : {BO->getOperand(0), BO->getOperand(1)}) {
2469 Info.addFact(Pred,
Op,
B, CB.NumIn, CB.NumOut, DFSInStack);
2474 if (ReproducerModule && DFSInStack.
size() > ReproducerCondStack.
size()) {
2477 for (
unsigned I = 0,
2478 E = (DFSInStack.
size() - ReproducerCondStack.
size());
2480 ReproducerCondStack.
emplace_back(ICmpInst::BAD_ICMP_PREDICATE,
2486 if (!CB.isConditionFact()) {
2492 ConstantInt::get(CB.Inst->getType(), 0));
2498 Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
2499 AddFact(Pred, MinMax, MinMax->getLHS());
2500 AddFact(Pred, MinMax, MinMax->getRHS());
2504 switch (USatI->getIntrinsicID()) {
2507 case Intrinsic::uadd_sat:
2508 AddFact(ICmpInst::ICMP_UGE, USatI, USatI->getLHS());
2509 AddFact(ICmpInst::ICMP_UGE, USatI, USatI->getRHS());
2511 case Intrinsic::usub_sat:
2512 AddFact(ICmpInst::ICMP_ULE, USatI, USatI->getLHS());
2519 if (BO->getOpcode() == Instruction::URem) {
2526 if (BO->getOpcode() == Instruction::UDiv) {
2531 if (BO->getOpcode() == Instruction::LShr) {
2536 if (BO->getOpcode() == Instruction::SRem) {
2537 Value *
X = BO->getOperand(0);
2538 Value *
N = BO->getOperand(1);
2558 auto &
DL =
F.getDataLayout();
2559 auto AddFactsAboutIndices = [&](
Value *Ptr,
Type *AccessType) {
2564 DL.getTypeStoreSize(AccessType).getFixedValue(), Pred,
A,
B,
DL,
2566 AddFact(Pred,
A,
B);
2570 AddFactsAboutIndices(LI->getPointerOperand(), LI->getAccessType());
2574 AddFactsAboutIndices(
SI->getPointerOperand(),
SI->getAccessType());
2579 if (CB.isConditionFact()) {
2580 Pred = CB.Cond.Pred;
2584 !
Info.doesHold(CB.DoesHold.Pred, CB.DoesHold.Op0, CB.DoesHold.Op1)) {
2586 dbgs() <<
"Not adding fact ";
2588 dbgs() <<
" because precondition ";
2591 dbgs() <<
" does not hold.\n";
2596 [[maybe_unused]]
bool Matched =
2600 "Must have an assume intrinsic with a icmp like operand");
2602 AddFact(Pred,
A,
B);
2605 if (ReproducerModule && !ReproducerModule->functions().empty()) {
2607 raw_string_ostream StringS(S);
2608 ReproducerModule->print(StringS,
nullptr);
2609 OptimizationRemark Rem(
DEBUG_TYPE,
"Reproducer", &
F);
2610 Rem <<
ore::NV(
"module") << S;
2615 unsigned SignedEntries =
2616 count_if(DFSInStack, [](
const StackEntry &
E) {
return E.IsSigned; });
2617 assert(
Info.getCS(
false).size() - FunctionArgs.size() ==
2618 DFSInStack.
size() - SignedEntries &&
2619 "updates to CS and DFSInStack are out of sync");
2620 assert(
Info.getCS(
true).size() == SignedEntries &&
2621 "updates to CS and DFSInStack are out of sync");
2625 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 int64_t MinSignedConstraintValue
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 replaceOverflowUses(IntrinsicInst *II, Instruction::BinaryOps Opcode, Value *A, Value *B, SmallVectorImpl< Instruction * > &ToRemove)
Replace the uses of the overflow intrinsic II, which has been proven not to signed-overflow,...
static bool doesHoldInRange(const 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 bool preconditionHolds(const ConstraintInfo &Info, CmpInst::Predicate Pred, Value *Op, int64_t RHS)
Returns true if the pre-condition Op Pred RHS, required to look through an expression while decomposi...
static bool canUseSExt(ConstantInt *CI)
static bool tryToStrengthenBinOpFlags(Instruction *I, Value *Op0, Value *Op1, ConstraintInfo &Info)
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 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 Decomposition decompose(Value *V, const ConstraintInfo &Info, bool IsSigned, const DataLayout &DL)
static Decomposition decomposeGEP(GEPOperator &GEP, const ConstraintInfo &Info, bool IsSigned, const DataLayout &DL)
static void dumpConstraint(ArrayRef< Entry > C, const DenseMap< Value *, unsigned > &Value2Index)
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 bool tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
static Instruction * findCommonDominatorOfUses(Instruction &I, DominatorTree &DT)
Returns the closest program point dominating all uses of I.
static bool tryToStrengthenFlags(Instruction *I, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
Try to strengthen I's poison generating flags using Info.
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,...
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.
static bool hasNoUnsignedWrap(BinaryOperator &I)
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Machine Check Debug Module
uint64_t IntrinsicInst * II
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.
uint64_t getLimitedValue(uint64_t Limit=UINT64_MAX) const
If this value is smaller than the specified limit, return it, otherwise return the limit value.
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 makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp, const ConstantRange &Other, unsigned NoWrapKind)
Produce the largest range containing all X such that "X BinOp Y" is guaranteed not to wrap (overflow)...
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)
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.
A wrapper class for inspecting calls to intrinsic functions.
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.
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 const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Return LHS-RHS.
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'.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
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...
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.
BinaryOp_match< LHS, RHS, Instruction::Add > m_Add(const LHS &L, const RHS &R)
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.
OverflowingBinaryOp_match< LHS, RHS, Instruction::Sub, OverflowingBinaryOperator::NoSignedWrap > m_NSWSub(const LHS &L, const RHS &R)
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
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.
NoWrapTrunc_match< OpTy, TruncInst::NoSignedWrap > m_NSWTrunc(const OpTy &Op)
Matches trunc nsw.
NNegZExt_match< OpTy > m_NNegZExt(const OpTy &Op)
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
OverflowingBinaryOp_match< LHS, RHS, Instruction::Shl, OverflowingBinaryOperator::NoSignedWrap > m_NSWShl(const LHS &L, const RHS &R)
CastInst_match< OpTy, ZExtInst > m_ZExt(const OpTy &Op)
Matches ZExt.
OverflowingBinaryOp_match< LHS, RHS, Instruction::Shl, OverflowingBinaryOperator::NoUnsignedWrap > m_NUWShl(const LHS &L, const RHS &R)
OverflowingBinaryOp_match< LHS, RHS, Instruction::Mul, OverflowingBinaryOperator::NoUnsignedWrap > m_NUWMul(const LHS &L, const RHS &R)
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.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
match_combine_or< OverflowingBinaryOp_match< LHS, RHS, Instruction::Add, OverflowingBinaryOperator::NoSignedWrap >, DisjointOr_match< LHS, RHS > > m_NSWAddLike(const LHS &L, const RHS &R)
Match either "add nsw" or "or disjoint".
OverflowingBinaryOp_match< LHS, RHS, Instruction::Add, OverflowingBinaryOperator::NoSignedWrap > m_NSWAdd(const LHS &L, const RHS &R)
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.
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.
match_combine_or< OverflowingBinaryOp_match< LHS, RHS, Instruction::Add, OverflowingBinaryOperator::NoUnsignedWrap >, DisjointOr_match< LHS, RHS > > m_NUWAddLike(const LHS &L, const RHS &R)
Match either "add nuw" or "or disjoint".
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.
OverflowingBinaryOp_match< LHS, RHS, Instruction::Mul, OverflowingBinaryOperator::NoSignedWrap > m_NSWMul(const LHS &L, const RHS &R)
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...
@ 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.