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);
182 if (BinOp->isCommutative() && BinOp->getOperand(0) > BinOp->getOperand(1))
197 if (std::tie(
LHS, Pred) > std::tie(
RHS, SwappedPred)) {
226 return hash_combine(CI->getOpcode(), CI->getType(), CI->getOperand(0));
229 return hash_combine(FI->getOpcode(), FI->getOperand(0));
232 return hash_combine(EVI->getOpcode(), EVI->getOperand(0),
236 return hash_combine(IVI->getOpcode(), IVI->getOperand(0),
242 "Invalid/unknown instruction");
246 if (
II &&
II->isCommutative() &&
II->arg_size() >= 2) {
259 return hash_combine(GCR->getOpcode(), GCR->getOperand(0),
260 GCR->getBasePtr(), GCR->getDerivedPtr());
280 .
get<ScalarOptions>()
281 .earlycse_debug_hash)
290 if (LHSI->
getOpcode() != RHSI->getOpcode())
297 CI && CI->isConvergent() && LHSI->
getParent() != RHSI->getParent())
305 if (!LHSBinOp->isCommutative())
309 "same opcode, but different instruction type?");
313 return LHSBinOp->getOperand(0) == RHSBinOp->
getOperand(1) &&
314 LHSBinOp->getOperand(1) == RHSBinOp->
getOperand(0);
318 "same opcode, but different instruction type?");
321 return LHSCmp->getOperand(0) == RHSCmp->
getOperand(1) &&
322 LHSCmp->getOperand(1) == RHSCmp->
getOperand(0) &&
323 LHSCmp->getSwappedPredicate() == RHSCmp->
getPredicate();
328 if (LII && RII && LII->getIntrinsicID() == RII->getIntrinsicID() &&
329 LII->isCommutative() && LII->arg_size() >= 2) {
330 return LII->getArgOperand(0) == RII->getArgOperand(1) &&
331 LII->getArgOperand(1) == RII->getArgOperand(0) &&
332 std::equal(LII->arg_begin() + 2, LII->arg_end(),
333 RII->arg_begin() + 2, RII->arg_end()) &&
334 LII->hasSameSpecialState(RII,
false,
341 return GCR1->getOperand(0) == GCR2->getOperand(0) &&
342 GCR1->getBasePtr() == GCR2->getBasePtr() &&
343 GCR1->getDerivedPtr() == GCR2->getDerivedPtr();
346 Value *CondL, *CondR, *LHSA, *RHSA, *LHSB, *RHSB;
350 if (CondL == CondR && LHSA == RHSA && LHSB == RHSB)
361 if (LHSA == RHSB && LHSB == RHSA) {
393 CallValue(Instruction *
I) : Inst(
I) {
394 assert(canHandle(
I) &&
"Inst can't be handled!");
397 static bool canHandle(Instruction *Inst) {
417 static bool isEqual(CallValue LHS, CallValue RHS);
448 std::optional<int64_t> ConstantOffset;
450 GEPValue(Instruction *
I) : Inst(
I) {
451 assert(canHandle(
I) &&
"Inst can't be handled!");
454 GEPValue(Instruction *
I, std::optional<int64_t> ConstantOffset)
455 : Inst(
I), ConstantOffset(ConstantOffset) {
456 assert(canHandle(
I) &&
"Inst can't be handled!");
459 static bool canHandle(Instruction *Inst) {
468 static bool isEqual(
const GEPValue &LHS,
const GEPValue &RHS);
473 if (Val.ConstantOffset.has_value())
475 Val.ConstantOffset.value());
483 if (LGEP->getPointerOperand() != RGEP->getPointerOperand())
485 if (
LHS.ConstantOffset.has_value() &&
RHS.ConstantOffset.has_value())
486 return LHS.ConstantOffset.value() ==
RHS.ConstantOffset.value();
487 return LGEP->isIdenticalToWhenDefined(RGEP);
505 const ScalarOptions &Opts;
506 const TargetLibraryInfo &TLI;
507 const TargetTransformInfo &TTI;
510 const SimplifyQuery SQ;
512 std::unique_ptr<MemorySSAUpdater> MSSAUpdater;
516 ScopedHashTableVal<SimpleValue, Value *>>;
518 ScopedHashTable<SimpleValue, Value *, DenseMapInfo<SimpleValue>,
527 ScopedHTType AvailableValues;
545 unsigned Generation = 0;
547 bool IsAtomic =
false;
550 LoadValue() =
default;
551 LoadValue(Instruction *Inst,
unsigned Generation,
unsigned MatchingId,
552 bool IsAtomic,
bool IsLoad)
553 : DefInst(Inst), Generation(Generation), MatchingId(MatchingId),
554 IsAtomic(IsAtomic), IsLoad(IsLoad) {}
557 using LoadMapAllocator =
559 ScopedHashTableVal<Value *, LoadValue>>;
561 ScopedHashTable<Value *, LoadValue, DenseMapInfo<Value *>,
564 LoadHTType AvailableLoads;
569 using InvariantMapAllocator =
571 ScopedHashTableVal<MemoryLocation, unsigned>>;
572 using InvariantHTType =
573 ScopedHashTable<MemoryLocation, unsigned, DenseMapInfo<MemoryLocation>,
574 InvariantMapAllocator>;
575 InvariantHTType AvailableInvariants;
582 ScopedHashTable<CallValue, std::pair<Instruction *, unsigned>>;
583 CallHTType AvailableCalls;
585 using GEPMapAllocatorTy =
587 ScopedHashTableVal<GEPValue, Value *>>;
588 using GEPHTType = ScopedHashTable<GEPValue, Value *, DenseMapInfo<GEPValue>,
590 GEPHTType AvailableGEPs;
593 unsigned CurrentGeneration = 0;
596 EarlyCSE(
const ScalarOptions &Opts,
const DataLayout &
DL,
597 const TargetLibraryInfo &TLI,
const TargetTransformInfo &TTI,
598 DominatorTree &DT, AssumptionCache &AC,
MemorySSA *MSSA)
599 : Opts(Opts), TLI(TLI), TTI(TTI), DT(DT), AC(AC), SQ(
DL, &TLI, &DT, &AC),
600 MSSA(MSSA), MSSAUpdater(std::make_unique<MemorySSAUpdater>(MSSA)) {}
605 unsigned ClobberCounter = 0;
611 NodeScope(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
612 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
613 GEPHTType &AvailableGEPs)
614 : Scope(AvailableValues), LoadScope(AvailableLoads),
615 InvariantScope(AvailableInvariants), CallScope(AvailableCalls),
616 GEPScope(AvailableGEPs) {}
617 NodeScope(
const NodeScope &) =
delete;
618 NodeScope &operator=(
const NodeScope &) =
delete;
634 StackNode(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
635 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
636 GEPHTType &AvailableGEPs,
unsigned cg,
DomTreeNode *n,
637 DomTreeNode::const_iterator child,
638 DomTreeNode::const_iterator end)
639 : CurrentGeneration(cg), ChildGeneration(cg), Node(n), ChildIter(child),
641 Scopes(AvailableValues, AvailableLoads, AvailableInvariants,
642 AvailableCalls, AvailableGEPs) {}
643 StackNode(
const StackNode &) =
delete;
644 StackNode &operator=(
const StackNode &) =
delete;
647 unsigned currentGeneration()
const {
return CurrentGeneration; }
648 unsigned childGeneration()
const {
return ChildGeneration; }
651 DomTreeNode::const_iterator childIter()
const {
return ChildIter; }
659 DomTreeNode::const_iterator
end()
const {
return EndIter; }
660 bool isProcessed()
const {
return Processed; }
661 void process() { Processed =
true; }
664 unsigned CurrentGeneration;
665 unsigned ChildGeneration;
667 DomTreeNode::const_iterator ChildIter;
668 DomTreeNode::const_iterator EndIter;
670 bool Processed =
false;
675 class ParseMemoryInst {
677 ParseMemoryInst(Instruction *Inst,
const TargetTransformInfo &
TTI)
680 IntrID =
II->getIntrinsicID();
683 if (isHandledNonTargetIntrinsic(IntrID)) {
685 case Intrinsic::masked_load:
686 Info.PtrVal = Inst->getOperand(0);
687 Info.MatchingId = Intrinsic::masked_load;
689 Info.WriteMem =
false;
690 Info.IsVolatile =
false;
692 case Intrinsic::masked_store:
693 Info.PtrVal = Inst->getOperand(1);
700 Info.MatchingId = Intrinsic::masked_load;
701 Info.ReadMem =
false;
702 Info.WriteMem =
true;
703 Info.IsVolatile =
false;
707 Info.PtrVal =
MI->getDest();
709 Info.ReadMem =
false;
710 Info.WriteMem =
true;
711 Info.IsVolatile =
MI->isVolatile();
727 return Info.WriteMem;
733 return Info.Ordering != AtomicOrdering::NotAtomic;
734 return Inst->isAtomic();
737 bool isUnordered()
const {
739 return Info.isUnordered();
742 return LI->isUnordered();
744 return SI->isUnordered();
747 return !Inst->isAtomic();
750 bool isVolatile()
const {
752 return Info.IsVolatile;
755 return LI->isVolatile();
757 return SI->isVolatile();
765 return LI->hasMetadata(LLVMContext::MD_invariant_load);
775 int getMatchingId()
const {
777 return Info.MatchingId;
789 return Inst->getAccessType();
792 bool mayReadFromMemory()
const {
795 return Inst->mayReadFromMemory();
798 bool mayWriteToMemory()
const {
800 return Info.WriteMem;
801 return Inst->mayWriteToMemory();
806 MemIntrinsicInfo Info;
814 case Intrinsic::masked_load:
815 case Intrinsic::masked_store:
820 static bool isHandledNonTargetIntrinsic(
const Value *V) {
822 return isHandledNonTargetIntrinsic(
II->getIntrinsicID());
828 bool handleBranchCondition(Instruction *CondInst,
const CondBrInst *BI,
829 const BasicBlock *BB,
const BasicBlock *Pred);
832 unsigned CurrentGeneration);
834 bool overridingStores(
const ParseMemoryInst &Earlier,
835 const ParseMemoryInst &Later);
837 Value *getOrCreateResult(Instruction *Inst,
Type *ExpectedType,
838 bool CanCreate)
const {
843 switch (
II->getIntrinsicID()) {
844 case Intrinsic::masked_load:
847 case Intrinsic::masked_store:
848 V =
II->getOperand(0);
851 return TTI.getOrCreateResultFromMemIntrinsic(
II, ExpectedType,
858 return V->getType() == ExpectedType ?
V :
nullptr;
863 bool isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt);
865 bool isSameMemGeneration(
unsigned EarlierGeneration,
unsigned LaterGeneration,
866 Instruction *EarlierInst, Instruction *LaterInst);
868 bool isNonTargetIntrinsicMatch(
const IntrinsicInst *Earlier,
869 const IntrinsicInst *Later) {
870 auto IsSubmask = [](
const Value *Mask0,
const Value *Mask1) {
880 if (Vec0->getType() != Vec1->getType())
882 for (
int i = 0, e = Vec0->getNumOperands(); i != e; ++i) {
883 Constant *Elem0 = Vec0->getOperand(i);
884 Constant *Elem1 = Vec1->getOperand(i);
886 if (Int0 && Int0->isZero())
899 auto PtrOp = [](
const IntrinsicInst *
II) {
900 if (
II->getIntrinsicID() == Intrinsic::masked_load)
901 return II->getOperand(0);
902 if (
II->getIntrinsicID() == Intrinsic::masked_store)
903 return II->getOperand(1);
906 auto MaskOp = [](
const IntrinsicInst *
II) {
907 if (
II->getIntrinsicID() == Intrinsic::masked_load)
908 return II->getOperand(1);
909 if (
II->getIntrinsicID() == Intrinsic::masked_store)
910 return II->getOperand(2);
913 auto ThruOp = [](
const IntrinsicInst *
II) {
914 if (
II->getIntrinsicID() == Intrinsic::masked_load)
915 return II->getOperand(2);
919 if (PtrOp(Earlier) != PtrOp(Later))
926 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_load) {
932 if (MaskOp(Earlier) == MaskOp(Later) && ThruOp(Earlier) == ThruOp(Later))
936 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
938 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_load) {
943 if (!IsSubmask(MaskOp(Later), MaskOp(Earlier)))
947 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_store) {
951 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
953 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_store) {
958 return IsSubmask(MaskOp(Earlier), MaskOp(Later));
963 void removeMSSA(Instruction &Inst) {
967 MSSA->verifyMemorySSA();
974 MSSAUpdater->removeMemoryAccess(&Inst,
true);
996bool EarlyCSE::isSameMemGeneration(
unsigned EarlierGeneration,
997 unsigned LaterGeneration,
1001 if (EarlierGeneration == LaterGeneration)
1025 MemoryAccess *LaterDef;
1026 if (ClobberCounter < Opts.earlycse_mssa_optimization_cap) {
1030 LaterDef = LaterMA->getDefiningAccess();
1032 return MSSA->
dominates(LaterDef, EarlierMA);
1035bool EarlyCSE::isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt) {
1039 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
1047 MemoryLocation MemLoc = *MemLocOpt;
1048 if (!AvailableInvariants.count(MemLoc))
1053 return AvailableInvariants.lookup(MemLoc) <= GenAt;
1056bool EarlyCSE::handleBranchCondition(Instruction *CondInst,
1057 const CondBrInst *BI,
const BasicBlock *BB,
1058 const BasicBlock *Pred) {
1066 if (Opcode == Instruction::And &&
1069 else if (Opcode == Instruction::Or &&
1077 unsigned PropagateOpcode =
1078 (BI->
getSuccessor(0) == BB) ? Instruction::And : Instruction::Or;
1080 bool MadeChanges =
false;
1081 SmallVector<Instruction *, 4> WorkList;
1082 SmallPtrSet<Instruction *, 4> Visited;
1084 while (!WorkList.
empty()) {
1085 Instruction *Curr = WorkList.pop_back_val();
1087 AvailableValues.insert(Curr, TorF);
1088 LLVM_DEBUG(dbgs() <<
"EarlyCSE CVP: Add conditional value for '"
1089 << Curr->getName() <<
"' as " << *TorF <<
" in "
1090 << BB->getName() <<
"\n");
1091 if (!DebugCounter::shouldExecute(CSECounter)) {
1092 LLVM_DEBUG(dbgs() <<
"Skipping due to debug counter\n");
1095 if (unsigned Count = replaceDominatedUsesWith(Curr, TorF, DT,
1096 BasicBlockEdge(Pred, BB))) {
1103 if (MatchBinOp(Curr, PropagateOpcode,
LHS,
RHS))
1106 if (SimpleValue::canHandle(OPI) && Visited.
insert(OPI).second)
1113Value *EarlyCSE::getMatchingValue(LoadValue &InVal, ParseMemoryInst &MemInst,
1114 unsigned CurrentGeneration) {
1115 if (InVal.DefInst ==
nullptr)
1118 if (!MemInst.isLoad() || MemInst.isVolatile() || !MemInst.isUnordered() ||
1119 MemInst.getMatchingId() != -1)
1121 if (MSI->isVolatile())
1124 if (!Val || !Val->isZero())
1126 auto Len = MSI->getLengthInBytes();
1129 Type *InstType = MemInst.getValueType();
1135 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1136 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1141 if (InVal.MatchingId != MemInst.getMatchingId())
1144 if (MemInst.isVolatile() || !MemInst.isUnordered())
1147 if (MemInst.isLoad() && !InVal.IsAtomic && MemInst.isAtomic())
1153 bool MemInstMatching = !MemInst.isLoad();
1154 Instruction *Matching = MemInstMatching ? MemInst.get() : InVal.DefInst;
1161 ? getOrCreateResult(Matching,
Other->getType(),
false)
1163 if (MemInst.isStore() && InVal.DefInst != Result)
1167 bool MatchingNTI = isHandledNonTargetIntrinsic(Matching);
1168 bool OtherNTI = isHandledNonTargetIntrinsic(
Other);
1169 if (OtherNTI != MatchingNTI)
1171 if (OtherNTI && MatchingNTI) {
1177 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1178 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1183 Result = getOrCreateResult(Matching,
Other->getType(),
true);
1197 I->andIRFlags(&From);
1211 assert(
Success &&
"Failed to intersect attributes in callsites that "
1212 "passed identical check");
1218bool EarlyCSE::overridingStores(
const ParseMemoryInst &Earlier,
1219 const ParseMemoryInst &Later) {
1222 assert(Earlier.isUnordered() && !Earlier.isVolatile() &&
1223 "Violated invariant");
1224 if (Earlier.getPointerOperand() != Later.getPointerOperand())
1226 if (!Earlier.getValueType() || !Later.getValueType() ||
1227 Earlier.getValueType() != Later.getValueType())
1229 if (Earlier.getMatchingId() != Later.getMatchingId())
1236 if (!Earlier.isUnordered() || !Later.isUnordered())
1240 bool ENTI = isHandledNonTargetIntrinsic(Earlier.get());
1241 bool LNTI = isHandledNonTargetIntrinsic(Later.get());
1249 return ENTI == LNTI;
1263 ++CurrentGeneration;
1274 if (CondInst && SimpleValue::canHandle(CondInst))
1275 Changed |= handleBranchCondition(CondInst, BI, BB, Pred);
1311 if (CondI && SimpleValue::canHandle(CondI)) {
1316 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping assumption: " << Inst <<
'\n');
1323 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping noalias intrinsic: " << Inst
1330 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping sideeffect: " << Inst <<
'\n');
1336 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping pseudoprobe: " << Inst <<
'\n');
1357 MemoryLocation MemLoc =
1360 if (!AvailableInvariants.count(MemLoc))
1361 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1368 if (SimpleValue::canHandle(CondI)) {
1370 if (
auto *KnownCond = AvailableValues.lookup(CondI)) {
1375 <<
"EarlyCSE removing guard: " << Inst <<
'\n');
1394 LastStore =
nullptr;
1401 LLVM_DEBUG(
dbgs() <<
"EarlyCSE Simplify: " << Inst <<
" to: " << *V
1406 bool Killed =
false;
1428 LastStore =
nullptr;
1431 if (SimpleValue::canHandle(&Inst)) {
1434 "Unexpected ebStrict from SimpleValue::canHandle()");
1435 assert((!CI->getRoundingMode() ||
1436 CI->getRoundingMode() != RoundingMode::Dynamic) &&
1437 "Unexpected dynamic rounding from SimpleValue::canHandle()");
1440 if (
Value *V = AvailableValues.lookup(&Inst)) {
1458 AvailableValues.insert(&Inst, &Inst);
1462 ParseMemoryInst MemInst(&Inst,
TTI);
1464 if (MemInst.isValid() && MemInst.isLoad()) {
1467 if (MemInst.isVolatile() || !MemInst.isUnordered()) {
1468 LastStore =
nullptr;
1469 ++CurrentGeneration;
1472 if (MemInst.isInvariantLoad()) {
1479 if (!AvailableInvariants.count(MemLoc))
1480 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1490 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1493 <<
" to: " << *InVal.DefInst <<
'\n');
1512 AvailableLoads.insert(MemInst.getPointerOperand(),
1513 LoadValue(&Inst, CurrentGeneration,
1514 MemInst.getMatchingId(),
1517 LastStore =
nullptr;
1527 !(MemInst.isValid() && !MemInst.mayReadFromMemory()))
1528 LastStore =
nullptr;
1534 if (CallValue::canHandle(&Inst) &&
1535 (!MemInst.isValid() || !MemInst.isStore()) && !
isa<MemSetInst>(&Inst)) {
1538 std::pair<Instruction *, unsigned> InVal = AvailableCalls.lookup(&Inst);
1539 if (InVal.first !=
nullptr &&
1540 isSameMemGeneration(InVal.second, CurrentGeneration, InVal.first,
1544 <<
" to: " << *InVal.first <<
'\n');
1563 ++CurrentGeneration;
1566 AvailableCalls.insert(&Inst, std::make_pair(&Inst, CurrentGeneration));
1571 if (GEPValue::canHandle(&Inst)) {
1574 GEPValue GEPVal(
GEP,
GEP->accumulateConstantOffset(SQ.
DL,
Offset)
1577 if (
Value *V = AvailableGEPs.lookup(GEPVal)) {
1578 LLVM_DEBUG(
dbgs() <<
"EarlyCSE CSE GEP: " << Inst <<
" to: " << *V
1591 AvailableGEPs.insert(GEPVal, &Inst);
1601 if (FI->getOrdering() == AtomicOrdering::Release) {
1611 if (MemInst.isValid() && MemInst.isStore()) {
1612 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1613 if (InVal.DefInst &&
1616 LLVM_DEBUG(
dbgs() <<
"EarlyCSE DSE (writeback): " << Inst <<
'\n');
1636 ++CurrentGeneration;
1638 if (MemInst.isValid() && MemInst.isStore()) {
1642 if (overridingStores(ParseMemoryInst(LastStore,
TTI), MemInst)) {
1644 <<
" due to: " << Inst <<
'\n');
1649 removeMSSA(*LastStore);
1653 LastStore =
nullptr;
1664 AvailableLoads.insert(MemInst.getPointerOperand(),
1665 LoadValue(&Inst, CurrentGeneration,
1666 MemInst.getMatchingId(),
1677 if (MemInst.isUnordered() && !MemInst.isVolatile())
1680 LastStore =
nullptr;
1688bool EarlyCSE::run() {
1694 std::deque<StackNode *> nodesToProcess;
1699 nodesToProcess.push_back(
new StackNode(
1700 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1701 AvailableGEPs, CurrentGeneration, DT.
getRootNode(),
1704 assert(!CurrentGeneration &&
"Create a new EarlyCSE instance to rerun it.");
1707 while (!nodesToProcess.empty()) {
1710 StackNode *NodeToProcess = nodesToProcess.back();
1721 }
else if (NodeToProcess->
childIter() != NodeToProcess->
end()) {
1724 nodesToProcess.push_back(
new StackNode(
1725 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1731 delete NodeToProcess;
1732 nodesToProcess.pop_back();
1748 EarlyCSE
CSE(
F.getContext().getLibraryOptions().get<ScalarOptions>(),
1749 F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1763 static_cast<PassInfoMixin<EarlyCSEPass> *
>(
this)->
printPipeline(
1764 OS, MapClassName2PassName);
1780template<
bool UseMemorySSA>
1793 if (skipFunction(
F))
1796 auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
1797 auto &
TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
1798 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
1799 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
1801 UseMemorySSA ? &getAnalysis<MemorySSAWrapperPass>().getMSSA() :
nullptr;
1803 EarlyCSE
CSE(
F.getContext().getLibraryOptions().get<ScalarOptions>(),
1804 F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1809 void getAnalysisUsage(AnalysisUsage &AU)
const override {
1830char EarlyCSELegacyPass::ID = 0;
1840using EarlyCSEMemSSALegacyPass =
1841 EarlyCSELegacyCommonPass<
true>;
1844char EarlyCSEMemSSALegacyPass::ID = 0;
1848 return new EarlyCSEMemSSALegacyPass();
1854 "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
static bool matchSelectWithOptionalNotCond(Value *V, Value *&Cond, Value *&A, Value *&B)
Match a 'select' including an optional 'not's of the condition.
early cse Early CSE w MemorySSA
static unsigned getHashValueImpl(SimpleValue Val)
static bool isEqualImpl(SimpleValue LHS, SimpleValue RHS)
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.
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.
LLVM_ABI cl::LibraryOptionsContext & getLibraryOptions() const
The library options this context reads in place of their process-wide values.
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.
LLVMContext & getContext() const
All values hold a context through their type.
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))
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....
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)