64#define DEBUG_TYPE "early-cse"
66STATISTIC(NumSimplify,
"Number of instructions simplified or DCE'd");
68STATISTIC(NumCSECVP,
"Number of compare instructions CVP'd");
69STATISTIC(NumCSELoad,
"Number of load instructions CSE'd");
70STATISTIC(NumCSECall,
"Number of call instructions CSE'd");
71STATISTIC(NumCSEGEP,
"Number of GEP instructions CSE'd");
72STATISTIC(NumDSE,
"Number of trivial dead stores removed");
75 "Controls which instructions are removed");
88 assert(canHandle(
I) &&
"Inst can't be handled!");
91 static bool canHandle(Instruction *Inst) {
96 if (
Function *
F = CI->getCalledFunction()) {
97 switch (
F->getIntrinsicID()) {
98 case Intrinsic::experimental_constrained_fadd:
99 case Intrinsic::experimental_constrained_fsub:
100 case Intrinsic::experimental_constrained_fmul:
101 case Intrinsic::experimental_constrained_fdiv:
102 case Intrinsic::experimental_constrained_frem:
103 case Intrinsic::experimental_constrained_fptosi:
104 case Intrinsic::experimental_constrained_sitofp:
105 case Intrinsic::experimental_constrained_fptoui:
106 case Intrinsic::experimental_constrained_uitofp:
107 case Intrinsic::experimental_constrained_fcmp:
108 case Intrinsic::experimental_constrained_fcmps: {
110 if (CFP->getExceptionBehavior() &&
115 if (CFP->getRoundingMode() &&
116 CFP->getRoundingMode() == RoundingMode::Dynamic)
122 return CI->doesNotAccessMemory() &&
130 !CI->getFunction()->isPresplitCoroutine();
145 static bool isEqual(SimpleValue LHS, SimpleValue RHS);
213 if (BinOp->isCommutative() && BinOp->getOperand(0) > BinOp->getOperand(1))
228 if (std::tie(
LHS, Pred) > std::tie(
RHS, SwappedPred)) {
270 return hash_combine(CI->getOpcode(), CI->getType(), CI->getOperand(0));
273 return hash_combine(FI->getOpcode(), FI->getOperand(0));
276 return hash_combine(EVI->getOpcode(), EVI->getOperand(0),
280 return hash_combine(IVI->getOpcode(), IVI->getOperand(0),
286 "Invalid/unknown instruction");
290 if (
II &&
II->isCommutative() &&
II->arg_size() >= 2) {
303 return hash_combine(GCR->getOpcode(), GCR->getOperand(0),
304 GCR->getBasePtr(), GCR->getDerivedPtr());
322 if (ScalarOptions::Global.earlycse_debug_hash)
331 if (LHSI->
getOpcode() != RHSI->getOpcode())
338 CI && CI->isConvergent() && LHSI->
getParent() != RHSI->getParent())
346 if (!LHSBinOp->isCommutative())
350 "same opcode, but different instruction type?");
354 return LHSBinOp->getOperand(0) == RHSBinOp->
getOperand(1) &&
355 LHSBinOp->getOperand(1) == RHSBinOp->
getOperand(0);
359 "same opcode, but different instruction type?");
362 return LHSCmp->getOperand(0) == RHSCmp->
getOperand(1) &&
363 LHSCmp->getOperand(1) == RHSCmp->
getOperand(0) &&
364 LHSCmp->getSwappedPredicate() == RHSCmp->
getPredicate();
369 if (LII && RII && LII->getIntrinsicID() == RII->getIntrinsicID() &&
370 LII->isCommutative() && LII->arg_size() >= 2) {
371 return LII->getArgOperand(0) == RII->getArgOperand(1) &&
372 LII->getArgOperand(1) == RII->getArgOperand(0) &&
373 std::equal(LII->arg_begin() + 2, LII->arg_end(),
374 RII->arg_begin() + 2, RII->arg_end()) &&
375 LII->hasSameSpecialState(RII,
false,
382 return GCR1->getOperand(0) == GCR2->getOperand(0) &&
383 GCR1->getBasePtr() == GCR2->getBasePtr() &&
384 GCR1->getDerivedPtr() == GCR2->getDerivedPtr();
390 Value *CondL, *CondR, *LHSA, *RHSA, *LHSB, *RHSB;
397 return ((LHSA == RHSA && LHSB == RHSB) ||
398 (LHSA == RHSB && LHSB == RHSA));
401 if (CondL == CondR && LHSA == RHSA && LHSB == RHSB)
423 if (LHSA == RHSB && LHSB == RHSA) {
455 CallValue(Instruction *
I) : Inst(
I) {
456 assert(canHandle(
I) &&
"Inst can't be handled!");
459 static bool canHandle(Instruction *Inst) {
479 static bool isEqual(CallValue LHS, CallValue RHS);
510 std::optional<int64_t> ConstantOffset;
512 GEPValue(Instruction *
I) : Inst(
I) {
513 assert(canHandle(
I) &&
"Inst can't be handled!");
516 GEPValue(Instruction *
I, std::optional<int64_t> ConstantOffset)
517 : Inst(
I), ConstantOffset(ConstantOffset) {
518 assert(canHandle(
I) &&
"Inst can't be handled!");
521 static bool canHandle(Instruction *Inst) {
530 static bool isEqual(
const GEPValue &LHS,
const GEPValue &RHS);
535 if (Val.ConstantOffset.has_value())
537 Val.ConstantOffset.value());
545 if (LGEP->getPointerOperand() != RGEP->getPointerOperand())
547 if (
LHS.ConstantOffset.has_value() &&
RHS.ConstantOffset.has_value())
548 return LHS.ConstantOffset.value() ==
RHS.ConstantOffset.value();
549 return LGEP->isIdenticalToWhenDefined(RGEP);
567 const TargetLibraryInfo &TLI;
568 const TargetTransformInfo &TTI;
571 const SimplifyQuery SQ;
573 std::unique_ptr<MemorySSAUpdater> MSSAUpdater;
577 ScopedHashTableVal<SimpleValue, Value *>>;
579 ScopedHashTable<SimpleValue, Value *, DenseMapInfo<SimpleValue>,
588 ScopedHTType AvailableValues;
606 unsigned Generation = 0;
608 bool IsAtomic =
false;
611 LoadValue() =
default;
612 LoadValue(Instruction *Inst,
unsigned Generation,
unsigned MatchingId,
613 bool IsAtomic,
bool IsLoad)
614 : DefInst(Inst), Generation(Generation), MatchingId(MatchingId),
615 IsAtomic(IsAtomic), IsLoad(IsLoad) {}
618 using LoadMapAllocator =
620 ScopedHashTableVal<Value *, LoadValue>>;
622 ScopedHashTable<Value *, LoadValue, DenseMapInfo<Value *>,
625 LoadHTType AvailableLoads;
630 using InvariantMapAllocator =
632 ScopedHashTableVal<MemoryLocation, unsigned>>;
633 using InvariantHTType =
634 ScopedHashTable<MemoryLocation, unsigned, DenseMapInfo<MemoryLocation>,
635 InvariantMapAllocator>;
636 InvariantHTType AvailableInvariants;
643 ScopedHashTable<CallValue, std::pair<Instruction *, unsigned>>;
644 CallHTType AvailableCalls;
646 using GEPMapAllocatorTy =
648 ScopedHashTableVal<GEPValue, Value *>>;
649 using GEPHTType = ScopedHashTable<GEPValue, Value *, DenseMapInfo<GEPValue>,
651 GEPHTType AvailableGEPs;
654 unsigned CurrentGeneration = 0;
657 EarlyCSE(
const DataLayout &
DL,
const TargetLibraryInfo &TLI,
658 const TargetTransformInfo &TTI, DominatorTree &DT,
660 : TLI(TLI), TTI(TTI), DT(DT), AC(AC), SQ(
DL, &TLI, &DT, &AC), MSSA(MSSA),
661 MSSAUpdater(std::make_unique<MemorySSAUpdater>(MSSA)) {}
666 unsigned ClobberCounter = 0;
672 NodeScope(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
673 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
674 GEPHTType &AvailableGEPs)
675 : Scope(AvailableValues), LoadScope(AvailableLoads),
676 InvariantScope(AvailableInvariants), CallScope(AvailableCalls),
677 GEPScope(AvailableGEPs) {}
678 NodeScope(
const NodeScope &) =
delete;
679 NodeScope &operator=(
const NodeScope &) =
delete;
695 StackNode(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
696 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
697 GEPHTType &AvailableGEPs,
unsigned cg,
DomTreeNode *n,
698 DomTreeNode::const_iterator child,
699 DomTreeNode::const_iterator end)
700 : CurrentGeneration(cg), ChildGeneration(cg), Node(n), ChildIter(child),
702 Scopes(AvailableValues, AvailableLoads, AvailableInvariants,
703 AvailableCalls, AvailableGEPs) {}
704 StackNode(
const StackNode &) =
delete;
705 StackNode &operator=(
const StackNode &) =
delete;
708 unsigned currentGeneration()
const {
return CurrentGeneration; }
709 unsigned childGeneration()
const {
return ChildGeneration; }
712 DomTreeNode::const_iterator childIter()
const {
return ChildIter; }
720 DomTreeNode::const_iterator
end()
const {
return EndIter; }
721 bool isProcessed()
const {
return Processed; }
722 void process() { Processed =
true; }
725 unsigned CurrentGeneration;
726 unsigned ChildGeneration;
728 DomTreeNode::const_iterator ChildIter;
729 DomTreeNode::const_iterator EndIter;
731 bool Processed =
false;
736 class ParseMemoryInst {
738 ParseMemoryInst(Instruction *Inst,
const TargetTransformInfo &
TTI)
741 IntrID =
II->getIntrinsicID();
744 if (isHandledNonTargetIntrinsic(IntrID)) {
746 case Intrinsic::masked_load:
747 Info.PtrVal = Inst->getOperand(0);
748 Info.MatchingId = Intrinsic::masked_load;
750 Info.WriteMem =
false;
751 Info.IsVolatile =
false;
753 case Intrinsic::masked_store:
754 Info.PtrVal = Inst->getOperand(1);
761 Info.MatchingId = Intrinsic::masked_load;
762 Info.ReadMem =
false;
763 Info.WriteMem =
true;
764 Info.IsVolatile =
false;
768 Info.PtrVal =
MI->getDest();
770 Info.ReadMem =
false;
771 Info.WriteMem =
true;
772 Info.IsVolatile =
MI->isVolatile();
788 return Info.WriteMem;
794 return Info.Ordering != AtomicOrdering::NotAtomic;
795 return Inst->isAtomic();
798 bool isUnordered()
const {
800 return Info.isUnordered();
803 return LI->isUnordered();
805 return SI->isUnordered();
808 return !Inst->isAtomic();
811 bool isVolatile()
const {
813 return Info.IsVolatile;
816 return LI->isVolatile();
818 return SI->isVolatile();
826 return LI->hasMetadata(LLVMContext::MD_invariant_load);
836 int getMatchingId()
const {
838 return Info.MatchingId;
850 return Inst->getAccessType();
853 bool mayReadFromMemory()
const {
856 return Inst->mayReadFromMemory();
859 bool mayWriteToMemory()
const {
861 return Info.WriteMem;
862 return Inst->mayWriteToMemory();
867 MemIntrinsicInfo Info;
875 case Intrinsic::masked_load:
876 case Intrinsic::masked_store:
881 static bool isHandledNonTargetIntrinsic(
const Value *V) {
883 return isHandledNonTargetIntrinsic(
II->getIntrinsicID());
889 bool handleBranchCondition(Instruction *CondInst,
const CondBrInst *BI,
890 const BasicBlock *BB,
const BasicBlock *Pred);
893 unsigned CurrentGeneration);
895 bool overridingStores(
const ParseMemoryInst &Earlier,
896 const ParseMemoryInst &Later);
898 Value *getOrCreateResult(Instruction *Inst,
Type *ExpectedType,
899 bool CanCreate)
const {
904 switch (
II->getIntrinsicID()) {
905 case Intrinsic::masked_load:
908 case Intrinsic::masked_store:
909 V =
II->getOperand(0);
912 return TTI.getOrCreateResultFromMemIntrinsic(
II, ExpectedType,
919 return V->getType() == ExpectedType ?
V :
nullptr;
924 bool isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt);
926 bool isSameMemGeneration(
unsigned EarlierGeneration,
unsigned LaterGeneration,
927 Instruction *EarlierInst, Instruction *LaterInst);
929 bool isNonTargetIntrinsicMatch(
const IntrinsicInst *Earlier,
930 const IntrinsicInst *Later) {
931 auto IsSubmask = [](
const Value *Mask0,
const Value *Mask1) {
941 if (Vec0->getType() != Vec1->getType())
943 for (
int i = 0, e = Vec0->getNumOperands(); i != e; ++i) {
944 Constant *Elem0 = Vec0->getOperand(i);
945 Constant *Elem1 = Vec1->getOperand(i);
947 if (Int0 && Int0->isZero())
960 auto PtrOp = [](
const IntrinsicInst *
II) {
961 if (
II->getIntrinsicID() == Intrinsic::masked_load)
962 return II->getOperand(0);
963 if (
II->getIntrinsicID() == Intrinsic::masked_store)
964 return II->getOperand(1);
967 auto MaskOp = [](
const IntrinsicInst *
II) {
968 if (
II->getIntrinsicID() == Intrinsic::masked_load)
969 return II->getOperand(1);
970 if (
II->getIntrinsicID() == Intrinsic::masked_store)
971 return II->getOperand(2);
974 auto ThruOp = [](
const IntrinsicInst *
II) {
975 if (
II->getIntrinsicID() == Intrinsic::masked_load)
976 return II->getOperand(2);
980 if (PtrOp(Earlier) != PtrOp(Later))
987 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_load) {
993 if (MaskOp(Earlier) == MaskOp(Later) && ThruOp(Earlier) == ThruOp(Later))
997 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
999 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_load) {
1004 if (!IsSubmask(MaskOp(Later), MaskOp(Earlier)))
1008 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_store) {
1012 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
1014 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_store) {
1019 return IsSubmask(MaskOp(Earlier), MaskOp(Later));
1024 void removeMSSA(Instruction &Inst) {
1028 MSSA->verifyMemorySSA();
1035 MSSAUpdater->removeMemoryAccess(&Inst,
true);
1057bool EarlyCSE::isSameMemGeneration(
unsigned EarlierGeneration,
1058 unsigned LaterGeneration,
1062 if (EarlierGeneration == LaterGeneration)
1086 MemoryAccess *LaterDef;
1087 if (ClobberCounter < ScalarOptions::Global.earlycse_mssa_optimization_cap) {
1091 LaterDef = LaterMA->getDefiningAccess();
1093 return MSSA->
dominates(LaterDef, EarlierMA);
1096bool EarlyCSE::isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt) {
1100 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
1108 MemoryLocation MemLoc = *MemLocOpt;
1109 if (!AvailableInvariants.count(MemLoc))
1114 return AvailableInvariants.lookup(MemLoc) <= GenAt;
1117bool EarlyCSE::handleBranchCondition(Instruction *CondInst,
1118 const CondBrInst *BI,
const BasicBlock *BB,
1119 const BasicBlock *Pred) {
1127 if (Opcode == Instruction::And &&
1130 else if (Opcode == Instruction::Or &&
1138 unsigned PropagateOpcode =
1139 (BI->
getSuccessor(0) == BB) ? Instruction::And : Instruction::Or;
1141 bool MadeChanges =
false;
1142 SmallVector<Instruction *, 4> WorkList;
1143 SmallPtrSet<Instruction *, 4> Visited;
1145 while (!WorkList.
empty()) {
1146 Instruction *Curr = WorkList.pop_back_val();
1148 AvailableValues.insert(Curr, TorF);
1149 LLVM_DEBUG(dbgs() <<
"EarlyCSE CVP: Add conditional value for '"
1150 << Curr->getName() <<
"' as " << *TorF <<
" in "
1151 << BB->getName() <<
"\n");
1152 if (!DebugCounter::shouldExecute(CSECounter)) {
1153 LLVM_DEBUG(dbgs() <<
"Skipping due to debug counter\n");
1156 if (unsigned Count = replaceDominatedUsesWith(Curr, TorF, DT,
1157 BasicBlockEdge(Pred, BB))) {
1164 if (MatchBinOp(Curr, PropagateOpcode,
LHS,
RHS))
1167 if (SimpleValue::canHandle(OPI) && Visited.
insert(OPI).second)
1174Value *EarlyCSE::getMatchingValue(LoadValue &InVal, ParseMemoryInst &MemInst,
1175 unsigned CurrentGeneration) {
1176 if (InVal.DefInst ==
nullptr)
1179 if (!MemInst.isLoad() || MemInst.isVolatile() || !MemInst.isUnordered() ||
1180 MemInst.getMatchingId() != -1)
1182 if (MSI->isVolatile())
1185 if (!Val || !Val->isZero())
1187 auto Len = MSI->getLengthInBytes();
1190 Type *InstType = MemInst.getValueType();
1196 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1197 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1202 if (InVal.MatchingId != MemInst.getMatchingId())
1205 if (MemInst.isVolatile() || !MemInst.isUnordered())
1208 if (MemInst.isLoad() && !InVal.IsAtomic && MemInst.isAtomic())
1214 bool MemInstMatching = !MemInst.isLoad();
1215 Instruction *Matching = MemInstMatching ? MemInst.get() : InVal.DefInst;
1222 ? getOrCreateResult(Matching,
Other->getType(),
false)
1224 if (MemInst.isStore() && InVal.DefInst != Result)
1228 bool MatchingNTI = isHandledNonTargetIntrinsic(Matching);
1229 bool OtherNTI = isHandledNonTargetIntrinsic(
Other);
1230 if (OtherNTI != MatchingNTI)
1232 if (OtherNTI && MatchingNTI) {
1238 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1239 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1244 Result = getOrCreateResult(Matching,
Other->getType(),
true);
1258 I->andIRFlags(&From);
1272 assert(
Success &&
"Failed to intersect attributes in callsites that "
1273 "passed identical check");
1279bool EarlyCSE::overridingStores(
const ParseMemoryInst &Earlier,
1280 const ParseMemoryInst &Later) {
1283 assert(Earlier.isUnordered() && !Earlier.isVolatile() &&
1284 "Violated invariant");
1285 if (Earlier.getPointerOperand() != Later.getPointerOperand())
1287 if (!Earlier.getValueType() || !Later.getValueType() ||
1288 Earlier.getValueType() != Later.getValueType())
1290 if (Earlier.getMatchingId() != Later.getMatchingId())
1297 if (!Earlier.isUnordered() || !Later.isUnordered())
1301 bool ENTI = isHandledNonTargetIntrinsic(Earlier.get());
1302 bool LNTI = isHandledNonTargetIntrinsic(Later.get());
1310 return ENTI == LNTI;
1324 ++CurrentGeneration;
1335 if (CondInst && SimpleValue::canHandle(CondInst))
1336 Changed |= handleBranchCondition(CondInst, BI, BB, Pred);
1372 if (CondI && SimpleValue::canHandle(CondI)) {
1377 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping assumption: " << Inst <<
'\n');
1384 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping noalias intrinsic: " << Inst
1391 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping sideeffect: " << Inst <<
'\n');
1397 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping pseudoprobe: " << Inst <<
'\n');
1418 MemoryLocation MemLoc =
1421 if (!AvailableInvariants.count(MemLoc))
1422 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1429 if (SimpleValue::canHandle(CondI)) {
1431 if (
auto *KnownCond = AvailableValues.lookup(CondI)) {
1436 <<
"EarlyCSE removing guard: " << Inst <<
'\n');
1455 LastStore =
nullptr;
1462 LLVM_DEBUG(
dbgs() <<
"EarlyCSE Simplify: " << Inst <<
" to: " << *V
1467 bool Killed =
false;
1489 LastStore =
nullptr;
1492 if (SimpleValue::canHandle(&Inst)) {
1495 "Unexpected ebStrict from SimpleValue::canHandle()");
1496 assert((!CI->getRoundingMode() ||
1497 CI->getRoundingMode() != RoundingMode::Dynamic) &&
1498 "Unexpected dynamic rounding from SimpleValue::canHandle()");
1501 if (
Value *V = AvailableValues.lookup(&Inst)) {
1519 AvailableValues.insert(&Inst, &Inst);
1523 ParseMemoryInst MemInst(&Inst,
TTI);
1525 if (MemInst.isValid() && MemInst.isLoad()) {
1528 if (MemInst.isVolatile() || !MemInst.isUnordered()) {
1529 LastStore =
nullptr;
1530 ++CurrentGeneration;
1533 if (MemInst.isInvariantLoad()) {
1540 if (!AvailableInvariants.count(MemLoc))
1541 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1551 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1554 <<
" to: " << *InVal.DefInst <<
'\n');
1573 AvailableLoads.insert(MemInst.getPointerOperand(),
1574 LoadValue(&Inst, CurrentGeneration,
1575 MemInst.getMatchingId(),
1578 LastStore =
nullptr;
1588 !(MemInst.isValid() && !MemInst.mayReadFromMemory()))
1589 LastStore =
nullptr;
1595 if (CallValue::canHandle(&Inst) &&
1596 (!MemInst.isValid() || !MemInst.isStore()) && !
isa<MemSetInst>(&Inst)) {
1599 std::pair<Instruction *, unsigned> InVal = AvailableCalls.lookup(&Inst);
1600 if (InVal.first !=
nullptr &&
1601 isSameMemGeneration(InVal.second, CurrentGeneration, InVal.first,
1605 <<
" to: " << *InVal.first <<
'\n');
1624 ++CurrentGeneration;
1627 AvailableCalls.insert(&Inst, std::make_pair(&Inst, CurrentGeneration));
1632 if (GEPValue::canHandle(&Inst)) {
1635 GEPValue GEPVal(
GEP,
GEP->accumulateConstantOffset(SQ.
DL,
Offset)
1638 if (
Value *V = AvailableGEPs.lookup(GEPVal)) {
1639 LLVM_DEBUG(
dbgs() <<
"EarlyCSE CSE GEP: " << Inst <<
" to: " << *V
1652 AvailableGEPs.insert(GEPVal, &Inst);
1662 if (FI->getOrdering() == AtomicOrdering::Release) {
1672 if (MemInst.isValid() && MemInst.isStore()) {
1673 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1674 if (InVal.DefInst &&
1677 LLVM_DEBUG(
dbgs() <<
"EarlyCSE DSE (writeback): " << Inst <<
'\n');
1697 ++CurrentGeneration;
1699 if (MemInst.isValid() && MemInst.isStore()) {
1703 if (overridingStores(ParseMemoryInst(LastStore,
TTI), MemInst)) {
1705 <<
" due to: " << Inst <<
'\n');
1710 removeMSSA(*LastStore);
1714 LastStore =
nullptr;
1725 AvailableLoads.insert(MemInst.getPointerOperand(),
1726 LoadValue(&Inst, CurrentGeneration,
1727 MemInst.getMatchingId(),
1738 if (MemInst.isUnordered() && !MemInst.isVolatile())
1741 LastStore =
nullptr;
1749bool EarlyCSE::run() {
1755 std::deque<StackNode *> nodesToProcess;
1760 nodesToProcess.push_back(
new StackNode(
1761 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1762 AvailableGEPs, CurrentGeneration, DT.
getRootNode(),
1765 assert(!CurrentGeneration &&
"Create a new EarlyCSE instance to rerun it.");
1768 while (!nodesToProcess.empty()) {
1771 StackNode *NodeToProcess = nodesToProcess.back();
1782 }
else if (NodeToProcess->
childIter() != NodeToProcess->
end()) {
1785 nodesToProcess.push_back(
new StackNode(
1786 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1792 delete NodeToProcess;
1793 nodesToProcess.pop_back();
1809 EarlyCSE
CSE(
F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1823 static_cast<PassInfoMixin<EarlyCSEPass> *
>(
this)->
printPipeline(
1824 OS, MapClassName2PassName);
1840template<
bool UseMemorySSA>
1853 if (skipFunction(
F))
1856 auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
1857 auto &
TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
1858 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
1859 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
1861 UseMemorySSA ? &getAnalysis<MemorySSAWrapperPass>().getMSSA() :
nullptr;
1863 EarlyCSE
CSE(
F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1868 void getAnalysisUsage(AnalysisUsage &AU)
const override {
1889char EarlyCSELegacyPass::ID = 0;
1899using EarlyCSEMemSSALegacyPass =
1900 EarlyCSELegacyCommonPass<
true>;
1903char EarlyCSEMemSSALegacyPass::ID = 0;
1907 return new EarlyCSEMemSSALegacyPass();
1913 "Early CSE w/ MemorySSA",
false,
false)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool isLoad(int Opcode)
static bool isStore(int Opcode)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file defines the BumpPtrAllocator interface.
Atomic ordering constants.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Optimize for code generation
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
This file defines DenseMapInfo traits for DenseMap.
static void combineIRFlags(Instruction &From, Value *To)
EarlyCSELegacyCommonPass< false > EarlyCSELegacyPass
early cse Early CSE w MemorySSA
static unsigned getHashValueImpl(SimpleValue Val)
static bool isEqualImpl(SimpleValue LHS, SimpleValue RHS)
static bool matchSelectWithOptionalNotCond(Value *V, Value *&Cond, Value *&A, Value *&B, SelectPatternFlavor &Flavor)
Match a 'select' including an optional 'not's of the condition.
static unsigned hashCallInst(CallInst *CI)
This file provides the interface for a simple, fast CSE pass.
static bool runOnFunction(Function &F, bool PostInlining)
This is the interface for a simple mod/ref and alias analysis over globals.
This header defines various interfaces for pass management in LLVM.
static Constant * getFalse(Type *Ty)
For a boolean type or a vector of boolean type, return false or a vector with every element false.
Value * getMatchingValue(LoadValue LV, LoadInst *LI, unsigned CurrentGeneration, BatchAAResults &BAA, function_ref< MemorySSA *()> GetMSSA)
This file exposes an interface to building/using memory SSA to walk memory instructions using a use/d...
static bool isInvariantLoad(const Instruction *I, const Value *Ptr, const bool IsKernelFn)
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
const SmallVectorImpl< MachineOperand > & Cond
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
separate const offset from Split GEPs to a variadic base and a constant offset for better CSE
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)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
unsigned currentGeneration() const
unsigned childGeneration() const
DomTreeNode::const_iterator end() const
DomTreeNode * nextChild()
DomTreeNode::const_iterator childIter() const
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
A function analysis which provides an AssumptionCache.
An immutable pass that tracks lazily created AssumptionCache objects.
LLVM_ABI const BasicBlock * getSinglePredecessor() const
Return the predecessor of this block if it has a single predecessor block.
LLVM_ABI LLVMContext & getContext() const
Get the context in which this basic block lives.
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.
bool onlyWritesMemory(unsigned OpNo) const
bool onlyReadsMemory(unsigned OpNo) const
bool isConvergent() const
Determine if the invoke is convergent.
This class represents a function call, abstracting a target machine's calling convention.
This is the base class for all instructions that perform data casts.
This class is the base class for the comparison instructions.
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 getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
Predicate getPredicate() const
Return the predicate for this instruction.
An abstraction over a floating-point predicate, and a pack of an integer predicate with samesign info...
Value * getCondition() const
BasicBlock * getSuccessor(unsigned i) const
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI unsigned getIndexTypeSizeInBits(Type *Ty) const
The size in bits of the index used in GEP calculation for this type.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
static bool shouldExecute(CounterInfo &Counter)
Analysis pass which computes a DominatorTree.
DomTreeNodeBase< NodeT > * getRootNode()
getRootNode - This returns the entry node for the CFG of the function.
Legacy analysis pass which computes a DominatorTree.
This class represents a freeze function that returns random concrete value if an operand is either a ...
FunctionPass class - This class is used to implement most global optimizations.
bool isPresplitCoroutine() const
Determine if the function is presplit coroutine.
Represents calls to the gc.relocate intrinsic.
This instruction inserts a struct field of array element value into an aggregate value.
LLVM_ABI bool mayThrow(bool IncludePhaseOneUnwind=false) const LLVM_READONLY
Return true if this instruction may throw an exception.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI bool isIdenticalToWhenDefined(const Instruction *I, bool IntersectAttrs=false) const LLVM_READONLY
This is like isIdenticalTo, except that it ignores the SubclassOptionalData flags,...
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
static LLVM_ABI MemoryLocation get(const LoadInst *LI)
Return a location with information about the memory reference by the given instruction.
static LLVM_ABI std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
static LLVM_ABI MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx, const TargetLibraryInfo *TLI)
Return a location representing a particular argument of a call.
An analysis that produces MemorySSA for a function.
MemoryAccess * getClobberingMemoryAccess(const Instruction *I, BatchAAResults &AA)
Given a memory Mod/Ref/ModRef'ing instruction, calling this will give you the nearest dominating Memo...
Legacy analysis pass which computes MemorySSA.
LLVM_ABI bool dominates(const MemoryAccess *A, const MemoryAccess *B) const
Given two memory accesses in potentially different blocks, determine whether MemoryAccess A dominates...
LLVM_ABI MemorySSAWalker * getWalker()
MemoryUseOrDef * getMemoryAccess(const Instruction *I) const
Given a memory Mod/Ref'ing instruction, get the MemorySSA access associated with it.
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
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.
ScopedHashTableScope< SimpleValue, Value *, DenseMapInfo< SimpleValue >, AllocatorTy > ScopeTy
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
Analysis pass providing the TargetTransformInfo.
Analysis pass providing the TargetLibraryInfo.
Value * getOperand(unsigned i) const
iterator_range< value_op_iterator > operand_values()
LLVM Value Representation.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
constexpr ScalarTy getFixedValue() const
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
An efficient, type-erasing, non-owning reference to a callable.
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.
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
auto m_Cmp()
Matches any compare instruction and ignore it.
bool match(Val *V, const Pattern &P)
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
auto m_Value()
Match an arbitrary value and ignore it.
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
constexpr bool isAtomic(const T &...O)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
@ ebStrict
This corresponds to "fpexcept.strict".
NodeAddr< NodeBase * > Node
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Type * getValueType(Value *V, bool ReVec, bool LookThroughCmp)
Returns the "element type" of the given value/instruction V.
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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI void salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI)
Assuming the instruction MI is going to be deleted, attempt to salvage debug users of MI by writing t...
const Value * getLoadStorePointerOperand(const Value *V)
A helper function that returns the pointer operand of a load or store instruction.
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...
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
LLVM_ABI void initializeEarlyCSEMemSSALegacyPassPass(PassRegistry &)
LLVM_ABI Value * simplifyInstruction(Instruction *I, const SimplifyQuery &Q)
See if we can compute a simplified version of this instruction.
DomTreeNodeBase< BasicBlock > DomTreeNode
LLVM_ABI bool isInstructionTriviallyDead(Instruction *I, const TargetLibraryInfo *TLI=nullptr)
Return true if the result produced by the instruction is not used, and the instruction will return.
LLVM_ABI bool isGuard(const User *U)
Returns true iff U has semantics of a guard expressed in a form of call of llvm.experimental....
SelectPatternFlavor
Specific patterns of select instructions we can match.
@ SPF_UMIN
Signed minimum.
@ SPF_UMAX
Signed maximum.
@ SPF_SMAX
Unsigned minimum.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI bool programUndefinedIfPoison(const Instruction *Inst)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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_ABI void combineMetadataForCSE(Instruction *K, const Instruction *J, bool DoesKMove)
Combine the metadata of two instructions so that K can replace J.
LLVM_ABI bool VerifyMemorySSA
Enables verification of MemorySSA.
LLVM_ABI bool salvageKnowledge(Instruction *I, AssumptionCache *AC=nullptr, DominatorTree *DT=nullptr)
Calls BuildAssumeFromInst and if the resulting llvm.assume is valid insert if before I.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
LLVM_ABI FunctionPass * createEarlyCSEPass(bool UseMemorySSA=false)
LLVM_ABI void initializeEarlyCSELegacyPassPass(PassRegistry &)
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
static unsigned getHashValue(CallValue Val)
static bool isEqual(CallValue LHS, CallValue RHS)
static bool isEqual(const GEPValue &LHS, const GEPValue &RHS)
static unsigned getHashValue(const GEPValue &Val)
static unsigned getHashValue(SimpleValue Val)
static bool isEqual(SimpleValue LHS, SimpleValue RHS)
An information struct used to provide DenseMap with the various necessary components for a given valu...
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Run the pass over the function.
LLVM_ABI void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName)