63#define DEBUG_TYPE "early-cse"
65STATISTIC(NumSimplify,
"Number of instructions simplified or DCE'd");
67STATISTIC(NumCSECVP,
"Number of compare instructions CVP'd");
68STATISTIC(NumCSELoad,
"Number of load instructions CSE'd");
69STATISTIC(NumCSECall,
"Number of call instructions CSE'd");
70STATISTIC(NumCSEGEP,
"Number of GEP instructions CSE'd");
71STATISTIC(NumDSE,
"Number of trivial dead stores removed");
74 "Controls which instructions are removed");
78 cl::desc(
"Enable imprecision in EarlyCSE in pathological cases, in exchange "
79 "for faster compile. Caps the MemorySSA clobbering calls."));
83 cl::desc(
"Perform extra assertion checking to verify that SimpleValue's hash "
84 "function is well-behaved w.r.t. its isEqual predicate"));
101 return Inst == DenseMapInfo<Instruction *>::getEmptyKey() ||
102 Inst == DenseMapInfo<Instruction *>::getTombstoneKey();
105 static bool canHandle(Instruction *Inst) {
110 if (Function *
F = CI->getCalledFunction()) {
111 switch (
F->getIntrinsicID()) {
112 case Intrinsic::experimental_constrained_fadd:
113 case Intrinsic::experimental_constrained_fsub:
114 case Intrinsic::experimental_constrained_fmul:
115 case Intrinsic::experimental_constrained_fdiv:
116 case Intrinsic::experimental_constrained_frem:
117 case Intrinsic::experimental_constrained_fptosi:
118 case Intrinsic::experimental_constrained_sitofp:
119 case Intrinsic::experimental_constrained_fptoui:
120 case Intrinsic::experimental_constrained_uitofp:
121 case Intrinsic::experimental_constrained_fcmp:
122 case Intrinsic::experimental_constrained_fcmps: {
124 if (CFP->getExceptionBehavior() &&
129 if (CFP->getRoundingMode() &&
130 CFP->getRoundingMode() == RoundingMode::Dynamic)
136 return CI->doesNotAccessMemory() &&
144 !CI->getFunction()->isPresplitCoroutine();
167 static bool isEqual(SimpleValue LHS, SimpleValue RHS);
235 if (BinOp->isCommutative() && BinOp->getOperand(0) > BinOp->getOperand(1))
250 if (std::tie(
LHS, Pred) > std::tie(
RHS, SwappedPred)) {
292 return hash_combine(CI->getOpcode(), CI->getType(), CI->getOperand(0));
295 return hash_combine(FI->getOpcode(), FI->getOperand(0));
298 return hash_combine(EVI->getOpcode(), EVI->getOperand(0),
302 return hash_combine(IVI->getOpcode(), IVI->getOperand(0),
308 "Invalid/unknown instruction");
312 if (
II &&
II->isCommutative() &&
II->arg_size() >= 2) {
325 return hash_combine(GCR->getOpcode(), GCR->getOperand(0),
326 GCR->getBasePtr(), GCR->getDerivedPtr());
353 if (
LHS.isSentinel() ||
RHS.isSentinel())
356 if (LHSI->
getOpcode() != RHSI->getOpcode())
363 CI && CI->isConvergent() && LHSI->
getParent() != RHSI->getParent())
371 if (!LHSBinOp->isCommutative())
375 "same opcode, but different instruction type?");
379 return LHSBinOp->getOperand(0) == RHSBinOp->
getOperand(1) &&
380 LHSBinOp->getOperand(1) == RHSBinOp->
getOperand(0);
384 "same opcode, but different instruction type?");
387 return LHSCmp->getOperand(0) == RHSCmp->
getOperand(1) &&
388 LHSCmp->getOperand(1) == RHSCmp->
getOperand(0) &&
389 LHSCmp->getSwappedPredicate() == RHSCmp->
getPredicate();
394 if (LII && RII && LII->getIntrinsicID() == RII->getIntrinsicID() &&
395 LII->isCommutative() && LII->arg_size() >= 2) {
396 return LII->getArgOperand(0) == RII->getArgOperand(1) &&
397 LII->getArgOperand(1) == RII->getArgOperand(0) &&
398 std::equal(LII->arg_begin() + 2, LII->arg_end(),
399 RII->arg_begin() + 2, RII->arg_end()) &&
400 LII->hasSameSpecialState(RII,
false,
407 return GCR1->getOperand(0) == GCR2->getOperand(0) &&
408 GCR1->getBasePtr() == GCR2->getBasePtr() &&
409 GCR1->getDerivedPtr() == GCR2->getDerivedPtr();
415 Value *CondL, *CondR, *LHSA, *RHSA, *LHSB, *RHSB;
422 return ((LHSA == RHSA && LHSB == RHSB) ||
423 (LHSA == RHSB && LHSB == RHSA));
426 if (CondL == CondR && LHSA == RHSA && LHSB == RHSB)
448 if (LHSA == RHSB && LHSB == RHSA) {
481 CallValue(Instruction *
I) : Inst(
I) {
486 return Inst == DenseMapInfo<Instruction *>::getEmptyKey() ||
487 Inst == DenseMapInfo<Instruction *>::getTombstoneKey();
490 static bool canHandle(Instruction *Inst) {
518 static bool isEqual(CallValue LHS, CallValue RHS);
529 if (
LHS.isSentinel() ||
RHS.isSentinel())
530 return LHS.Inst ==
RHS.Inst;
552 std::optional<int64_t> ConstantOffset;
554 GEPValue(Instruction *
I) : Inst(
I) {
558 GEPValue(Instruction *
I, std::optional<int64_t> ConstantOffset)
559 : Inst(
I), ConstantOffset(ConstantOffset) {
564 return Inst == DenseMapInfo<Instruction *>::getEmptyKey() ||
565 Inst == DenseMapInfo<Instruction *>::getTombstoneKey();
568 static bool canHandle(Instruction *Inst) {
585 static bool isEqual(
const GEPValue &LHS,
const GEPValue &RHS);
590 if (Val.ConstantOffset.has_value())
592 Val.ConstantOffset.value());
598 if (
LHS.isSentinel() ||
RHS.isSentinel())
599 return LHS.Inst ==
RHS.Inst;
602 if (LGEP->getPointerOperand() != RGEP->getPointerOperand())
604 if (
LHS.ConstantOffset.has_value() &&
RHS.ConstantOffset.has_value())
605 return LHS.ConstantOffset.value() ==
RHS.ConstantOffset.value();
606 return LGEP->isIdenticalToWhenDefined(RGEP);
624 const TargetLibraryInfo &TLI;
625 const TargetTransformInfo &TTI;
628 const SimplifyQuery SQ;
630 std::unique_ptr<MemorySSAUpdater> MSSAUpdater;
634 ScopedHashTableVal<SimpleValue, Value *>>;
636 ScopedHashTable<SimpleValue, Value *, DenseMapInfo<SimpleValue>,
645 ScopedHTType AvailableValues;
663 unsigned Generation = 0;
665 bool IsAtomic =
false;
668 LoadValue() =
default;
669 LoadValue(Instruction *Inst,
unsigned Generation,
unsigned MatchingId,
670 bool IsAtomic,
bool IsLoad)
671 : DefInst(Inst), Generation(Generation), MatchingId(MatchingId),
672 IsAtomic(IsAtomic), IsLoad(IsLoad) {}
675 using LoadMapAllocator =
677 ScopedHashTableVal<Value *, LoadValue>>;
679 ScopedHashTable<Value *, LoadValue, DenseMapInfo<Value *>,
682 LoadHTType AvailableLoads;
687 using InvariantMapAllocator =
689 ScopedHashTableVal<MemoryLocation, unsigned>>;
690 using InvariantHTType =
691 ScopedHashTable<MemoryLocation, unsigned, DenseMapInfo<MemoryLocation>,
692 InvariantMapAllocator>;
693 InvariantHTType AvailableInvariants;
700 ScopedHashTable<CallValue, std::pair<Instruction *, unsigned>>;
701 CallHTType AvailableCalls;
703 using GEPMapAllocatorTy =
705 ScopedHashTableVal<GEPValue, Value *>>;
706 using GEPHTType = ScopedHashTable<GEPValue, Value *, DenseMapInfo<GEPValue>,
708 GEPHTType AvailableGEPs;
711 unsigned CurrentGeneration = 0;
714 EarlyCSE(
const DataLayout &
DL,
const TargetLibraryInfo &TLI,
715 const TargetTransformInfo &TTI, DominatorTree &DT,
717 : TLI(TLI), TTI(TTI), DT(DT), AC(AC), SQ(
DL, &TLI, &DT, &AC), MSSA(MSSA),
718 MSSAUpdater(std::make_unique<MemorySSAUpdater>(MSSA)) {}
723 unsigned ClobberCounter = 0;
729 NodeScope(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
730 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
731 GEPHTType &AvailableGEPs)
732 : Scope(AvailableValues), LoadScope(AvailableLoads),
733 InvariantScope(AvailableInvariants), CallScope(AvailableCalls),
734 GEPScope(AvailableGEPs) {}
735 NodeScope(
const NodeScope &) =
delete;
736 NodeScope &operator=(
const NodeScope &) =
delete;
752 StackNode(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
753 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
754 GEPHTType &AvailableGEPs,
unsigned cg,
DomTreeNode *n,
757 : CurrentGeneration(cg), ChildGeneration(cg), Node(n), ChildIter(child),
759 Scopes(AvailableValues, AvailableLoads, AvailableInvariants,
760 AvailableCalls, AvailableGEPs) {}
761 StackNode(
const StackNode &) =
delete;
762 StackNode &operator=(
const StackNode &) =
delete;
765 unsigned currentGeneration()
const {
return CurrentGeneration; }
766 unsigned childGeneration()
const {
return ChildGeneration; }
778 bool isProcessed()
const {
return Processed; }
779 void process() { Processed =
true; }
782 unsigned CurrentGeneration;
783 unsigned ChildGeneration;
788 bool Processed =
false;
793 class ParseMemoryInst {
795 ParseMemoryInst(Instruction *Inst,
const TargetTransformInfo &
TTI)
798 IntrID =
II->getIntrinsicID();
801 if (isHandledNonTargetIntrinsic(IntrID)) {
803 case Intrinsic::masked_load:
804 Info.PtrVal = Inst->getOperand(0);
805 Info.MatchingId = Intrinsic::masked_load;
807 Info.WriteMem =
false;
808 Info.IsVolatile =
false;
810 case Intrinsic::masked_store:
811 Info.PtrVal = Inst->getOperand(1);
818 Info.MatchingId = Intrinsic::masked_load;
819 Info.ReadMem =
false;
820 Info.WriteMem =
true;
821 Info.IsVolatile =
false;
839 return Info.WriteMem;
843 bool isAtomic()
const {
845 return Info.Ordering != AtomicOrdering::NotAtomic;
846 return Inst->isAtomic();
849 bool isUnordered()
const {
851 return Info.isUnordered();
854 return LI->isUnordered();
856 return SI->isUnordered();
859 return !Inst->isAtomic();
862 bool isVolatile()
const {
864 return Info.IsVolatile;
867 return LI->isVolatile();
869 return SI->isVolatile();
877 return LI->hasMetadata(LLVMContext::MD_invariant_load);
887 int getMatchingId()
const {
889 return Info.MatchingId;
901 return Inst->getAccessType();
904 bool mayReadFromMemory()
const {
907 return Inst->mayReadFromMemory();
910 bool mayWriteToMemory()
const {
912 return Info.WriteMem;
913 return Inst->mayWriteToMemory();
918 MemIntrinsicInfo Info;
926 case Intrinsic::masked_load:
927 case Intrinsic::masked_store:
932 static bool isHandledNonTargetIntrinsic(
const Value *V) {
934 return isHandledNonTargetIntrinsic(
II->getIntrinsicID());
940 bool handleBranchCondition(Instruction *CondInst,
const BranchInst *BI,
941 const BasicBlock *BB,
const BasicBlock *Pred);
944 unsigned CurrentGeneration);
946 bool overridingStores(
const ParseMemoryInst &Earlier,
947 const ParseMemoryInst &Later);
949 Value *getOrCreateResult(Instruction *Inst,
Type *ExpectedType,
950 bool CanCreate)
const {
955 switch (
II->getIntrinsicID()) {
956 case Intrinsic::masked_load:
959 case Intrinsic::masked_store:
960 V =
II->getOperand(0);
963 return TTI.getOrCreateResultFromMemIntrinsic(
II, ExpectedType,
970 return V->getType() == ExpectedType ?
V :
nullptr;
975 bool isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt);
977 bool isSameMemGeneration(
unsigned EarlierGeneration,
unsigned LaterGeneration,
978 Instruction *EarlierInst, Instruction *LaterInst);
980 bool isNonTargetIntrinsicMatch(
const IntrinsicInst *Earlier,
981 const IntrinsicInst *Later) {
982 auto IsSubmask = [](
const Value *Mask0,
const Value *Mask1) {
992 if (Vec0->getType() != Vec1->getType())
994 for (
int i = 0, e = Vec0->getNumOperands(); i != e; ++i) {
995 Constant *Elem0 = Vec0->getOperand(i);
996 Constant *Elem1 = Vec1->getOperand(i);
998 if (Int0 && Int0->isZero())
1011 auto PtrOp = [](
const IntrinsicInst *
II) {
1012 if (
II->getIntrinsicID() == Intrinsic::masked_load)
1013 return II->getOperand(0);
1014 if (
II->getIntrinsicID() == Intrinsic::masked_store)
1015 return II->getOperand(1);
1018 auto MaskOp = [](
const IntrinsicInst *
II) {
1019 if (
II->getIntrinsicID() == Intrinsic::masked_load)
1020 return II->getOperand(2);
1021 if (
II->getIntrinsicID() == Intrinsic::masked_store)
1022 return II->getOperand(3);
1025 auto ThruOp = [](
const IntrinsicInst *
II) {
1026 if (
II->getIntrinsicID() == Intrinsic::masked_load)
1027 return II->getOperand(3);
1031 if (PtrOp(Earlier) != PtrOp(Later))
1038 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_load) {
1044 if (MaskOp(Earlier) == MaskOp(Later) && ThruOp(Earlier) == ThruOp(Later))
1048 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
1050 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_load) {
1055 if (!IsSubmask(MaskOp(Later), MaskOp(Earlier)))
1059 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_store) {
1063 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
1065 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_store) {
1070 return IsSubmask(MaskOp(Earlier), MaskOp(Later));
1075 void removeMSSA(Instruction &Inst) {
1079 MSSA->verifyMemorySSA();
1086 MSSAUpdater->removeMemoryAccess(&Inst,
true);
1108bool EarlyCSE::isSameMemGeneration(
unsigned EarlierGeneration,
1109 unsigned LaterGeneration,
1113 if (EarlierGeneration == LaterGeneration)
1137 MemoryAccess *LaterDef;
1142 LaterDef = LaterMA->getDefiningAccess();
1144 return MSSA->
dominates(LaterDef, EarlierMA);
1147bool EarlyCSE::isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt) {
1151 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
1159 MemoryLocation MemLoc = *MemLocOpt;
1160 if (!AvailableInvariants.count(MemLoc))
1165 return AvailableInvariants.lookup(MemLoc) <= GenAt;
1168bool EarlyCSE::handleBranchCondition(Instruction *CondInst,
1169 const BranchInst *BI,
const BasicBlock *BB,
1170 const BasicBlock *Pred) {
1179 if (Opcode == Instruction::And &&
1182 else if (Opcode == Instruction::Or &&
1190 unsigned PropagateOpcode =
1191 (BI->
getSuccessor(0) == BB) ? Instruction::And : Instruction::Or;
1193 bool MadeChanges =
false;
1194 SmallVector<Instruction *, 4> WorkList;
1195 SmallPtrSet<Instruction *, 4> Visited;
1197 while (!WorkList.
empty()) {
1198 Instruction *Curr = WorkList.pop_back_val();
1200 AvailableValues.insert(Curr, TorF);
1201 LLVM_DEBUG(dbgs() <<
"EarlyCSE CVP: Add conditional value for '"
1202 << Curr->getName() <<
"' as " << *TorF <<
" in "
1203 << BB->getName() <<
"\n");
1204 if (!DebugCounter::shouldExecute(CSECounter)) {
1205 LLVM_DEBUG(dbgs() <<
"Skipping due to debug counter\n");
1208 if (unsigned Count = replaceDominatedUsesWith(Curr, TorF, DT,
1209 BasicBlockEdge(Pred, BB))) {
1216 if (MatchBinOp(Curr, PropagateOpcode,
LHS,
RHS))
1219 if (SimpleValue::canHandle(OPI) && Visited.
insert(OPI).second)
1226Value *EarlyCSE::getMatchingValue(LoadValue &InVal, ParseMemoryInst &MemInst,
1227 unsigned CurrentGeneration) {
1228 if (InVal.DefInst ==
nullptr)
1230 if (InVal.MatchingId != MemInst.getMatchingId())
1233 if (MemInst.isVolatile() || !MemInst.isUnordered())
1236 if (MemInst.isLoad() && !InVal.IsAtomic && MemInst.isAtomic())
1242 bool MemInstMatching = !MemInst.isLoad();
1243 Instruction *Matching = MemInstMatching ? MemInst.get() : InVal.DefInst;
1250 ? getOrCreateResult(Matching,
Other->getType(),
false)
1252 if (MemInst.isStore() && InVal.DefInst != Result)
1256 bool MatchingNTI = isHandledNonTargetIntrinsic(Matching);
1257 bool OtherNTI = isHandledNonTargetIntrinsic(
Other);
1258 if (OtherNTI != MatchingNTI)
1260 if (OtherNTI && MatchingNTI) {
1266 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1267 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1272 Result = getOrCreateResult(Matching,
Other->getType(),
true);
1286 I->andIRFlags(&From);
1300 assert(
Success &&
"Failed to intersect attributes in callsites that "
1301 "passed identical check");
1307bool EarlyCSE::overridingStores(
const ParseMemoryInst &Earlier,
1308 const ParseMemoryInst &Later) {
1311 assert(Earlier.isUnordered() && !Earlier.isVolatile() &&
1312 "Violated invariant");
1313 if (Earlier.getPointerOperand() != Later.getPointerOperand())
1315 if (!Earlier.getValueType() || !Later.getValueType() ||
1316 Earlier.getValueType() != Later.getValueType())
1318 if (Earlier.getMatchingId() != Later.getMatchingId())
1325 if (!Earlier.isUnordered() || !Later.isUnordered())
1329 bool ENTI = isHandledNonTargetIntrinsic(Earlier.get());
1330 bool LNTI = isHandledNonTargetIntrinsic(Later.get());
1338 return ENTI == LNTI;
1352 ++CurrentGeneration;
1364 if (CondInst && SimpleValue::canHandle(CondInst))
1365 Changed |= handleBranchCondition(CondInst, BI, BB, Pred);
1401 if (CondI && SimpleValue::canHandle(CondI)) {
1406 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping assumption: " << Inst <<
'\n');
1413 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping noalias intrinsic: " << Inst
1420 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping sideeffect: " << Inst <<
'\n');
1426 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping pseudoprobe: " << Inst <<
'\n');
1447 MemoryLocation MemLoc =
1450 if (!AvailableInvariants.count(MemLoc))
1451 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1458 if (SimpleValue::canHandle(CondI)) {
1460 if (
auto *KnownCond = AvailableValues.lookup(CondI)) {
1465 <<
"EarlyCSE removing guard: " << Inst <<
'\n');
1484 LastStore =
nullptr;
1491 LLVM_DEBUG(
dbgs() <<
"EarlyCSE Simplify: " << Inst <<
" to: " << *V
1496 bool Killed =
false;
1518 LastStore =
nullptr;
1521 if (SimpleValue::canHandle(&Inst)) {
1524 "Unexpected ebStrict from SimpleValue::canHandle()");
1525 assert((!CI->getRoundingMode() ||
1526 CI->getRoundingMode() != RoundingMode::Dynamic) &&
1527 "Unexpected dynamic rounding from SimpleValue::canHandle()");
1530 if (
Value *V = AvailableValues.lookup(&Inst)) {
1548 AvailableValues.insert(&Inst, &Inst);
1552 ParseMemoryInst MemInst(&Inst,
TTI);
1554 if (MemInst.isValid() && MemInst.isLoad()) {
1557 if (MemInst.isVolatile() || !MemInst.isUnordered()) {
1558 LastStore =
nullptr;
1559 ++CurrentGeneration;
1562 if (MemInst.isInvariantLoad()) {
1569 if (!AvailableInvariants.count(MemLoc))
1570 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1580 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1583 <<
" to: " << *InVal.DefInst <<
'\n');
1602 AvailableLoads.insert(MemInst.getPointerOperand(),
1603 LoadValue(&Inst, CurrentGeneration,
1604 MemInst.getMatchingId(),
1607 LastStore =
nullptr;
1617 !(MemInst.isValid() && !MemInst.mayReadFromMemory()))
1618 LastStore =
nullptr;
1624 if (CallValue::canHandle(&Inst) &&
1625 (!MemInst.isValid() || !MemInst.isStore()) && !
isa<MemSetInst>(&Inst)) {
1628 std::pair<Instruction *, unsigned> InVal = AvailableCalls.lookup(&Inst);
1629 if (InVal.first !=
nullptr &&
1630 isSameMemGeneration(InVal.second, CurrentGeneration, InVal.first,
1634 <<
" to: " << *InVal.first <<
'\n');
1653 ++CurrentGeneration;
1656 AvailableCalls.insert(&Inst, std::make_pair(&Inst, CurrentGeneration));
1661 if (GEPValue::canHandle(&Inst)) {
1664 GEPValue GEPVal(
GEP,
GEP->accumulateConstantOffset(SQ.
DL,
Offset)
1667 if (
Value *V = AvailableGEPs.lookup(GEPVal)) {
1668 LLVM_DEBUG(
dbgs() <<
"EarlyCSE CSE GEP: " << Inst <<
" to: " << *V
1681 AvailableGEPs.insert(GEPVal, &Inst);
1691 if (FI->getOrdering() == AtomicOrdering::Release) {
1701 if (MemInst.isValid() && MemInst.isStore()) {
1702 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1703 if (InVal.DefInst &&
1706 LLVM_DEBUG(
dbgs() <<
"EarlyCSE DSE (writeback): " << Inst <<
'\n');
1726 ++CurrentGeneration;
1728 if (MemInst.isValid() && MemInst.isStore()) {
1732 if (overridingStores(ParseMemoryInst(LastStore,
TTI), MemInst)) {
1734 <<
" due to: " << Inst <<
'\n');
1739 removeMSSA(*LastStore);
1743 LastStore =
nullptr;
1754 AvailableLoads.insert(MemInst.getPointerOperand(),
1755 LoadValue(&Inst, CurrentGeneration,
1756 MemInst.getMatchingId(),
1767 if (MemInst.isUnordered() && !MemInst.isVolatile())
1770 LastStore =
nullptr;
1778bool EarlyCSE::run() {
1784 std::deque<StackNode *> nodesToProcess;
1789 nodesToProcess.push_back(
new StackNode(
1790 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1791 AvailableGEPs, CurrentGeneration, DT.
getRootNode(),
1794 assert(!CurrentGeneration &&
"Create a new EarlyCSE instance to rerun it.");
1797 while (!nodesToProcess.empty()) {
1800 StackNode *NodeToProcess = nodesToProcess.back();
1811 }
else if (NodeToProcess->
childIter() != NodeToProcess->
end()) {
1814 nodesToProcess.push_back(
new StackNode(
1815 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1821 delete NodeToProcess;
1822 nodesToProcess.pop_back();
1838 EarlyCSE
CSE(
F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1853 OS, MapClassName2PassName);
1869template<
bool UseMemorySSA>
1882 if (skipFunction(
F))
1885 auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
1886 auto &
TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
1887 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
1888 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
1890 UseMemorySSA ? &getAnalysis<MemorySSAWrapperPass>().getMSSA() :
nullptr;
1892 EarlyCSE
CSE(
F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1897 void getAnalysisUsage(AnalysisUsage &AU)
const override {
1918char EarlyCSELegacyPass::ID = 0;
1928using EarlyCSEMemSSALegacyPass =
1929 EarlyCSELegacyCommonPass<
true>;
1932char EarlyCSEMemSSALegacyPass::
ID = 0;
1936 return new EarlyCSEMemSSALegacyPass();
1942 "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...
static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE)
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
This file defines DenseMapInfo traits for DenseMap.
static cl::opt< bool > EarlyCSEDebugHash("earlycse-debug-hash", cl::init(false), cl::Hidden, cl::desc("Perform extra assertion checking to verify that SimpleValue's hash " "function is well-behaved w.r.t. its isEqual predicate"))
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)
static cl::opt< unsigned > EarlyCSEMssaOptCap("earlycse-mssa-optimization-cap", cl::init(500), cl::Hidden, cl::desc("Enable imprecision in EarlyCSE in pathological cases, in exchange " "for faster compile. Caps the MemorySSA clobbering calls."))
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 LoadInst *LI, 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_>.
static Type * getValueType(Value *V)
Returns the type of the given value/instruction V.
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")
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
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 if the block is well formed or null if the block is not well forme...
bool isConditional() const
BasicBlock * getSuccessor(unsigned i) const
Value * getCondition() const
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...
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
LLVM_ABI unsigned getIndexTypeSizeInBits(Type *Ty) const
The size in bits of the index used in GEP calculation for this type.
static bool shouldExecute(unsigned CounterName)
typename SmallVector< DomTreeNodeBase *, 4 >::const_iterator const_iterator
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)
StringRef - 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.
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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ 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.
bool match(Val *V, const Pattern &P)
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
IntrinsicID_match m_Intrinsic()
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
class_match< CmpInst > m_Cmp()
Matches any compare instruction and ignore it.
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
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.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
@ ebStrict
This corresponds to "fpexcept.strict".
@ Assume
Do not drop type tests (default).
NodeAddr< NodeBase * > Node
Context & getContext() const
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
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.
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.
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.
BumpPtrAllocatorImpl BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
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.
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 CallValue getTombstoneKey()
static bool isEqual(CallValue LHS, CallValue RHS)
static CallValue getEmptyKey()
static bool isEqual(const GEPValue &LHS, const GEPValue &RHS)
static unsigned getHashValue(const GEPValue &Val)
static GEPValue getTombstoneKey()
static GEPValue getEmptyKey()
static SimpleValue getEmptyKey()
static unsigned getHashValue(SimpleValue Val)
static SimpleValue getTombstoneKey()
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)
A CRTP mix-in to automatically provide informational APIs needed for passes.