46using namespace PatternMatch;
48#define DEBUG_TYPE "constraint-elimination"
50STATISTIC(NumCondsRemoved,
"Number of instructions removed");
52 "Controls which conditions are eliminated");
56 cl::desc(
"Maximum number of rows to keep in constraint system"));
60 cl::desc(
"Dump IR to reproduce successful transformations."));
80 Instruction *UserI = cast<Instruction>(U.getUser());
81 if (
auto *Phi = dyn_cast<PHINode>(UserI))
82 UserI = Phi->getIncomingBlock(U)->getTerminator();
94 : Pred(Pred), Op0(Op0), Op1(Op1) {}
123 : Inst(Inst), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
127 :
U(
U), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
128 Ty(EntryTy::UseCheck) {}
131 :
Cond(Pred, Op0, Op1), NumIn(DTN->getDFSNumIn()),
132 NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {}
136 return FactOrCheck(DTN, Pred, Op0, Op1);
140 return FactOrCheck(EntryTy::InstFact, DTN, Inst);
145 return FactOrCheck(DTN, Pred, Op0, Op1);
149 return FactOrCheck(DTN, U);
153 return FactOrCheck(EntryTy::InstCheck, DTN, CI);
156 bool isCheck()
const {
157 return Ty == EntryTy::InstCheck || Ty == EntryTy::UseCheck;
161 if (Ty == EntryTy::UseCheck)
168 if (Ty == EntryTy::InstCheck)
171 return dyn_cast<Instruction>(*U);
174 bool isConditionFact()
const {
return Ty == EntryTy::ConditionFact; }
199 bool IsSigned =
false;
204 StackEntry(
unsigned NumIn,
unsigned NumOut,
bool IsSigned,
206 : NumIn(NumIn), NumOut(NumOut), IsSigned(IsSigned),
207 ValuesToRelease(ValuesToRelease) {}
216 bool IsSigned =
false;
218 ConstraintTy() =
default;
222 : Coefficients(Coefficients), IsSigned(IsSigned), IsEq(IsEq), IsNe(IsNe) {
225 unsigned size()
const {
return Coefficients.
size(); }
227 unsigned empty()
const {
return Coefficients.
empty(); }
231 bool isValid(
const ConstraintInfo &Info)
const;
233 bool isEq()
const {
return IsEq; }
235 bool isNe()
const {
return IsNe; }
255class ConstraintInfo {
264 : UnsignedCS(FunctionArgs), SignedCS(FunctionArgs),
DL(
DL) {}
274 return Signed ? SignedCS : UnsignedCS;
277 return Signed ? SignedCS : UnsignedCS;
281 void popLastNVariables(
bool Signed,
unsigned N) {
282 getCS(
Signed).popLastNVariables(
N);
310 unsigned NumIn,
unsigned NumOut,
319 bool IsKnownNonNegative;
321 DecompEntry(int64_t Coefficient,
Value *Variable,
322 bool IsKnownNonNegative =
false)
323 : Coefficient(Coefficient), Variable(Variable),
324 IsKnownNonNegative(IsKnownNonNegative) {}
328struct Decomposition {
333 Decomposition(
Value *V,
bool IsKnownNonNegative =
false) {
339 void add(int64_t OtherOffset) {
343 void add(
const Decomposition &
Other) {
348 void mul(int64_t Factor) {
350 for (
auto &Var : Vars)
371 if (
DL.getIndexTypeSizeInBits(
GEP.getPointerOperand()->getType()) > 64)
374 if (!
GEP.isInBounds())
377 assert(!IsSigned &&
"The logic below only supports decomposition for "
378 "unsinged predicates at the moment.");
379 Type *PtrTy =
GEP.getType()->getScalarType();
380 unsigned BitWidth =
DL.getIndexTypeSizeInBits(PtrTy);
383 if (!
GEP.collectOffset(
DL,
BitWidth, VariableOffsets, ConstantOffset))
388 auto *InnerGEP = dyn_cast<GEPOperator>(
GEP.getPointerOperand());
389 if (VariableOffsets.
empty() && InnerGEP && InnerGEP->getNumOperands() == 2) {
390 auto Result =
decompose(InnerGEP, Preconditions, IsSigned,
DL);
394 unsigned Scale =
DL.getTypeAllocSize(InnerGEP->getResultElementType());
395 int64_t ConstantOffsetI = ConstantOffset.
getSExtValue();
396 if (ConstantOffsetI % Scale != 0)
404 -1 * (ConstantOffsetI / Scale)));
410 DecompEntry(1,
GEP.getPointerOperand()));
411 for (
auto [
Index, Scale] : VariableOffsets) {
413 IdxResult.mul(Scale.getSExtValue());
414 Result.add(IdxResult);
432 auto MergeResults = [&Preconditions, IsSigned, &
DL](
Value *
A,
Value *
B,
442 if (
auto *CI = dyn_cast<ConstantInt>(V)) {
444 return CI->getSExtValue();
449 return MergeResults(Op0, Op1, IsSigned);
453 auto Result =
decompose(Op0, Preconditions, IsSigned,
DL);
461 if (
auto *CI = dyn_cast<ConstantInt>(V)) {
464 return int64_t(CI->getZExtValue());
467 if (
auto *
GEP = dyn_cast<GEPOperator>(V))
471 bool IsKnownNonNegative =
false;
473 IsKnownNonNegative =
true;
480 return MergeResults(Op0, Op1, IsSigned);
490 return MergeResults(Op0, Op1, IsSigned);
498 return MergeResults(Op0, CI,
true);
504 return MergeResults(Op0, CI, IsSigned);
509 return {V, IsKnownNonNegative};
510 auto Result =
decompose(Op1, Preconditions, IsSigned,
DL);
517 auto Result =
decompose(Op1, Preconditions, IsSigned,
DL);
525 return {0, {{1, Op0}, {-1, Op1}}};
527 return {V, IsKnownNonNegative};
533 assert(NewVariables.
empty() &&
"NewVariables must be empty when passed in");
574 auto &Value2Index = getValue2Index(IsSigned);
576 Preconditions, IsSigned,
DL);
578 Preconditions, IsSigned,
DL);
579 int64_t Offset1 = ADec.Offset;
580 int64_t Offset2 = BDec.Offset;
583 auto &VariablesA = ADec.Vars;
584 auto &VariablesB = BDec.Vars;
589 auto GetOrAddIndex = [&Value2Index, &NewVariables,
590 &NewIndexMap](
Value *
V) ->
unsigned {
591 auto V2I = Value2Index.
find(V);
592 if (V2I != Value2Index.end())
595 NewIndexMap.
insert({V, Value2Index.size() + NewVariables.size() + 1});
597 NewVariables.push_back(V);
598 return Insert.first->second;
602 for (
const auto &KV : concat<DecompEntry>(VariablesA, VariablesB))
603 GetOrAddIndex(KV.Variable);
609 IsSigned, IsEq, IsNe);
613 auto &
R = Res.Coefficients;
614 for (
const auto &KV : VariablesA) {
615 R[GetOrAddIndex(KV.Variable)] += KV.Coefficient;
617 KnownNonNegativeVariables.
insert({KV.Variable, KV.IsKnownNonNegative});
618 I.first->second &= KV.IsKnownNonNegative;
621 for (
const auto &KV : VariablesB) {
622 if (
SubOverflow(R[GetOrAddIndex(KV.Variable)], KV.Coefficient,
623 R[GetOrAddIndex(KV.Variable)]))
626 KnownNonNegativeVariables.
insert({KV.Variable, KV.IsKnownNonNegative});
627 I.first->second &= KV.IsKnownNonNegative;
634 if (
AddOverflow(OffsetSum, int64_t(-1), OffsetSum))
637 Res.Preconditions = std::move(Preconditions);
641 while (!NewVariables.empty()) {
642 int64_t
Last =
R.back();
646 Value *RemovedV = NewVariables.pop_back_val();
647 NewIndexMap.
erase(RemovedV);
651 for (
auto &KV : KnownNonNegativeVariables) {
653 (!Value2Index.contains(KV.first) && !NewIndexMap.
contains(KV.first)))
656 C[GetOrAddIndex(KV.first)] = -1;
657 Res.ExtraInfo.push_back(
C);
674 ConstraintTy
R = getConstraint(Pred, Op0, Op1, NewVariables);
675 if (!NewVariables.
empty())
680bool ConstraintTy::isValid(
const ConstraintInfo &Info)
const {
681 return Coefficients.
size() > 0 &&
682 all_of(Preconditions, [&Info](
const ConditionTy &
C) {
683 return Info.doesHold(
C.Pred,
C.Op0,
C.Op1);
693 bool IsNegatedOrEqualImplied =
699 if (IsConditionImplied && IsNegatedOrEqualImplied)
706 bool IsStrictLessThanImplied =
713 if (IsNegatedImplied || IsStrictLessThanImplied)
719 if (IsConditionImplied)
724 if (IsNegatedImplied)
733 auto R = getConstraintForSolving(Pred,
A,
B);
734 return R.isValid(*
this) &&
735 getCS(
R.IsSigned).isConditionImplied(
R.Coefficients);
738void ConstraintInfo::transferToOtherSystem(
743 if (!
A->getType()->isIntegerTy())
804 bool GuaranteedToExecute =
true;
807 if (
auto Cmp = dyn_cast<ICmpInst>(&
I)) {
808 for (
Use &U :
Cmp->uses()) {
810 auto *DTN = DT.
getNode(UserI->getParent());
813 WorkList.
push_back(FactOrCheck::getCheck(DTN, &U));
818 if (
match(&
I, m_Intrinsic<Intrinsic::ssub_with_overflow>())) {
820 FactOrCheck::getCheck(DT.
getNode(&BB), cast<CallInst>(&
I)));
824 if (isa<MinMaxIntrinsic>(&
I)) {
832 if (
match(&
I, m_Intrinsic<Intrinsic::assume>(
834 if (GuaranteedToExecute) {
841 FactOrCheck::getInstFact(DT.
getNode(
I.getParent()), &
I));
847 if (
auto *Switch = dyn_cast<SwitchInst>(BB.getTerminator())) {
848 for (
auto &Case :
Switch->cases()) {
850 Value *
V = Case.getCaseValue();
851 if (!canAddSuccessor(BB, Succ))
859 auto *Br = dyn_cast<BranchInst>(BB.getTerminator());
860 if (!Br || !Br->isConditional())
881 auto QueueValue = [&CondWorkList, &SeenCond](
Value *
V) {
882 if (SeenCond.
insert(V).second)
887 while (!CondWorkList.
empty()) {
889 if (
auto *Cmp = dyn_cast<ICmpInst>(Cur)) {
893 :
Cmp->getPredicate(),
894 Cmp->getOperand(0),
Cmp->getOperand(1)));
912 auto *CmpI = dyn_cast<ICmpInst>(Br->getCondition());
915 if (canAddSuccessor(BB, Br->getSuccessor(0)))
917 DT.
getNode(Br->getSuccessor(0)), CmpI->getPredicate(),
918 CmpI->getOperand(0), CmpI->getOperand(1)));
919 if (canAddSuccessor(BB, Br->getSuccessor(1)))
921 DT.
getNode(Br->getSuccessor(1)),
923 CmpI->getOperand(1)));
931struct ReproducerEntry {
967 auto &Value2Index =
Info.getValue2Index(IsSigned);
969 while (!WorkList.
empty()) {
971 if (!Seen.
insert(V).second)
973 if (Old2New.
find(V) != Old2New.
end())
975 if (isa<Constant>(V))
978 auto *
I = dyn_cast<Instruction>(V);
979 if (Value2Index.contains(V) || !
I ||
980 !isa<CmpInst, BinaryOperator, GEPOperator, CastInst>(V)) {
990 for (
auto &Entry : Stack)
991 if (Entry.Pred != ICmpInst::BAD_ICMP_PREDICATE)
992 CollectArguments({Entry.LHS, Entry.RHS}, ICmpInst::isSigned(Entry.Pred));
993 CollectArguments(
Cond, ICmpInst::isSigned(
Cond->getPredicate()));
1002 Cond->getModule()->getName() +
1003 Cond->getFunction()->getName() +
"repro",
1006 for (
unsigned I = 0;
I < Args.size(); ++
I) {
1008 Old2New[Args[
I]] =
F->getArg(
I);
1014 Builder.SetInsertPoint(Entry->getTerminator());
1023 auto &Value2Index =
Info.getValue2Index(IsSigned);
1024 while (!WorkList.
empty()) {
1026 if (Old2New.
find(V) != Old2New.
end())
1029 auto *
I = dyn_cast<Instruction>(V);
1030 if (!Value2Index.contains(V) &&
I) {
1031 Old2New[V] =
nullptr;
1041 Old2New[
I] = Cloned;
1042 Old2New[
I]->setName(
I->getName());
1054 for (
auto &Entry : Stack) {
1055 if (Entry.Pred == ICmpInst::BAD_ICMP_PREDICATE)
1059 dbgs() <<
" Materializing assumption icmp " << Entry.Pred <<
' ';
1060 Entry.LHS->printAsOperand(
dbgs(),
true);
dbgs() <<
", ";
1061 Entry.RHS->printAsOperand(
dbgs(),
false);
dbgs() <<
"\n");
1064 auto *Cmp =
Builder.CreateICmp(Entry.Pred, Entry.LHS, Entry.RHS);
1065 Builder.CreateAssumption(Cmp);
1071 Entry->getTerminator()->setOperand(0,
Cond);
1078 unsigned NumIn,
unsigned NumOut,
1083 Value *
A = Cmp->getOperand(0);
1084 Value *
B = Cmp->getOperand(1);
1086 auto R =
Info.getConstraintForSolving(Pred,
A,
B);
1087 if (R.empty() || !R.isValid(
Info)){
1089 return std::nullopt;
1092 auto &CSToUse =
Info.getCS(R.IsSigned);
1097 for (
auto &Row : R.ExtraInfo)
1098 CSToUse.addVariableRow(Row);
1100 for (
unsigned I = 0;
I < R.ExtraInfo.size(); ++
I)
1101 CSToUse.popLastConstraint();
1104 if (
auto ImpliedCondition = R.isImpliedBy(CSToUse)) {
1106 return std::nullopt;
1109 if (*ImpliedCondition) {
1110 dbgs() <<
"Condition " << *Cmp;
1112 auto InversePred = Cmp->getInversePredicate();
1114 << *
A <<
", " << *
B;
1116 dbgs() <<
" implied by dominating constraints\n";
1119 return ImpliedCondition;
1122 return std::nullopt;
1126 CmpInst *Cmp, ConstraintInfo &Info,
unsigned NumIn,
unsigned NumOut,
1130 auto ReplaceCmpWithConstant = [&](
CmpInst *Cmp,
bool IsTrue) {
1134 Cmp->replaceUsesWithIf(ConstantC, [&DT, NumIn, NumOut,
1135 ContextInst](
Use &U) {
1137 auto *DTN = DT.
getNode(UserI->getParent());
1138 if (!DTN || DTN->getDFSNumIn() < NumIn || DTN->getDFSNumOut() > NumOut)
1140 if (UserI->getParent() == ContextInst->
getParent() &&
1141 UserI->comesBefore(ContextInst))
1146 auto *II = dyn_cast<IntrinsicInst>(U.getUser());
1147 return !II || II->getIntrinsicID() != Intrinsic::assume;
1150 if (Cmp->use_empty())
1155 if (
auto ImpliedCondition =
1157 return ReplaceCmpWithConstant(Cmp, *ImpliedCondition);
1163 Module *ReproducerModule,
1166 Info.popLastConstraint(
E.IsSigned);
1168 auto &Mapping =
Info.getValue2Index(
E.IsSigned);
1169 for (
Value *V :
E.ValuesToRelease)
1171 Info.popLastNVariables(
E.IsSigned,
E.ValuesToRelease.size());
1173 if (ReproducerModule)
1179 FactOrCheck &CB, ConstraintInfo &Info,
Module *ReproducerModule,
1189 unsigned OldSize = DFSInStack.
size();
1190 Info.addFact(Pred,
A,
B, CB.NumIn, CB.NumOut, DFSInStack);
1191 if (OldSize == DFSInStack.
size())
1194 bool Changed =
false;
1196 if (
auto ImpliedCondition =
1198 CB.NumOut, CB.getContextInst())) {
1204 while (OldSize < DFSInStack.
size()) {
1205 StackEntry
E = DFSInStack.
back();
1213 unsigned NumIn,
unsigned NumOut,
1218 auto R = getConstraint(Pred,
A,
B, NewVariables);
1221 if (!
R.isValid(*
this) ||
R.isNe())
1225 A->printAsOperand(
dbgs(),
false);
dbgs() <<
", ";
1226 B->printAsOperand(
dbgs(),
false);
dbgs() <<
"'\n");
1228 auto &CSToUse = getCS(
R.IsSigned);
1229 if (
R.Coefficients.empty())
1232 Added |= CSToUse.addVariableRowFill(
R.Coefficients);
1238 auto &Value2Index = getValue2Index(
R.IsSigned);
1239 for (
Value *V : NewVariables) {
1240 Value2Index.insert({
V, Value2Index.size() + 1});
1245 dbgs() <<
" constraint: ";
1251 std::move(ValuesToRelease));
1255 for (
auto &Coeff :
R.Coefficients)
1257 CSToUse.addVariableRowFill(
R.Coefficients);
1267 bool Changed =
false;
1269 Value *Sub =
nullptr;
1274 U->replaceAllUsesWith(Sub);
1277 U->replaceAllUsesWith(
Builder.getFalse());
1282 if (U->use_empty()) {
1283 auto *
I = cast<Instruction>(U);
1301 ConstraintInfo &
Info) {
1302 auto R =
Info.getConstraintForSolving(Pred,
A,
B);
1303 if (R.size() < 2 || !R.isValid(
Info))
1306 auto &CSToUse =
Info.getCS(R.IsSigned);
1307 return CSToUse.isConditionImplied(R.Coefficients);
1310 bool Changed =
false;
1327 bool Changed =
false;
1330 for (
Value &Arg :
F.args())
1332 ConstraintInfo
Info(
F.getParent()->getDataLayout(), FunctionArgs);
1334 std::unique_ptr<Module> ReproducerModule(
1353 stable_sort(S.WorkList, [](
const FactOrCheck &
A,
const FactOrCheck &
B) {
1354 auto HasNoConstOp = [](const FactOrCheck &B) {
1355 Value *V0 = B.isConditionFact() ? B.Cond.Op0 : B.Inst->getOperand(0);
1356 Value *V1 = B.isConditionFact() ? B.Cond.Op1 : B.Inst->getOperand(1);
1357 return !isa<ConstantInt>(V0) && !isa<ConstantInt>(V1);
1361 if (
A.NumIn ==
B.NumIn) {
1362 if (A.isConditionFact() && B.isConditionFact()) {
1363 bool NoConstOpA = HasNoConstOp(A);
1364 bool NoConstOpB = HasNoConstOp(B);
1365 return NoConstOpA < NoConstOpB;
1367 if (
A.isConditionFact())
1369 if (
B.isConditionFact())
1371 auto *InstA =
A.getContextInst();
1372 auto *InstB =
B.getContextInst();
1373 return InstA->comesBefore(InstB);
1375 return A.NumIn <
B.NumIn;
1383 for (FactOrCheck &CB : S.WorkList) {
1386 while (!DFSInStack.
empty()) {
1387 auto &
E = DFSInStack.
back();
1390 LLVM_DEBUG(
dbgs() <<
"CB: " << CB.NumIn <<
" " << CB.NumOut <<
"\n");
1392 if (CB.NumOut <=
E.NumOut)
1395 dbgs() <<
"Removing ";
1397 Info.getValue2Index(
E.IsSigned));
1409 Instruction *Inst = CB.getInstructionToSimplify();
1412 LLVM_DEBUG(
dbgs() <<
"condition to simplify: " << *Inst <<
"\n");
1413 if (
auto *II = dyn_cast<WithOverflowInst>(Inst)) {
1415 }
else if (
auto *Cmp = dyn_cast<ICmpInst>(Inst)) {
1417 Cmp, Info, CB.NumIn, CB.NumOut, CB.getContextInst(),
1418 ReproducerModule.get(), ReproducerCondStack, S.DT,
ToRemove);
1419 if (!Simplified &&
match(CB.getContextInst(),
1423 ReproducerCondStack, DFSInStack);
1434 <<
"Skip adding constraint because system has too many rows.\n");
1439 dbgs() <<
"Processing fact to add to the system: " << Pred <<
" ";
1440 A->printAsOperand(
dbgs());
1442 B->printAsOperand(
dbgs(),
false);
1446 Info.addFact(Pred,
A,
B, CB.NumIn, CB.NumOut, DFSInStack);
1447 if (ReproducerModule && DFSInStack.
size() > ReproducerCondStack.
size())
1450 Info.transferToOtherSystem(Pred,
A,
B, CB.NumIn, CB.NumOut, DFSInStack);
1451 if (ReproducerModule && DFSInStack.
size() > ReproducerCondStack.
size()) {
1454 for (
unsigned I = 0,
1455 E = (DFSInStack.
size() - ReproducerCondStack.
size());
1457 ReproducerCondStack.
emplace_back(ICmpInst::BAD_ICMP_PREDICATE,
1464 if (!CB.isConditionFact()) {
1465 if (
auto *
MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {
1466 Pred = ICmpInst::getNonStrictPredicate(
MinMax->getPredicate());
1473 Value *
A =
nullptr, *
B =
nullptr;
1474 if (CB.isConditionFact()) {
1475 Pred = CB.Cond.Pred;
1479 bool Matched =
match(CB.Inst, m_Intrinsic<Intrinsic::assume>(
1482 assert(Matched &&
"Must have an assume intrinsic with a icmp operand");
1484 AddFact(Pred,
A,
B);
1487 if (ReproducerModule && !ReproducerModule->functions().empty()) {
1490 ReproducerModule->print(StringS,
nullptr);
1493 Rem <<
ore::NV(
"module") << S;
1498 unsigned SignedEntries =
1499 count_if(DFSInStack, [](
const StackEntry &
E) {
return E.IsSigned; });
1500 assert(
Info.getCS(
false).size() == DFSInStack.
size() - SignedEntries &&
1501 "updates to CS and DFSInStack are out of sync");
1502 assert(
Info.getCS(
true).size() == SignedEntries &&
1503 "updates to CS and DFSInStack are out of sync");
1507 I->eraseFromParent();
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
ReachingDefAnalysis InstSet & ToRemove
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Analysis containing CSE Info
std::pair< ICmpInst *, unsigned > ConditionTy
static int64_t MaxConstraintValue
static int64_t MinSignedConstraintValue
static Instruction * getContextInstForUse(Use &U)
static bool checkAndSecondOpImpliedByFirst(FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule, SmallVectorImpl< ReproducerEntry > &ReproducerCondStack, SmallVectorImpl< StackEntry > &DFSInStack)
Check if the first condition for an AND implies the second.
static Decomposition decomposeGEP(GEPOperator &GEP, SmallVectorImpl< ConditionTy > &Preconditions, bool IsSigned, const DataLayout &DL)
static bool canUseSExt(ConstantInt *CI)
static int64_t multiplyWithOverflow(int64_t A, int64_t B)
static void dumpConstraint(ArrayRef< int64_t > C, const DenseMap< Value *, unsigned > &Value2Index)
static void removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info, Module *ReproducerModule, SmallVectorImpl< ReproducerEntry > &ReproducerCondStack, SmallVectorImpl< StackEntry > &DFSInStack)
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 int64_t addWithOverflow(int64_t A, int64_t B)
static cl::opt< bool > DumpReproducers("constraint-elimination-dump-reproducers", cl::init(false), cl::Hidden, cl::desc("Dump IR to reproduce successful transformations."))
static void generateReproducer(CmpInst *Cond, Module *M, ArrayRef< ReproducerEntry > Stack, ConstraintInfo &Info, DominatorTree &DT)
Helper function to generate a reproducer function for simplifying Cond.
static bool eliminateConstraints(Function &F, DominatorTree &DT, OptimizationRemarkEmitter &ORE)
static Decomposition decompose(Value *V, SmallVectorImpl< ConditionTy > &Preconditions, bool IsSigned, const DataLayout &DL)
static bool replaceSubOverflowUses(IntrinsicInst *II, Value *A, Value *B, SmallVectorImpl< Instruction * > &ToRemove)
static std::optional< bool > checkCondition(CmpInst *Cmp, ConstraintInfo &Info, unsigned NumIn, unsigned NumOut, Instruction *ContextInst)
static bool tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info, SmallVectorImpl< Instruction * > &ToRemove)
static bool checkAndReplaceCondition(CmpInst *Cmp, ConstraintInfo &Info, unsigned NumIn, unsigned NumOut, Instruction *ContextInst, Module *ReproducerModule, ArrayRef< ReproducerEntry > ReproducerCondStack, DominatorTree &DT, SmallVectorImpl< Instruction * > &ToRemove)
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
std::optional< std::vector< StOtherPiece > > Other
This is the interface for a simple mod/ref and alias analysis over globals.
static StringRef getName(Value *V)
const SmallVectorImpl< MachineOperand > & Cond
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
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.
bool sgt(const APInt &RHS) const
Signed greater than comparison.
bool isNegative() const
Determine sign of this APInt.
bool slt(const APInt &RHS) const
Signed less than comparison.
int64_t getSExtValue() const
Get sign extended value.
A container for analyses that lazily runs them and caches their results.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Represents analyses that only rely on functions' control flow.
Value * getArgOperand(unsigned i) const
This class represents a function call, abstracting a target machine's calling convention.
This class is the base class for the comparison instructions.
static Type * makeCmpResultType(Type *opnd_type)
Create a result type for fcmp/icmp.
Predicate getSignedPredicate()
For example, ULT->SLT, ULE->SLE, UGT->SGT, UGE->SGE, SLT->Failed assert.
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
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getUnsignedPredicate()
For example, SLT->ULT, SLE->ULE, SGT->UGT, SGE->UGE, ULT->Failed assert.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
static StringRef getPredicateName(Predicate P)
This is the shared class of boolean and integer constants.
static Constant * get(Type *Ty, uint64_t V, bool IsSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
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 ConstantInt * getBool(LLVMContext &Context, bool V)
This is an important base class in LLVM.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &)
DenseMap< Value *, unsigned > & getValue2Index()
static SmallVector< int64_t, 8 > negate(SmallVector< int64_t, 8 > R)
bool isConditionImplied(SmallVector< int64_t, 8 > R) const
static SmallVector< int64_t, 8 > toStrictLessThan(SmallVector< int64_t, 8 > R)
Converts the given vector to form a strict less than inequality.
static SmallVector< int64_t, 8 > negateOrEqual(SmallVector< int64_t, 8 > R)
Multiplies each coefficient in the given vector by -1.
bool addVariableRowFill(ArrayRef< int64_t > R)
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(unsigned CounterName)
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
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.
bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
void insertBefore(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified instruction.
const BasicBlock * getParent() const
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
void dropUnknownNonDebugMetadata(ArrayRef< unsigned > KnownIDs)
Drop all unknown metadata except for debug locations.
A wrapper class for inspecting calls to intrinsic functions.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
This is an important class for using LLVM in a threaded context.
This class implements a map that also provides access to all stored values in a deterministic order.
A Module instance is used to store all the information related to an LLVM module.
static 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.
void preserveSet()
Mark an analysis set as preserved.
void preserve()
Mark an analysis as preserved.
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 push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
iterator find(const KeyT &Val)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
iterator_range< user_iterator > users()
const Value * stripPointerCastsSameRepresentation() const
Strip off pointer casts, all-zero GEPs and address space casts but ensures the representation of the ...
self_iterator getIterator()
A raw_ostream that writes to an std::string.
@ C
The default llvm calling convention, compatible with C.
BinaryOp_match< LHS, RHS, Instruction::Add > m_Add(const LHS &L, const RHS &R)
OverflowingBinaryOp_match< LHS, RHS, Instruction::Add, OverflowingBinaryOperator::NoUnsignedWrap > m_NUWAdd(const LHS &L, const RHS &R)
CastClass_match< OpTy, Instruction::ZExt > m_ZExt(const OpTy &Op)
Matches ZExt.
bool match(Val *V, const Pattern &P)
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
class_match< ConstantInt > m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
CmpClass_match< LHS, RHS, ICmpInst, ICmpInst::Predicate > m_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R)
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
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)
OverflowingBinaryOp_match< LHS, RHS, Instruction::Sub, OverflowingBinaryOperator::NoUnsignedWrap > m_NUWSub(const LHS &L, const RHS &R)
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
OverflowingBinaryOp_match< LHS, RHS, Instruction::Add, OverflowingBinaryOperator::NoSignedWrap > m_NSWAdd(const LHS &L, const RHS &R)
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
BinaryOp_match< LHS, RHS, Instruction::Or > m_Or(const LHS &L, const RHS &R)
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
OverflowingBinaryOp_match< LHS, RHS, Instruction::Mul, OverflowingBinaryOperator::NoSignedWrap > m_NSWMul(const LHS &L, const RHS &R)
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
This is an optimization pass for GlobalISel generic memory operations.
std::enable_if_t< std::is_signed_v< T >, T > MulOverflow(T X, T Y, T &Result)
Multiply two signed integers, computing the two's complement truncated result, returning true if an o...
void stable_sort(R &&Range)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
detail::scope_exit< std::decay_t< Callable > > make_scope_exit(Callable &&F)
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 a range to a container.
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 unsigned MaxAnalysisRecursionDepth
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool haveNoCommonBitsSet(const Value *LHS, const Value *RHS, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true)
Return true if LHS and RHS have no common bits set.
@ And
Bitwise or logical AND of integers.
void remapInstructionsInBlocks(ArrayRef< BasicBlock * > Blocks, ValueToValueMapTy &VMap)
Remaps instructions in Blocks using the mapping in VMap.
constexpr unsigned BitWidth
bool isGuaranteedToTransferExecutionToSuccessor(const Instruction *I)
Return true if this function can prove that the instruction I will always transfer execution to one o...
bool isKnownNonNegative(const Value *V, const DataLayout &DL, unsigned Depth=0, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true)
Returns true if the give value is known to be non-negative.
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...
std::enable_if_t< std::is_signed_v< T >, T > AddOverflow(T X, T Y, T &Result)
Add two signed integers, computing the two's complement truncated result, returning true if overflow ...
std::enable_if_t< std::is_signed_v< T >, T > SubOverflow(T X, T Y, T &Result)
Subtract two signed integers, computing the two's complement truncated result, returning true if an o...
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.