55#define DEBUG_TYPE "constraint-elimination"
57STATISTIC(NumCondsRemoved,
"Number of instructions removed");
59 "Controls which conditions are eliminated");
67 UserI = Phi->getIncomingBlock(U)->getTerminator();
76 for (
Use &U :
I.uses()) {
102 : Pred(Pred), Op0(Op0), Op1(Op1) {}
140 FactOrCheck(EntryTy Ty,
DomTreeNode *DTN, Instruction *Inst,
141 Instruction *ContextInst =
nullptr)
142 : Inst(Inst), ContextInst(ContextInst ? ContextInst : Inst),
143 NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), Ty(Ty) {}
146 :
U(
U), ContextInst(nullptr), NumIn(DTN->getDFSNumIn()),
147 NumOut(DTN->getDFSNumOut()), Ty(EntryTy::UseCheck) {}
151 :
Cond(Pred, Op0, Op1), DoesHold(Precond), NumIn(DTN->getDFSNumIn()),
152 NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {}
154 static FactOrCheck getConditionFact(
DomTreeNode *DTN, CmpPredicate Pred,
157 return FactOrCheck(DTN, Pred, Op0, Op1, Precond);
160 static FactOrCheck getInstFact(
DomTreeNode *DTN, Instruction *Inst) {
161 return FactOrCheck(EntryTy::InstFact, DTN, Inst);
164 static FactOrCheck getCheck(
DomTreeNode *DTN, Use *U) {
165 return FactOrCheck(DTN, U);
168 static FactOrCheck getCheck(
DomTreeNode *DTN, Instruction *
I,
169 Instruction *ContextInst =
nullptr) {
171 "anchoring instruction must be in DTN's block");
172 return FactOrCheck(EntryTy::InstCheck, DTN,
I, ContextInst);
175 bool isCheck()
const {
176 return Ty == EntryTy::InstCheck || Ty == EntryTy::UseCheck;
180 assert(!isConditionFact());
181 if (Ty == EntryTy::UseCheck)
188 if (Ty == EntryTy::InstCheck)
194 bool isConditionFact()
const {
return Ty == EntryTy::ConditionFact; }
199struct MonotonicInfo {
201 bool Decreasing =
false;
203 bool Unsigned =
false;
214 TargetLibraryInfo &TLI;
217 State(DominatorTree &DT, LoopInfo &LI, ScalarEvolution *SE,
218 TargetLibraryInfo &TLI)
219 : DT(DT), LI(LI), SE(SE), TLI(TLI) {}
222 void addInfoFor(BasicBlock &BB);
226 void addBoundsForHeaderInductions(BasicBlock &BB);
230 void addInfoForInductions(BasicBlock &BB);
234 MonotonicInfo getMonotonicityInfo(PHINode &PN,
Value *Step);
238 bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ)
const {
239 return DT.dominates(BasicBlockEdge(&BB, Succ), Succ);
248 bool IsSigned =
false;
251 SmallVector<Value *, 2> ValuesToRelease;
253 StackEntry(
unsigned NumIn,
unsigned NumOut,
bool IsSigned,
254 SmallVector<Value *, 2> ValuesToRelease)
255 : NumIn(NumIn), NumOut(NumOut), IsSigned(IsSigned),
256 ValuesToRelease(std::
move(ValuesToRelease)) {}
263 unsigned NumVars = 0;
265 bool IsSigned =
false;
267 ConstraintTy() =
default;
269 ConstraintTy(RowTy Coefficients,
unsigned NumVars,
bool IsSigned,
bool IsEq,
271 : Coefficients(std::
move(Coefficients)), NumVars(NumVars),
272 IsSigned(IsSigned), IsEq(IsEq), IsNe(IsNe) {}
274 bool empty()
const {
return Coefficients.empty(); }
276 bool isEq()
const {
return IsEq; }
278 bool isNe()
const {
return IsNe; }
285 std::optional<bool> isImpliedBy(
const ConstraintSystem &CS)
const;
297 DecompEntry(int64_t Coefficient,
Value *Variable)
298 : Coefficient(Coefficient), Variable(Variable) {}
302struct Decomposition {
306 Decomposition(int64_t Offset) : Offset(Offset) {}
307 Decomposition(
Value *V) { Vars.emplace_back(1, V); }
309 : Offset(Offset), Vars(Vars) {}
313 [[nodiscard]]
bool add(int64_t OtherOffset) {
319 [[nodiscard]]
bool add(
const Decomposition &
Other) {
328 [[nodiscard]]
bool sub(
const Decomposition &
Other) {
329 Decomposition Tmp =
Other;
340 [[nodiscard]]
bool mul(int64_t Factor) {
343 for (
auto &Var : Vars)
344 if (
MulOverflow(Var.Coefficient, Factor, Var.Coefficient))
356class ConstraintInfo {
358 ConstraintSystem UnsignedCS;
359 ConstraintSystem SignedCS;
361 const DataLayout &DL;
365 DenseMap<PointerIntPair<Value *, 1, bool>, Decomposition> DecomposeCache;
368 DenseMap<PointerIntPair<Value *, 1, bool>, Decomposition> &
369 getDecomposeCache() {
370 return DecomposeCache;
374 : UnsignedCS(FunctionArgs), SignedCS(FunctionArgs), DL(DL) {
375 auto &Value2Index = getValue2Index(
false);
377 for (
Value *Arg : FunctionArgs)
378 UnsignedCS.addRow({
Entry(0, 0),
Entry(-1, Value2Index.at(Arg))},
382 DenseMap<Value *, unsigned> &getValue2Index(
bool Signed) {
383 return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
385 const DenseMap<Value *, unsigned> &getValue2Index(
bool Signed)
const {
386 return Signed ? SignedCS.getValue2Index() : UnsignedCS.getValue2Index();
389 ConstraintSystem &getCS(
bool Signed) {
390 return Signed ? SignedCS : UnsignedCS;
392 const ConstraintSystem &getCS(
bool Signed)
const {
393 return Signed ? SignedCS : UnsignedCS;
396 void popLastConstraint(
bool Signed) {
397 assert(DecomposeCache.empty() &&
"Cache must be cleared");
398 getCS(
Signed).popLastConstraint();
400 void popLastNVariables(
bool Signed,
unsigned N) {
401 assert(DecomposeCache.empty() &&
"Cache must be cleared");
402 getCS(
Signed).popLastNVariables(
N);
412 function_ref<std::optional<bool>()> Solve);
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)) {
505 bool Overflow =
false;
506 APInt CombinedOffset =
507 Result.ConstantOffset.sadd_ov(ConstantOffset2, Overflow);
511 Result.BasePtr = InnerGEP->getPointerOperand();
512 Result.ConstantOffset = CombinedOffset;
513 if (Result.VariableOffsets.size() == 0 && VariableOffsets2.
size() == 1)
514 Result.VariableOffsets = std::move(VariableOffsets2);
515 Result.NW &= InnerGEP->getNoWrapFlags();
520static Decomposition
decompose(
Value *V, ConstraintInfo &Info,
bool IsSigned,
536 int64_t RequiredOffset = -
static_cast<int64_t
>(Slack.
getZExtValue());
538 const auto &Value2Index = Info.getValue2Index(
Signed);
539 unsigned OpIdx = Value2Index.lookup(
Op);
543 int64_t OpCoefficient =
Upper ? 1 : -1;
544 unsigned OpSize =
Op->getType()->getScalarSizeInBits();
548 if (Row.size() != 3 || Row[0].Id != 0 ||
549 Row[0].Coefficient > RequiredOffset)
551 bool OpFirst = Row[1].Id == OpIdx;
552 const Entry &OpE = Row[OpFirst ? 1 : 2];
553 const Entry &WitnessE = Row[OpFirst ? 2 : 1];
554 if (OpE.Id != OpIdx || OpE.Coefficient != OpCoefficient ||
555 WitnessE.Coefficient != -OpCoefficient)
559 Value2Index, [&](
const auto &KV) {
return KV.second == WitnessE.Id; });
560 assert(Witness != Value2Index.end() &&
"row variables must be mapped");
561 Type *WitnessTy = Witness->first->getType();
572 if (R.isEmptySet() || (
Signed ? R.isSignWrappedSet() : R.isWrappedSet()))
578 unsigned BitWidth = R.getBitWidth();
579 APInt Min =
Signed ? R.getSignedMin() : R.getUnsignedMin();
580 APInt Max =
Signed ? R.getSignedMax() : R.getUnsignedMax();
586 APInt UpperSlack = MaxVal - Max;
594 ConstantInt::get(Ty, Min)) &&
599 ConstantInt::get(Ty, Max)) &&
608 unsigned NoWrapFlags, ConstraintInfo &Info,
612 if (NoWrapFlags & (
Signed ? OBO::NoSignedWrap : OBO::NoUnsignedWrap))
615 if (Opcode == Instruction::Sub) {
621 if (Info.isKnownNonNegative(Op1) &&
626 if (!
Signed && (NoWrapFlags & OBO::NoSignedWrap) &&
627 (Opcode == Instruction::Shl || Info.isKnownNonNegative(Op1)) &&
628 Info.isKnownNonNegative(Op0))
639 Opcode,
C->getValue(),
640 Signed ? OBO::NoSignedWrap : OBO::NoUnsignedWrap),
651 return isKnownNoWrap(WO->getBinaryOp(), WO->getLHS(), WO->getRHS(),
656 return Trunc->hasNoSignedWrap();
660 return Trunc->hasNoUnsignedWrap() ||
661 (Trunc->hasNoSignedWrap() &&
662 Info.isKnownNonNegative(Trunc->getOperand(0)));
668 BO->getOperand(0), BO->getOperand(1),
669 BO->getNoWrapKind(), Info,
Signed);
676 if (
DL.getIndexTypeSizeInBits(
GEP.getPointerOperand()->getType()) > 64)
679 assert(!IsSigned &&
"The logic below only supports decomposition for "
680 "unsigned predicates at the moment.");
681 const auto &[BasePtr, ConstantOffset, VariableOffsets, NW] =
690 if (!NW.hasNoUnsignedSignedWrap() && ConstantOffset.isNegative())
693 Decomposition Result(ConstantOffset.getSExtValue(), DecompEntry(1, BasePtr));
694 for (
auto [Index, Scale] : VariableOffsets) {
697 if (Index->getType()->getScalarSizeInBits() != Scale.getBitWidth())
699 if (!NW.hasNoUnsignedWrap()) {
702 assert(NW.hasNoUnsignedSignedWrap() &&
"Must have nusw flag");
703 if (!Info.isKnownNonNegative(Index))
705 }
else if (!NW.hasNoUnsignedSignedWrap()) {
708 if (Scale.isNegative())
712 auto IdxResult =
decompose(Index, Info, IsSigned,
DL);
713 if (IdxResult.mul(Scale.getSExtValue()))
715 if (Result.add(IdxResult))
735 switch (
Op->getOpcode()) {
736 case Instruction::GetElementPtr:
737 case Instruction::Add:
738 case Instruction::Sub:
739 case Instruction::Mul:
740 case Instruction::Shl:
741 case Instruction::LShr:
742 case Instruction::AShr:
743 case Instruction::ZExt:
744 case Instruction::SExt:
745 case Instruction::Trunc:
746 case Instruction::Or:
747 case Instruction::Xor:
760 auto &Cache = Info.getDecomposeCache();
761 auto It = Cache.find(
Key);
762 if (It != Cache.end())
766 Info.getDecomposeCache().insert({
Key, Result});
772 auto MergeResults = [&Info, IsSigned,
774 bool IsSignedB) -> std::optional<Decomposition> {
783 if (Ty->isPointerTy() && !IsSigned) {
795 if (!Ty->isIntegerTy() || Ty->getIntegerBitWidth() > 64)
801 return CI->getSExtValue();
803 return int64_t(CI->getZExtValue());
819 if (!IsSigned && !Info.isKnownNonNegative(Op0))
823 if (Trunc->getSrcTy()->getScalarSizeInBits() <= 64 &&
825 V = Trunc->getOperand(0);
830 if (
auto Decomp = MergeResults(Op0, Op1, IsSigned))
840 if (
auto Decomp = MergeResults(Op0, CI,
true))
847 Decomposition Result(-1);
848 if (!Result.sub(
decompose(Op0, Info, IsSigned,
DL)))
876 bool IsAShr =
cast<Operator>(V)->getOpcode() == Instruction::AShr;
878 (IsSigned == IsAShr || Info.isKnownNonNegative(Op0))) {
881 if (Result.Offset % Factor == 0 &&
882 all_of(Result.Vars, [Factor](
const DecompEntry &
E) {
883 return E.Coefficient % Factor == 0;
885 Result.Offset /= Factor;
886 for (
auto &
E : Result.Vars)
887 E.Coefficient /= Factor;
898 int64_t MaxShift = IsSigned ? Ty->getIntegerBitWidth() - 1 : 63;
916 const Decomposition &BDec,
922 if (
SubOverflow(BDec.Offset, ADec.Offset, OffsetSum))
924 RowTy R(1, Entry(OffsetSum, 0));
925 auto GetCoefficient = [&R](
unsigned Idx) -> int64_t & {
930 if (
I == R.end() ||
I->Id != Idx)
931 I = R.insert(
I, Entry(0, Idx));
932 return I->Coefficient;
936 auto GetOrAddIndex = [&Value2Index, &NewVariables](
Value *V) ->
unsigned {
937 auto V2I = Value2Index.
find(V);
938 if (V2I != Value2Index.
end())
940 unsigned Idx =
find(NewVariables, V) - NewVariables.
begin();
941 if (Idx == NewVariables.
size())
943 return Value2Index.
size() + Idx + 1;
945 for (
const DecompEntry &KV : ADec.Vars)
946 GetCoefficient(GetOrAddIndex(KV.Variable)) += KV.Coefficient;
948 for (
const DecompEntry &KV : BDec.Vars) {
949 auto &Coeff = GetCoefficient(GetOrAddIndex(KV.Variable));
955 erase_if(R, [](
const Entry &
E) {
return E.Id != 0 &&
E.Coefficient == 0; });
962 bool ForceSignedSystem) {
963 assert(NewVariables.
empty() &&
"NewVariables must be empty when passed in");
965 "signed system can only be forced on eq/ne");
1006 auto &Value2Index = getValue2Index(IsSigned);
1016 if (
AddOverflow(R[0].Coefficient, int64_t(-1), R[0].Coefficient))
1020 unsigned NumV2I = Value2Index.size();
1021 NewVariables.
truncate(
R.back().Id > NumV2I ?
R.back().Id - NumV2I : 0);
1023 return ConstraintTy(std::move(R), Value2Index.size() + NewVariables.
size(),
1024 IsSigned, IsEq, IsNe);
1035 return ConstraintTy(RowTy(1,
Entry(0, 0)), 0,
1036 false,
false,
false);
1048 ConstraintTy
R = getConstraint(Pred, Op0, Op1, NewVariables);
1049 if (!NewVariables.
empty())
1055ConstraintTy::isImpliedBy(
const ConstraintSystem &CS)
const {
1056 const auto &[SubCS, NewCoefficients] = CS.
getSubSystem(Coefficients);
1057 bool IsConditionImplied = SubCS.isConditionImplied(NewCoefficients);
1061 bool IsNegatedOrEqualImplied =
1062 !NegatedOrEqual.empty() && SubCS.isConditionImplied(NegatedOrEqual);
1067 if (IsConditionImplied && IsNegatedOrEqualImplied)
1071 bool IsNegatedImplied =
1072 !Negated.empty() && SubCS.isConditionImplied(Negated);
1075 bool IsStrictLessThanImplied =
1076 !StrictLessThan.empty() && SubCS.isConditionImplied(StrictLessThan);
1082 if (IsNegatedImplied || IsStrictLessThanImplied)
1085 return std::nullopt;
1088 if (IsConditionImplied)
1092 auto IsNegatedImplied = !Negated.empty() && SubCS.isConditionImplied(Negated);
1093 if (IsNegatedImplied)
1097 return std::nullopt;
1101 ConstraintInfo &Info,
1102 const DataLayout &
DL);
1105ConstraintInfo::tryWithLinkRows(
Value *
A,
Value *
B,
const ConstraintTy &
C,
1106 function_ref<std::optional<bool>()> Solve) {
1107 if (std::optional<bool> Res = Solve())
1110 return std::nullopt;
1112 auto &CS = getCS(
C.IsSigned);
1113 unsigned NumVars = getValue2Index(
C.IsSigned).size();
1114 unsigned NumPushed = 0;
1118 if (Row.empty() || Negated.empty())
1120 NumPushed += CS.
addRow(Row, NumVars);
1121 NumPushed += CS.
addRow(Negated, NumVars);
1124 return std::nullopt;
1126 unsigned NumRows = CS.
size();
1128 std::optional<bool> Res = Solve();
1129 assert(CS.
size() == NumRows &&
"rows added while link rows are pushed");
1136 auto R = getConstraintForSolving(Pred,
A,
B);
1139 auto &CS = getCS(
R.IsSigned);
1140 return tryWithLinkRows(
A,
B, R,
1141 [&]() -> std::optional<bool> {
1144 return std::nullopt;
1149bool ConstraintInfo::isKnownNonNegative(
Value *V) {
1151 return !CI->isNegative();
1152 return ::isKnownNonNegative(V,
DL) ||
1156bool ConstraintInfo::isKnownPositive(
Value *V) {
1158 return CI->getValue().isStrictlyPositive();
1159 return ::isKnownPositive(V,
DL) ||
1163void ConstraintInfo::transferToOtherSystem(
1165 unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack) {
1168 if (!
A->getType()->isIntegerTy())
1181 NumOut, DFSInStack);
1191 NumOut, DFSInStack);
1205 NumOut, DFSInStack);
1231static std::pair<Value *, Value *>
1234 "LoopPred must be a predecessor of the phi's block");
1236 return {
nullptr,
nullptr};
1243template <
typename PhiMatchTy>
1252MonotonicInfo State::getMonotonicityInfo(PHINode &PN,
Value *Step) {
1254 const APInt *StepOffset =
nullptr;
1258 Info.Unsigned = !
Info.Decreasing &&
Add->hasNoUnsignedWrap();
1259 Info.Signed =
Add->hasNoSignedWrap();
1265 APInt GEPOffset(
DL.getIndexTypeSizeInBits(
GEP->getType()), 0);
1266 Info.Unsigned =
GEP->getPointerOperand() == &PN &&
1267 (
GEP->hasNoUnsignedWrap() ||
1268 ((
GEP->hasNoUnsignedSignedWrap() &&
1269 GEP->accumulateConstantOffset(
DL, GEPOffset) &&
1270 !GEPOffset.isNegative())));
1275 if (
Info.Unsigned ||
Info.Signed || !StepOffset)
1292void State::addBoundsForHeaderInductions(BasicBlock &BB) {
1294 if (!L ||
L->getHeader() != &BB)
1301 for (PHINode &PN : BB.
phis()) {
1309 MonotonicInfo
Info = getMonotonicityInfo(PN, Step);
1313 Info.Unsigned =
false;
1314 if (!
Info.Unsigned && !
Info.Signed)
1320 if (
Info.Decreasing)
1324 WorkList.
push_back(FactOrCheck::getConditionFact(DTN, Pred,
LHS,
RHS));
1328void State::addInfoForInductions(BasicBlock &BB) {
1335 if (Header != &BB && Latch != &BB)
1342 PHINode *PN =
nullptr;
1343 const APInt *IncStep =
nullptr;
1353 std::optional<bool> PeeledOnEdge;
1354 if (!
match(Br->getCondition(), CountingCmp)) {
1358 PeeledOnEdge =
true;
1360 PeeledOnEdge =
false;
1369 bool ContinueOnTrue =
1373 BasicBlock *InLoopSucc = Br->getSuccessor(ContinueOnTrue ? 0 : 1);
1377 if (PeeledOnEdge && *PeeledOnEdge != ContinueOnTrue)
1380 if (!
L->contains(InLoopSucc) || !
L->isLoopExiting(&BB))
1384 if (!LoopPred || !
L->isLoopInvariant(
B))
1396 bool HasHeaderBound =
1400 if (HasHeaderBound) {
1402 WorkList.
push_back(FactOrCheck::getConditionFact(
1403 HeaderDTN, BoundPred, PN,
B,
ConditionTy(BoundPred, StartValue,
B)));
1412 if (&BB == Latch && !IncStep)
1422 WorkList.
push_back(FactOrCheck::getConditionFact(
1423 HeaderDTN, ContinuePred, PN,
B,
1429 if (ICmpInst::isSigned(ContinuePred)) {
1432 "Expected a signed less-than continuation predicate");
1433 MonotonicInfo
Info = getMonotonicityInfo(*PN, Backedge);
1434 if (
Info.Signed && !
Info.Decreasing) {
1436 WorkList.
push_back(FactOrCheck::getConditionFact(
1437 HeaderDTN, UPred, PN,
B,
ConditionTy(UPred, StartValue,
B)));
1446 const APInt *StepOffset =
nullptr;
1447 const SCEV *StartSCEV =
nullptr;
1449 if (StepOffset->
isZero())
1452 const SCEV *Expr = SE->
getSCEV(PN);
1461 if (IncStep && *IncStep != *StepOffset)
1464 MonotonicInfo
Info = getMonotonicityInfo(*PN, Backedge);
1469 if (!(-*StepOffset).isOne())
1479 ConditionTy BBeforeStartUnsigned = {UPrecond,
B, StartValue};
1485 WorkList.
push_back(FactOrCheck::getConditionFact(
1487 if (!(
Info.Decreasing &&
Info.Signed))
1488 WorkList.
push_back(FactOrCheck::getConditionFact(
1492 B, BBeforeStartUnsigned));
1494 B, BBeforeStartSigned));
1504 if (!StepOffset->
isOne()) {
1507 StartSCEV = SE->
getSCEV(StartValue);
1521 ConditionTy StartBeforeBoundUnsigned = {UPrecond, StartValue,
B};
1527 WorkList.
push_back(FactOrCheck::getConditionFact(
1530 WorkList.
push_back(FactOrCheck::getConditionFact(
1535 if (!HasHeaderBound || !canAddSuccessor(BB, InLoopSucc)) {
1536 WorkList.
push_back(FactOrCheck::getConditionFact(
1538 WorkList.
push_back(FactOrCheck::getConditionFact(
1551 L->getExitBlocks(ExitBBs);
1552 for (BasicBlock *EB : ExitBBs) {
1566 if (!
GEP.hasNoUnsignedWrap())
1571 Base = InnerGEP->getPointerOperand();
1587 if (
Offset.VariableOffsets.size() != 1)
1591 auto &[Index, Scale] =
Offset.VariableOffsets.front();
1593 if (Index->getType()->getScalarSizeInBits() !=
BitWidth)
1606 B = ConstantInt::get(Index->getType(), MaxIndex);
1614 return Trunc->getType()->isIntegerTy() && Trunc->hasNoSignedWrap() &&
1615 !Trunc->hasNoUnsignedWrap();
1618 if (!BO || !BO->getType()->isIntegerTy())
1621 switch (BO->getOpcode()) {
1622 case Instruction::Sub:
1623 if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())
1628 case Instruction::Add:
1629 case Instruction::Mul:
1630 case Instruction::Shl:
1631 if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())
1650 I->setHasNoSignedWrap();
1655 I->setHasNoUnsignedWrap();
1661void State::addInfoFor(BasicBlock &BB) {
1662 addBoundsForHeaderInductions(BB);
1663 addInfoForInductions(BB);
1669 bool GuaranteedToExecute =
true;
1671 for (Instruction &
I : BB) {
1673 for (Use &U :
I.uses()) {
1675 auto *DTN = DT.
getNode(UserI->getParent());
1678 WorkList.
push_back(FactOrCheck::getCheck(DTN, &U));
1683 auto AddFactFromMemoryAccess = [&](
Value *Ptr,
Type *AccessType) {
1687 TypeSize AccessSize =
DL.getTypeStoreSize(AccessType);
1690 if (GuaranteedToExecute) {
1692 Pred,
A,
B,
DL, TLI)) {
1700 FactOrCheck::getInstFact(DT.
getNode(
I.getParent()), &
I));
1705 if (!LI->isVolatile())
1706 AddFactFromMemoryAccess(LI->getPointerOperand(), LI->getAccessType());
1709 if (!
SI->isVolatile())
1710 AddFactFromMemoryAccess(
SI->getPointerOperand(),
SI->getAccessType());
1716 case Intrinsic::assume: {
1719 if (GuaranteedToExecute) {
1726 FactOrCheck::getInstFact(DT.
getNode(
I.getParent()), &
I));
1731 case Intrinsic::uadd_with_overflow:
1732 case Intrinsic::sadd_with_overflow:
1733 case Intrinsic::usub_with_overflow:
1734 case Intrinsic::ssub_with_overflow:
1735 case Intrinsic::umul_with_overflow:
1736 case Intrinsic::smul_with_overflow:
1737 case Intrinsic::ucmp:
1738 case Intrinsic::scmp:
1743 case Intrinsic::umin:
1744 case Intrinsic::umax:
1745 case Intrinsic::smin:
1746 case Intrinsic::smax:
1747 case Intrinsic::usub_sat:
1752 case Intrinsic::uadd_sat:
1758 case Intrinsic::abs:
1773 if ((BO->getOpcode() == Instruction::URem ||
1774 BO->getOpcode() == Instruction::UDiv ||
1775 BO->getOpcode() == Instruction::LShr ||
1776 BO->getOpcode() == Instruction::SRem ||
1777 BO->getOpcode() == Instruction::SDiv) &&
1786 WorkList.
push_back(FactOrCheck::getCheck(
1794 for (
auto &Case :
Switch->cases()) {
1796 Value *
V = Case.getCaseValue();
1797 if (!canAddSuccessor(BB, Succ))
1826 SmallPtrSet<Value *, 8> SeenCond;
1827 auto QueueValue = [&CondWorkList, &SeenCond](
Value *
V) {
1828 if (SeenCond.
insert(V).second)
1833 while (!CondWorkList.
empty()) {
1858 if (canAddSuccessor(BB, Br->getSuccessor(0)))
1860 DT.
getNode(Br->getSuccessor(0)), Pred,
A,
B));
1861 if (canAddSuccessor(BB, Br->getSuccessor(1)))
1869 OS <<
"icmp " << Pred <<
' ';
1870 LHS->printAsOperand(OS,
true);
1872 RHS->printAsOperand(OS,
false);
1881struct ReproducerEntry {
1882 ICmpInst::Predicate Pred;
1917 auto &Value2Index = Info.getValue2Index(IsSigned);
1919 while (!WorkList.
empty()) {
1921 if (!Seen.
insert(V).second)
1923 if (Old2New.
find(V) != Old2New.
end())
1929 if (Value2Index.contains(V) || !
I ||
1940 for (
auto &Entry : Stack)
1943 CollectArguments(
Cond, IsSigned);
1946 for (
auto *
P : Args)
1952 Cond->getModule()->getName() +
1953 Cond->getFunction()->getName() +
"repro",
1956 for (
unsigned I = 0;
I < Args.size(); ++
I) {
1958 Old2New[Args[
I]] =
F->getArg(
I);
1963 Builder.CreateRet(Builder.getTrue());
1964 Builder.SetInsertPoint(Entry->getTerminator());
1973 auto &Value2Index = Info.getValue2Index(IsSigned);
1974 while (!WorkList.
empty()) {
1976 if (Old2New.
find(V) != Old2New.
end())
1980 if (!Value2Index.contains(V) &&
I) {
1981 Old2New[V] =
nullptr;
1991 Old2New[
I] = Cloned;
1992 Old2New[
I]->setName(
I->getName());
2004 for (
auto &Entry : Stack) {
2013 auto *Cmp = Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS);
2014 Builder.CreateAssumption(Cmp);
2019 CloneInstructions(
Cond, IsSigned);
2020 Entry->getTerminator()->setOperand(0,
Cond);
2031 ConstraintInfo &Info,
2033 const auto &Value2Index = Info.getValue2Index(
C.IsSigned);
2034 auto It = Value2Index.find(V);
2035 if (It == Value2Index.end() ||
2037 [Id = It->second](
const Entry &
E) { return E.Id == Id; }))
2043 Value2Index, NewVariables);
2044 return NewVariables.
empty() ? Row : RowTy();
2049 ConstraintInfo &Info) {
2052 auto TryWithConstraint = [&](
const ConstraintTy &R) -> std::optional<bool> {
2055 return std::nullopt;
2058 auto &CSToUse = Info.getCS(R.IsSigned);
2059 if (
auto ImpliedCondition = R.isImpliedBy(CSToUse)) {
2061 return std::nullopt;
2063 dbgs() <<
"Condition ";
2065 *ImpliedCondition ? Pred
2068 dbgs() <<
" implied by dominating constraints\n";
2071 return ImpliedCondition;
2073 return std::nullopt;
2078 auto TryWithLinkedDecomposition =
2079 [&](
const ConstraintTy &
C) -> std::optional<bool> {
2080 return Info.tryWithLinkRows(
A,
B,
C, [&] {
return TryWithConstraint(
C); });
2083 auto R = Info.getConstraintForSolving(Pred,
A,
B);
2084 if (
auto ImpliedCondition = TryWithLinkedDecomposition(R))
2085 return ImpliedCondition;
2093 if (NewVariables.
empty() && !SR.empty() && Info.isKnownNonNegative(
A) &&
2094 Info.isKnownNonNegative(
B))
2095 if (
auto ImpliedCondition = TryWithConstraint(SR))
2096 return ImpliedCondition;
2102 const auto &Value2Index = Info.getValue2Index(
true);
2103 if (!Value2Index.contains(
A) && !Value2Index.contains(
B))
2104 return std::nullopt;
2107 auto SR = Info.getConstraint(Pred,
A,
B, NewVariables,
2109 if (NewVariables.
empty()) {
2110 if (
auto ImpliedCondition = TryWithLinkedDecomposition(SR))
2111 return ImpliedCondition;
2114 return std::nullopt;
2119 ConstraintInfo &Info,
unsigned NumIn,
unsigned NumOut,
2123 auto ReplaceCmpWithConstant = [&](
Instruction *CheckInst,
bool IsTrue) {
2125 ReproducerCondStack, Info, DT);
2130 auto *DTN = DT.
getNode(UserI->getParent());
2133 if (UserI->getParent() == ContextInst->
getParent() &&
2134 UserI->comesBefore(ContextInst))
2140 return !
II ||
II->getIntrinsicID() != Intrinsic::assume;
2149 for (
auto *DVR : DVRUsers) {
2150 auto *DTN = DT.
getNode(DVR->getParent());
2154 auto *MarkedI = DVR->getInstruction();
2155 if (MarkedI->getParent() == ContextInst->
getParent() &&
2156 MarkedI->comesBefore(ContextInst))
2159 DVR->replaceVariableLocationOp(CheckInst, ConstantC);
2169 return ReplaceCmpWithConstant(CheckInst, *ImpliedCondition);
2176 return ReplaceCmpWithConstant(CheckInst, *ImpliedCondition);
2185 MinMax->replaceAllUsesWith(
MinMax->getOperand(UseLHS ? 0 : 1));
2194 return ReplaceMinMaxWithOperand(
MinMax, *ImpliedCondition);
2197 return ReplaceMinMaxWithOperand(
MinMax, !*ImpliedCondition);
2206 I->replaceAllUsesWith(ConstantInt::get(
I->getType(), 1));
2216 I->replaceAllUsesWith(ConstantInt::get(
I->getType(), 0));
2234 Value *
Sub = Builder.CreateSub(
A,
B,
"",
true,
2235 Info.isKnownNonNegative(
A));
2237 Sub->takeName(USub);
2244 Module *ReproducerModule,
2247 Info.getDecomposeCache().clear();
2248 Info.popLastConstraint(
E.IsSigned);
2250 auto &Mapping = Info.getValue2Index(
E.IsSigned);
2251 for (
Value *V :
E.ValuesToRelease)
2253 Info.popLastNVariables(
E.IsSigned,
E.ValuesToRelease.size());
2255 if (ReproducerModule)
2262 FactOrCheck &CB, ConstraintInfo &Info,
Module *ReproducerModule,
2271 unsigned OtherOpIdx = JoinOp->
getOperand(0) == CmpToCheck ? 1 : 0;
2279 unsigned OldSize = DFSInStack.
size();
2282 while (OldSize < DFSInStack.
size()) {
2283 StackEntry
E = DFSInStack.
back();
2291 while (!Worklist.empty()) {
2292 Value *Val = Worklist.pop_back_val();
2300 Info.addFact(Pred,
LHS,
RHS, CB.NumIn, CB.NumOut, DFSInStack);
2305 Worklist.push_back(
LHS);
2306 Worklist.push_back(
RHS);
2309 if (OldSize == DFSInStack.
size())
2314 [[maybe_unused]]
bool Matched =
2316 assert(Matched &&
"expected icmp-like match");
2318 if (
auto ImpliedCondition =
checkCondition(Pred,
A,
B, CmpToCheck, Info)) {
2319 if (IsOr == *ImpliedCondition)
2332 unsigned NumIn,
unsigned NumOut,
2333 SmallVectorImpl<StackEntry> &DFSInStack) {
2334 addFactImpl(Pred,
A,
B, NumIn, NumOut, DFSInStack,
false);
2337 addFactImpl(Pred,
A,
B, NumIn, NumOut, DFSInStack,
true);
2339 tightenBoundUsingNe(
A,
B, NumIn, NumOut, DFSInStack);
2342void ConstraintInfo::tightenBoundUsingNe(
2344 SmallVectorImpl<StackEntry> &DFSInStack) {
2345 if (!
A->getType()->isIntOrPtrTy())
2348 for (
bool IsSigned : {
false,
true}) {
2355 const auto &Value2Index = getValue2Index(IsSigned);
2357 [&Value2Index](
const DecompEntry &
E) {
2358 return !Value2Index.contains(
E.Variable);
2369 if (!doesHold(NonStrict,
A,
B))
2375 dbgs() <<
"' using inequality\n");
2376 addFactImpl(
Strict,
A,
B, NumIn, NumOut, DFSInStack,
2384 unsigned NumIn,
unsigned NumOut,
2385 SmallVectorImpl<StackEntry> &DFSInStack,
2386 bool ForceSignedSystem) {
2388 auto R = getConstraint(Pred,
A,
B, NewVariables, ForceSignedSystem);
2391 if (
R.empty() ||
R.isNe())
2394 auto &CSToUse = getCS(
R.IsSigned);
2398 if (!
R.isEq() && NewVariables.
empty()) {
2400 if (CSToUse.isImpliedBySingleRow(
R.Coefficients))
2405 bool Added = CSToUse.addRow(
R.Coefficients,
R.NumVars);
2409 DecomposeCache.
clear();
2413 SmallVector<Value *, 2> ValuesToRelease;
2414 auto &Value2Index = getValue2Index(
R.IsSigned);
2415 for (
Value *V : NewVariables) {
2416 Value2Index.try_emplace(V, Value2Index.size() + 1);
2421 dbgs() <<
" constraint: ";
2427 std::move(ValuesToRelease));
2430 for (
Value *V : NewVariables) {
2432 CSToUse.addRow({
Entry(0, 0),
Entry(-1, Value2Index.at(V))},
2433 Value2Index.size());
2435 SmallVector<Value *, 2>());
2441 for (Entry &
E :
R.Coefficients)
2444 CSToUse.addRow(
R.Coefficients,
R.NumVars);
2447 SmallVector<Value *, 2>());
2457 Value *Res =
nullptr;
2461 Res = Builder.CreateNoWrapBinOp(
II->getBinaryOp(),
II->getLHS(),
2468 U->replaceAllUsesWith(Builder.getFalse());
2473 if (U->use_empty()) {
2481 if (
II->use_empty()) {
2483 for (
Use &Arg :
II->args())
2507 ConstraintInfo Info(
F.getDataLayout(), FunctionArgs);
2508 State S(DT, LI, SE, TLI);
2509 std::unique_ptr<Module> ReproducerModule(
2510 Opts.constraint_elimination_dump_reproducers
2511 ?
new Module(
F.getName(),
F.getContext())
2530 stable_sort(S.WorkList, [](
const FactOrCheck &
A,
const FactOrCheck &
B) {
2531 auto HasNoConstOp = [](const FactOrCheck &B) {
2532 Value *V0 = B.isConditionFact() ? B.Cond.Op0 : B.Inst->getOperand(0);
2533 Value *V1 = B.isConditionFact() ? B.Cond.Op1 : B.Inst->getOperand(1);
2534 return !isa<ConstantInt>(V0) && !isa<ConstantInt>(V1);
2538 if (
A.NumIn ==
B.NumIn) {
2539 if (A.isConditionFact() && B.isConditionFact()) {
2540 bool NoConstOpA = HasNoConstOp(A);
2541 bool NoConstOpB = HasNoConstOp(B);
2542 return NoConstOpA < NoConstOpB;
2544 if (
A.isConditionFact())
2546 if (
B.isConditionFact())
2548 auto *InstA =
A.getContextInst();
2549 auto *InstB =
B.getContextInst();
2550 return InstA->comesBefore(InstB);
2552 return A.NumIn <
B.NumIn;
2555 SmallVector<Instruction *>
ToRemove;
2560 for (FactOrCheck &CB : S.WorkList) {
2563 while (!DFSInStack.
empty()) {
2564 auto &
E = DFSInStack.
back();
2567 LLVM_DEBUG(
dbgs() <<
"CB: " << CB.NumIn <<
" " << CB.NumOut <<
"\n");
2569 if (CB.NumOut <=
E.NumOut)
2572 dbgs() <<
"Removing ";
2574 Info.getValue2Index(
E.IsSigned));
2586 Instruction *Inst = CB.getInstructionToSimplify();
2593 LLVM_DEBUG(
dbgs() <<
"Processing condition to simplify: " << *Inst
2599 Pred,
A,
B, Inst, Info, CB.NumIn, CB.NumOut, CB.getContextInst(),
2600 ReproducerModule.get(), ReproducerCondStack, S.DT,
ToRemove);
2604 CB, Info, ReproducerModule.get(), ReproducerCondStack, DFSInStack,
2619 auto AddFact = [&](CmpPredicate Pred,
Value *
A,
Value *
B) {
2623 Opts.constraint_elimination_max_rows) {
2626 <<
"Skip adding constraint because system has too many rows.\n");
2630 Info.addFact(Pred,
A,
B, CB.NumIn, CB.NumOut, DFSInStack);
2631 if (ReproducerModule && DFSInStack.
size() > ReproducerCondStack.
size())
2640 CB.NumIn, CB.NumOut, DFSInStack);
2642 Info.transferToOtherSystem(Pred,
A,
B, CB.NumIn, CB.NumOut,
2656 SmallPtrSet<Value *, 4> Seen;
2657 while (!Worklist.
empty()) {
2660 if (!BO || BO->getOpcode() !=
Opc)
2662 for (
Value *
Op : {BO->getOperand(0), BO->getOperand(1)}) {
2666 Info.addFact(Pred,
Op,
B, CB.NumIn, CB.NumOut, DFSInStack);
2671 if (ReproducerModule && DFSInStack.
size() > ReproducerCondStack.
size()) {
2674 for (
unsigned I = 0,
2675 E = (DFSInStack.
size() - ReproducerCondStack.
size());
2677 ReproducerCondStack.
emplace_back(ICmpInst::BAD_ICMP_PREDICATE,
2683 if (!CB.isConditionFact()) {
2689 ConstantInt::get(CB.Inst->getType(), 0));
2695 Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
2696 AddFact(Pred, MinMax, MinMax->getLHS());
2697 AddFact(Pred, MinMax, MinMax->getRHS());
2701 switch (USatI->getIntrinsicID()) {
2704 case Intrinsic::uadd_sat:
2705 AddFact(ICmpInst::ICMP_UGE, USatI, USatI->getLHS());
2706 AddFact(ICmpInst::ICMP_UGE, USatI, USatI->getRHS());
2708 case Intrinsic::usub_sat:
2709 AddFact(ICmpInst::ICMP_ULE, USatI, USatI->getLHS());
2716 if (BO->getOpcode() == Instruction::URem) {
2723 if (BO->getOpcode() == Instruction::UDiv) {
2728 if (BO->getOpcode() == Instruction::LShr) {
2733 if (BO->getOpcode() == Instruction::SRem) {
2734 Value *
X = BO->getOperand(0);
2735 Value *
N = BO->getOperand(1);
2753 if (BO->getOpcode() == Instruction::SDiv) {
2754 Value *
X = BO->getOperand(0);
2755 Value *
N = BO->getOperand(1);
2756 if (!
Info.isKnownNonNegative(
X) || !
Info.isKnownPositive(
N))
2759 bool IsStrict =
Info.isKnownPositive(
X) &&
2761 ConstantInt::get(
N->getType(), 1));
2768 auto &
DL =
F.getDataLayout();
2769 auto AddFactsAboutIndices = [&](
Value *Ptr,
Type *AccessType) {
2774 DL.getTypeStoreSize(AccessType).getFixedValue(), Pred,
A,
B,
DL,
2776 AddFact(Pred,
A,
B);
2780 AddFactsAboutIndices(LI->getPointerOperand(), LI->getAccessType());
2784 AddFactsAboutIndices(
SI->getPointerOperand(),
SI->getAccessType());
2789 if (CB.isConditionFact()) {
2790 Pred = CB.Cond.Pred;
2794 !
Info.doesHold(CB.DoesHold.Pred, CB.DoesHold.Op0, CB.DoesHold.Op1)) {
2796 dbgs() <<
"Not adding fact ";
2798 dbgs() <<
" because precondition ";
2801 dbgs() <<
" does not hold.\n";
2806 [[maybe_unused]]
bool Matched =
2810 "Must have an assume intrinsic with a icmp like operand");
2812 AddFact(Pred,
A,
B);
2815 if (ReproducerModule && !ReproducerModule->functions().empty()) {
2817 raw_string_ostream StringS(S);
2818 ReproducerModule->print(StringS,
nullptr);
2819 OptimizationRemark Rem(
DEBUG_TYPE,
"Reproducer", &
F);
2820 Rem <<
ore::NV(
"module") << S;
2825 unsigned SignedEntries =
2826 count_if(DFSInStack, [](
const StackEntry &
E) {
return E.IsSigned; });
2827 assert(
Info.getCS(
false).size() - FunctionArgs.size() ==
2828 DFSInStack.
size() - SignedEntries &&
2829 "updates to CS and DFSInStack are out of sync");
2830 assert(
Info.getCS(
true).size() == SignedEntries &&
2831 "updates to CS and DFSInStack are out of sync");
2835 I->eraseFromParent();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static const Function * getParent(const Value *V)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
std::pair< ICmpInst *, unsigned > ConditionTy
static int64_t MaxConstraintValue
static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI, ScalarEvolution *SE, OptimizationRemarkEmitter &ORE, TargetLibraryInfo &TLI)
static bool canStrengthenFlags(Instruction *I)
Returns true if I is a candidate whose poison-generating flags may be strengthened using the constrai...
static bool doesHoldInRange(ConstraintInfo &Info, Value *Op, const ConstantRange &R, bool Signed)
Returns true if Info implies that Op is in R, interpreting R as a signed range if Signed is set and a...
static RowTy getDecompositionLinkRow(Value *V, const ConstraintTy &C, ConstraintInfo &Info, const DataLayout &DL)
If V is a variable in the system and constraint C does not contain V, we managed to decompose V at th...
static int64_t MinSignedConstraintValue
static bool tryToSimplifyOverflowMath(WithOverflowInst *II, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
static auto m_IncrementOf(const PhiMatchTy &PhiM, const APInt *&Off)
Matches an increment of PhiM by a constant offset, captured in Off.
static Instruction * getContextInstForUse(Use &U)
static bool isKnownNoWrap(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1, unsigned NoWrapFlags, ConstraintInfo &Info, bool Signed)
Returns true if Opcode applied to Op0 and Op1 with NoWrapFlags is known to not wrap in signed or unsi...
static bool mayLookThrough(Value *V)
Returns true if V is an operation decomposeImpl can look through.
static bool canUseSExt(ConstantInt *CI)
static void removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info, Module *ReproducerModule, SmallVectorImpl< ReproducerEntry > &ReproducerCondStack, SmallVectorImpl< StackEntry > &DFSInStack)
static std::optional< bool > checkCondition(CmpInst::Predicate Pred, Value *A, Value *B, Instruction *CheckInst, ConstraintInfo &Info)
static Decomposition decompose(Value *V, ConstraintInfo &Info, bool IsSigned, const DataLayout &DL)
static bool checkOrAndOpImpliedByOther(FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule, SmallVectorImpl< ReproducerEntry > &ReproducerCondStack, SmallVectorImpl< StackEntry > &DFSInStack, SmallVectorImpl< Instruction * > &ToRemove)
Check if either the first condition of an AND or OR is implied by the (negated in case of OR) second ...
static OffsetResult collectOffsets(GEPOperator &GEP, const DataLayout &DL)
static bool checkAndReplaceMinMax(MinMaxIntrinsic *MinMax, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
static bool tryToStrengthenFlags(Instruction *I, ConstraintInfo &Info)
Try to strengthen I's poison generating flags using Info.
static RowTy getRowForLessEqual(const Decomposition &ADec, const Decomposition &BDec, const DenseMap< Value *, unsigned > &Value2Index, SmallVectorImpl< Value * > &NewVariables)
Build the row for 'ADec <= BDec', using the indices from Value2Index.
static void dumpConstraint(ArrayRef< Entry > C, const DenseMap< Value *, unsigned > &Value2Index)
static bool replaceOverflowUses(WithOverflowInst *II, SmallVectorImpl< Instruction * > &ToRemove)
Replace the uses of II, which is known not to overflow, by the corresponding plain binary operation a...
static bool getConstraintFromMemoryAccess(GetElementPtrInst &GEP, uint64_t AccessSize, CmpPredicate &Pred, Value *&A, Value *&B, const DataLayout &DL, const TargetLibraryInfo &TLI)
static void dumpUnpackedICmp(raw_ostream &OS, ICmpInst::Predicate Pred, Value *LHS, Value *RHS)
static void generateReproducer(Instruction *Cond, bool IsSigned, Module *M, ArrayRef< ReproducerEntry > Stack, ConstraintInfo &Info, DominatorTree &DT)
Helper function to generate a reproducer function for simplifying Cond.
static bool checkAndReplaceUSubSat(SaturatingInst *USub, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
Try to replace USub by a plain subtract, if Info proves it cannot saturate.
static bool hasLimitWitness(const ConstraintInfo &Info, Value *Op, const APInt &Slack, bool Signed, bool Upper)
Returns true if Op <= MaxVal - Slack holds in the system for Signed, by scanning it for a row of the ...
static bool checkAndReplaceCondition(CmpPredicate Pred, Value *A, Value *B, Instruction *CheckInst, ConstraintInfo &Info, unsigned NumIn, unsigned NumOut, Instruction *ContextInst, Module *ReproducerModule, ArrayRef< ReproducerEntry > ReproducerCondStack, DominatorTree &DT, SmallVectorImpl< Instruction * > &ToRemove)
static Instruction * findCommonDominatorOfUses(Instruction &I, DominatorTree &DT)
Returns the closest program point dominating all uses of I.
static Decomposition decomposeImpl(Value *V, ConstraintInfo &Info, bool IsSigned, const DataLayout &DL)
static bool checkAndReplaceCmp(CmpIntrinsic *I, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
static std::pair< Value *, Value * > getStartAndBackedgeValue(const PHINode &PN, const BasicBlock *LoopPred)
Splits the induction phi PN into the start value, coming from the loop predecessor LoopPred,...
static Decomposition decomposeGEP(GEPOperator &GEP, ConstraintInfo &Info, bool IsSigned, const DataLayout &DL)
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
This is the interface for a simple mod/ref and alias analysis over globals.
Module.h This file contains the declarations for the Module class.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
uint64_t IntrinsicInst * II
This file defines the PointerIntPair class.
static StringRef getName(Value *V)
SmallVector< MachineOperand, 4 > 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.
uint64_t getZExtValue() const
Get zero extended value.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
bool sgt(const APInt &RHS) const
Signed greater than comparison.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
static APInt getMinValue(unsigned numBits)
Gets minimum unsigned value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
bool slt(const APInt &RHS) const
Signed less than comparison.
bool isIntN(unsigned N) const
Check if this APInt has an N-bits unsigned integer value.
bool isOne() const
Determine if this is a value of 1.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this basic block belongs to.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Represents analyses that only rely on functions' control flow.
static Type * makeCmpResultType(Type *opnd_type)
Create a result type for fcmp/icmp.
Predicate getStrictPredicate() const
For example, SGE -> SGT, SLE -> SLT, ULE -> ULT, UGE -> UGT.
bool isEquality() const
Determine if this is an equals/not equals predicate.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ ICMP_ULT
unsigned less than
@ ICMP_SGE
signed greater or equal
@ ICMP_ULE
unsigned less or equal
static LLVM_ABI bool isEquality(Predicate pred)
Determine if this is an equals/not equals predicate.
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getNonStrictPredicate() const
For example, SGT -> SGE, SLT -> SLE, ULT -> ULE, UGT -> UGE.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
This class represents a ucmp/scmp intrinsic.
An abstraction over a floating-point predicate, and a pack of an integer predicate with samesign info...
static LLVM_ABI CmpPredicate getInverse(CmpPredicate P)
Get the inverse predicate of a CmpPredicate.
CmpInst::Predicate dropSameSign() const
Drops samesign information.
bool hasSameSign() const
Query samesign information, for optimizations.
This is the shared class of boolean and integer constants.
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
const APInt & getValue() const
Return the constant as an APInt value reference.
static LLVM_ABI ConstantInt * getBool(LLVMContext &Context, bool V)
This class represents a range of values.
static LLVM_ABI ConstantRange makeExactNoWrapRegion(Instruction::BinaryOps BinOp, const APInt &Other, unsigned NoWrapKind)
Produce the range that contains X if and only if "X BinOp Other" does not wrap.
This is an important base class in LLVM.
static LLVM_ABI Constant * getAllOnesValue(Type *Ty)
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &)
bool addRow(ArrayRef< Entry > R, size_t NumVars)
static RowTy negate(RowTy R)
unsigned size() const
Returns the number of rows in the constraint system.
LLVM_ABI std::pair< ConstraintSystem, RowTy > getSubSystem(ArrayRef< Entry > R) const
Build and return a sub-system of constraints connected (transitively) to query R, with variables comp...
static RowTy toStrictLessThan(RowTy R)
Converts the given row to form a strict less than inequality.
static LLVM_ABI void normalizeByGCD(MutableArrayRef< Entry > R)
Divide the variable coefficients of R by their greatest common divisor G and round the constant down ...
LLVM_ABI bool isConditionImpliedInSubSystem(ArrayRef< Entry > R) const
SmallVector< Entry, 8 > RowTy
A single constraint of the form 'c >= v1 * c1 + ... + vn * cn'.
static RowTy negateOrEqual(RowTy R)
Multiplies each coefficient in the given row by -1.
LLVM_ABI void dump() const
Print the constraints in the system.
A parsed version of the target data layout string in and methods for querying it.
static bool shouldExecute(CounterInfo &Counter)
iterator find(const_arg_type_t< KeyT > Val)
unsigned getDFSNumIn() const
getDFSNumIn/getDFSNumOut - These return the DFS visitation order for nodes in the dominator tree.
unsigned getDFSNumOut() const
Analysis pass which computes a DominatorTree.
void updateDFSNumbers() const
updateDFSNumbers - Assign In and Out numbers to the nodes while walking dominator tree in dfs order.
DomTreeNodeBase< NodeT > * getNode(const NodeT *BB) const
getNode - return the (Post)DominatorTree node for the specified basic block.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI Instruction * findNearestCommonDominator(Instruction *I1, Instruction *I2) const
Find the nearest instruction I that dominates both I1 and I2, in the sense that a result produced bef...
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
static GEPNoWrapFlags none()
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
@ ExternalLinkage
Externally visible function.
static bool isLT(Predicate P)
Return true if the predicate is SLT or ULT.
Predicate getFlippedSignednessPredicate() const
For example, SLT->ULT, ULT->SLT, SLE->ULE, ULE->SLE, EQ->EQ.
Predicate getSignedPredicate() const
For example, EQ->EQ, SLE->SLE, UGT->SGT, etc.
bool isRelational() const
Return true if the predicate is relational (not EQ or NE).
Predicate getUnsignedPredicate() const
For example, EQ->EQ, SLE->ULE, UGT->UGT, etc.
static bool isLE(Predicate P)
Return true if the predicate is SLE or ULE.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI void dropUnknownNonDebugMetadata(ArrayRef< unsigned > KnownIDs={})
Drop all unknown metadata except for debug locations.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
This is an important class for using LLVM in a threaded context.
Analysis pass that exposes the LoopInfo for a function.
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
This class represents min/max intrinsics.
A Module instance is used to store all the information related to an LLVM module.
Utility class for integer operators which may exhibit overflow - Add, Sub, Mul, and Shl.
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
int getBasicBlockIndex(const BasicBlock *BB) const
Return the first index of the specified basic block in the value list for this PHI.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
PointerIntPair - This class implements a pair of a pointer and small integer.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Represents a saturating add/sub intrinsic.
Analysis pass that exposes the ScalarEvolution for a function.
The main scalar evolution driver.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEVFlags Flags=SCEV::FlagNone, unsigned Depth=0)
Return LHS-RHS.
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI bool isSCEVable(Type *Ty) const
Test if values of the given type are analyzable within the SCEV framework.
MonotonicPredicateType
A predicate is said to be monotonically increasing if may go from being false to being true as the lo...
@ MonotonicallyDecreasing
@ MonotonicallyIncreasing
LLVM_ABI APInt getConstantMultiple(const SCEV *S, const Instruction *CtxI=nullptr)
Returns the max constant multiple of S.
LLVM_ABI std::optional< MonotonicPredicateType > getMonotonicPredicateType(const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred)
If, for all loop invariant X, the predicate "LHS `Pred` X" is monotonically increasing or decreasing,...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void truncate(size_type N)
Like resize, but requires that N is less than size().
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
bool isIntegerTy() const
True if this is an instance of IntegerType.
A Use represents the edge between a Value definition and its users.
Value * getOperand(unsigned i) const
iterator find(const KeyT &Val)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI const Value * stripPointerCastsSameRepresentation() const
Strip off pointer casts, all-zero GEPs and address space casts but ensures the representation of the ...
LLVM_ABI bool replaceUsesWithIf(Value *New, llvm::function_ref< bool(Use &U)> ShouldReplace)
Go through the uses list for this definition and make each use point to "V" if the callback ShouldRep...
Represents an op.with.overflow intrinsic.
constexpr ScalarTy getFixedValue() const
constexpr bool isFixed() const
Returns true if the quantity is not scaled by vscale.
const ParentTy * getParent() const
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BasicBlock
Various leaf nodes.
AllOnesConstantMatch m_AllOnes()
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
match_combine_or< Ty... > m_CombineOr(const Ty &...Ps)
Combine pattern matchers matching any of Ps patterns.
match_bind< PHINode > m_Phi(PHINode *&PN)
Match a PHI node, capturing it if we match.
auto m_LogicalOp()
Matches either L && R or L || R where L and R are arbitrary values.
CommutativeBinaryIntrinsic_match< IntrID, T0, T1 > m_c_Intrinsic(const T0 &Op0, const T1 &Op1)
ap_match< APInt > m_APInt(const APInt *&Res)
Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
DisjointOr_match< LHS, RHS > m_DisjointOr(const LHS &L, const RHS &R)
BinOpPred_match< LHS, RHS, is_right_shift_op > m_Shr(const LHS &L, const RHS &R)
Matches logical shift operations.
CmpClass_match< LHS, RHS, ICmpInst, true > m_c_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
Matches an ICmp with a predicate over LHS and RHS in either order.
ExtractValue_match< Ind, Val_t > m_ExtractValue(const Val_t &V)
Match a single index ExtractValue instruction.
ICmpLike_match< LHS, RHS > m_ICmpLike(CmpPredicate &Pred, const LHS &L, const RHS &R)
auto m_Value()
Match an arbitrary value and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
CastInst_match< OpTy, ZExtInst > m_ZExt(const OpTy &Op)
Matches ZExt.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
BinaryOp_match< LHS, RHS, Instruction::Add, true > m_c_Add(const LHS &L, const RHS &R)
Matches a Add with LHS and RHS in either order.
match_combine_or< BinaryOp_match< LHS, RHS, Instruction::Add >, DisjointOr_match< LHS, RHS > > m_AddLike(const LHS &L, const RHS &R)
Match either "add" or "or disjoint".
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
Exact_match< T > m_Exact(const T &SubPattern)
LogicalOp_match< LHS, RHS, Instruction::And, true > m_c_LogicalAnd(const LHS &L, const RHS &R)
Matches L && R with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)
Matches SExt.
LogicalOp_match< LHS, RHS, Instruction::Or, true > m_c_LogicalOr(const LHS &L, const RHS &R)
Matches L || R with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Sub > m_Sub(const LHS &L, const RHS &R)
auto m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
bind_cst_ty m_scev_APInt(const APInt *&C)
Match an SCEV constant and bind it to an APInt.
specificloop_ty m_SpecificLoop(const Loop *L)
bool match(const SCEV *S, const Pattern &P)
SCEVAffineAddRec_match< Op0_t, Op1_t, match_isa< const Loop > > m_scev_AffineAddRec(const Op0_t &Op0, const Op1_t &Op1)
@ Switch
The "resume-switch" lowering, where there are separate resume and destroy functions that are shared b...
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
void stable_sort(R &&Range)
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI bool verifyFunction(const Function &F, raw_ostream *OS=nullptr)
Check a function for errors, useful for use when debugging a pass.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
constexpr std::enable_if_t< std::is_signed_v< T >, std::pair< T, bool > > AddOverflow(T X, T Y)
Add two signed integers, computing the two's complement truncated result, returning a pair {result,...
const ScalarOptions & getScalarOptions(const LLVMContext &C)
LLVM_ABI std::optional< TypeSize > getBaseObjectSize(const Value *Ptr, const DataLayout &DL, const TargetLibraryInfo *TLI, ObjectSizeOpts Opts={})
Like getObjectSize(), but only returns the size of base objects (like allocas, global variables and a...
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
DomTreeNodeBase< BasicBlock > DomTreeNode
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
constexpr std::enable_if_t< std::is_signed_v< T >, std::pair< T, bool > > SubOverflow(T X, T Y)
Subtract two signed integers, computing the two's complement truncated result, returning a pair {resu...
constexpr unsigned MaxAnalysisRecursionDepth
LLVM_ABI bool isKnownPositive(const WithCache< const Value * > &V, const SimplifyQuery &SQ, unsigned Depth=0)
Returns true if the given value is known be positive (i.e.
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 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.