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();
104 static bool canHandle(Instruction *Inst) {
109 if (Function *
F = CI->getCalledFunction()) {
110 switch (
F->getIntrinsicID()) {
111 case Intrinsic::experimental_constrained_fadd:
112 case Intrinsic::experimental_constrained_fsub:
113 case Intrinsic::experimental_constrained_fmul:
114 case Intrinsic::experimental_constrained_fdiv:
115 case Intrinsic::experimental_constrained_frem:
116 case Intrinsic::experimental_constrained_fptosi:
117 case Intrinsic::experimental_constrained_sitofp:
118 case Intrinsic::experimental_constrained_fptoui:
119 case Intrinsic::experimental_constrained_uitofp:
120 case Intrinsic::experimental_constrained_fcmp:
121 case Intrinsic::experimental_constrained_fcmps: {
123 if (CFP->getExceptionBehavior() &&
128 if (CFP->getRoundingMode() &&
129 CFP->getRoundingMode() == RoundingMode::Dynamic)
135 return CI->doesNotAccessMemory() &&
143 !CI->getFunction()->isPresplitCoroutine();
162 static bool isEqual(SimpleValue LHS, SimpleValue RHS);
230 if (BinOp->isCommutative() && BinOp->getOperand(0) > BinOp->getOperand(1))
245 if (std::tie(
LHS, Pred) > std::tie(
RHS, SwappedPred)) {
287 return hash_combine(CI->getOpcode(), CI->getType(), CI->getOperand(0));
290 return hash_combine(FI->getOpcode(), FI->getOperand(0));
293 return hash_combine(EVI->getOpcode(), EVI->getOperand(0),
297 return hash_combine(IVI->getOpcode(), IVI->getOperand(0),
303 "Invalid/unknown instruction");
307 if (
II &&
II->isCommutative() &&
II->arg_size() >= 2) {
320 return hash_combine(GCR->getOpcode(), GCR->getOperand(0),
321 GCR->getBasePtr(), GCR->getDerivedPtr());
348 if (
LHS.isSentinel() ||
RHS.isSentinel())
351 if (LHSI->
getOpcode() != RHSI->getOpcode())
358 CI && CI->isConvergent() && LHSI->
getParent() != RHSI->getParent())
366 if (!LHSBinOp->isCommutative())
370 "same opcode, but different instruction type?");
374 return LHSBinOp->getOperand(0) == RHSBinOp->
getOperand(1) &&
375 LHSBinOp->getOperand(1) == RHSBinOp->
getOperand(0);
379 "same opcode, but different instruction type?");
382 return LHSCmp->getOperand(0) == RHSCmp->
getOperand(1) &&
383 LHSCmp->getOperand(1) == RHSCmp->
getOperand(0) &&
384 LHSCmp->getSwappedPredicate() == RHSCmp->
getPredicate();
389 if (LII && RII && LII->getIntrinsicID() == RII->getIntrinsicID() &&
390 LII->isCommutative() && LII->arg_size() >= 2) {
391 return LII->getArgOperand(0) == RII->getArgOperand(1) &&
392 LII->getArgOperand(1) == RII->getArgOperand(0) &&
393 std::equal(LII->arg_begin() + 2, LII->arg_end(),
394 RII->arg_begin() + 2, RII->arg_end()) &&
395 LII->hasSameSpecialState(RII,
false,
402 return GCR1->getOperand(0) == GCR2->getOperand(0) &&
403 GCR1->getBasePtr() == GCR2->getBasePtr() &&
404 GCR1->getDerivedPtr() == GCR2->getDerivedPtr();
410 Value *CondL, *CondR, *LHSA, *RHSA, *LHSB, *RHSB;
417 return ((LHSA == RHSA && LHSB == RHSB) ||
418 (LHSA == RHSB && LHSB == RHSA));
421 if (CondL == CondR && LHSA == RHSA && LHSB == RHSB)
443 if (LHSA == RHSB && LHSB == RHSA) {
476 CallValue(Instruction *
I) : Inst(
I) {
481 return Inst == DenseMapInfo<Instruction *>::getEmptyKey();
484 static bool canHandle(Instruction *Inst) {
508 static bool isEqual(CallValue LHS, CallValue RHS);
519 if (
LHS.isSentinel() ||
RHS.isSentinel())
520 return LHS.Inst ==
RHS.Inst;
542 std::optional<int64_t> ConstantOffset;
544 GEPValue(Instruction *
I) : Inst(
I) {
548 GEPValue(Instruction *
I, std::optional<int64_t> ConstantOffset)
549 : Inst(
I), ConstantOffset(ConstantOffset) {
554 return Inst == DenseMapInfo<Instruction *>::getEmptyKey();
557 static bool canHandle(Instruction *Inst) {
570 static bool isEqual(
const GEPValue &LHS,
const GEPValue &RHS);
575 if (Val.ConstantOffset.has_value())
577 Val.ConstantOffset.value());
583 if (
LHS.isSentinel() ||
RHS.isSentinel())
584 return LHS.Inst ==
RHS.Inst;
587 if (LGEP->getPointerOperand() != RGEP->getPointerOperand())
589 if (
LHS.ConstantOffset.has_value() &&
RHS.ConstantOffset.has_value())
590 return LHS.ConstantOffset.value() ==
RHS.ConstantOffset.value();
591 return LGEP->isIdenticalToWhenDefined(RGEP);
609 const TargetLibraryInfo &TLI;
610 const TargetTransformInfo &TTI;
613 const SimplifyQuery SQ;
615 std::unique_ptr<MemorySSAUpdater> MSSAUpdater;
619 ScopedHashTableVal<SimpleValue, Value *>>;
621 ScopedHashTable<SimpleValue, Value *, DenseMapInfo<SimpleValue>,
630 ScopedHTType AvailableValues;
648 unsigned Generation = 0;
650 bool IsAtomic =
false;
653 LoadValue() =
default;
654 LoadValue(Instruction *Inst,
unsigned Generation,
unsigned MatchingId,
655 bool IsAtomic,
bool IsLoad)
656 : DefInst(Inst), Generation(Generation), MatchingId(MatchingId),
657 IsAtomic(IsAtomic), IsLoad(IsLoad) {}
660 using LoadMapAllocator =
662 ScopedHashTableVal<Value *, LoadValue>>;
664 ScopedHashTable<Value *, LoadValue, DenseMapInfo<Value *>,
667 LoadHTType AvailableLoads;
672 using InvariantMapAllocator =
674 ScopedHashTableVal<MemoryLocation, unsigned>>;
675 using InvariantHTType =
676 ScopedHashTable<MemoryLocation, unsigned, DenseMapInfo<MemoryLocation>,
677 InvariantMapAllocator>;
678 InvariantHTType AvailableInvariants;
685 ScopedHashTable<CallValue, std::pair<Instruction *, unsigned>>;
686 CallHTType AvailableCalls;
688 using GEPMapAllocatorTy =
690 ScopedHashTableVal<GEPValue, Value *>>;
691 using GEPHTType = ScopedHashTable<GEPValue, Value *, DenseMapInfo<GEPValue>,
693 GEPHTType AvailableGEPs;
696 unsigned CurrentGeneration = 0;
699 EarlyCSE(
const DataLayout &
DL,
const TargetLibraryInfo &TLI,
700 const TargetTransformInfo &TTI, DominatorTree &DT,
702 : TLI(TLI), TTI(TTI), DT(DT), AC(AC), SQ(
DL, &TLI, &DT, &AC), MSSA(MSSA),
703 MSSAUpdater(std::make_unique<MemorySSAUpdater>(MSSA)) {}
708 unsigned ClobberCounter = 0;
714 NodeScope(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
715 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
716 GEPHTType &AvailableGEPs)
717 : Scope(AvailableValues), LoadScope(AvailableLoads),
718 InvariantScope(AvailableInvariants), CallScope(AvailableCalls),
719 GEPScope(AvailableGEPs) {}
720 NodeScope(
const NodeScope &) =
delete;
721 NodeScope &operator=(
const NodeScope &) =
delete;
737 StackNode(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
738 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
739 GEPHTType &AvailableGEPs,
unsigned cg,
DomTreeNode *n,
740 DomTreeNode::const_iterator child,
741 DomTreeNode::const_iterator end)
742 : CurrentGeneration(cg), ChildGeneration(cg), Node(n), ChildIter(child),
744 Scopes(AvailableValues, AvailableLoads, AvailableInvariants,
745 AvailableCalls, AvailableGEPs) {}
746 StackNode(
const StackNode &) =
delete;
747 StackNode &operator=(
const StackNode &) =
delete;
750 unsigned currentGeneration()
const {
return CurrentGeneration; }
751 unsigned childGeneration()
const {
return ChildGeneration; }
754 DomTreeNode::const_iterator childIter()
const {
return ChildIter; }
762 DomTreeNode::const_iterator
end()
const {
return EndIter; }
763 bool isProcessed()
const {
return Processed; }
764 void process() { Processed =
true; }
767 unsigned CurrentGeneration;
768 unsigned ChildGeneration;
770 DomTreeNode::const_iterator ChildIter;
771 DomTreeNode::const_iterator EndIter;
773 bool Processed =
false;
778 class ParseMemoryInst {
780 ParseMemoryInst(Instruction *Inst,
const TargetTransformInfo &
TTI)
783 IntrID =
II->getIntrinsicID();
786 if (isHandledNonTargetIntrinsic(IntrID)) {
788 case Intrinsic::masked_load:
789 Info.PtrVal = Inst->getOperand(0);
790 Info.MatchingId = Intrinsic::masked_load;
792 Info.WriteMem =
false;
793 Info.IsVolatile =
false;
795 case Intrinsic::masked_store:
796 Info.PtrVal = Inst->getOperand(1);
803 Info.MatchingId = Intrinsic::masked_load;
804 Info.ReadMem =
false;
805 Info.WriteMem =
true;
806 Info.IsVolatile =
false;
810 Info.PtrVal =
MI->getDest();
812 Info.ReadMem =
false;
813 Info.WriteMem =
true;
814 Info.IsVolatile =
MI->isVolatile();
830 return Info.WriteMem;
834 bool isAtomic()
const {
836 return Info.Ordering != AtomicOrdering::NotAtomic;
837 return Inst->isAtomic();
840 bool isUnordered()
const {
842 return Info.isUnordered();
845 return LI->isUnordered();
847 return SI->isUnordered();
850 return !Inst->isAtomic();
853 bool isVolatile()
const {
855 return Info.IsVolatile;
858 return LI->isVolatile();
860 return SI->isVolatile();
868 return LI->hasMetadata(LLVMContext::MD_invariant_load);
878 int getMatchingId()
const {
880 return Info.MatchingId;
892 return Inst->getAccessType();
895 bool mayReadFromMemory()
const {
898 return Inst->mayReadFromMemory();
901 bool mayWriteToMemory()
const {
903 return Info.WriteMem;
904 return Inst->mayWriteToMemory();
909 MemIntrinsicInfo Info;
917 case Intrinsic::masked_load:
918 case Intrinsic::masked_store:
923 static bool isHandledNonTargetIntrinsic(
const Value *V) {
925 return isHandledNonTargetIntrinsic(
II->getIntrinsicID());
931 bool handleBranchCondition(Instruction *CondInst,
const CondBrInst *BI,
932 const BasicBlock *BB,
const BasicBlock *Pred);
935 unsigned CurrentGeneration);
937 bool overridingStores(
const ParseMemoryInst &Earlier,
938 const ParseMemoryInst &Later);
940 Value *getOrCreateResult(Instruction *Inst,
Type *ExpectedType,
941 bool CanCreate)
const {
946 switch (
II->getIntrinsicID()) {
947 case Intrinsic::masked_load:
950 case Intrinsic::masked_store:
951 V =
II->getOperand(0);
954 return TTI.getOrCreateResultFromMemIntrinsic(
II, ExpectedType,
961 return V->getType() == ExpectedType ?
V :
nullptr;
966 bool isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt);
968 bool isSameMemGeneration(
unsigned EarlierGeneration,
unsigned LaterGeneration,
969 Instruction *EarlierInst, Instruction *LaterInst);
971 bool isNonTargetIntrinsicMatch(
const IntrinsicInst *Earlier,
972 const IntrinsicInst *Later) {
973 auto IsSubmask = [](
const Value *Mask0,
const Value *Mask1) {
983 if (Vec0->getType() != Vec1->getType())
985 for (
int i = 0, e = Vec0->getNumOperands(); i != e; ++i) {
986 Constant *Elem0 = Vec0->getOperand(i);
987 Constant *Elem1 = Vec1->getOperand(i);
989 if (Int0 && Int0->isZero())
1002 auto PtrOp = [](
const IntrinsicInst *
II) {
1003 if (
II->getIntrinsicID() == Intrinsic::masked_load)
1004 return II->getOperand(0);
1005 if (
II->getIntrinsicID() == Intrinsic::masked_store)
1006 return II->getOperand(1);
1009 auto MaskOp = [](
const IntrinsicInst *
II) {
1010 if (
II->getIntrinsicID() == Intrinsic::masked_load)
1011 return II->getOperand(1);
1012 if (
II->getIntrinsicID() == Intrinsic::masked_store)
1013 return II->getOperand(2);
1016 auto ThruOp = [](
const IntrinsicInst *
II) {
1017 if (
II->getIntrinsicID() == Intrinsic::masked_load)
1018 return II->getOperand(2);
1022 if (PtrOp(Earlier) != PtrOp(Later))
1029 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_load) {
1035 if (MaskOp(Earlier) == MaskOp(Later) && ThruOp(Earlier) == ThruOp(Later))
1039 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
1041 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_load) {
1046 if (!IsSubmask(MaskOp(Later), MaskOp(Earlier)))
1050 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_store) {
1054 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
1056 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_store) {
1061 return IsSubmask(MaskOp(Earlier), MaskOp(Later));
1066 void removeMSSA(Instruction &Inst) {
1070 MSSA->verifyMemorySSA();
1077 MSSAUpdater->removeMemoryAccess(&Inst,
true);
1099bool EarlyCSE::isSameMemGeneration(
unsigned EarlierGeneration,
1100 unsigned LaterGeneration,
1104 if (EarlierGeneration == LaterGeneration)
1128 MemoryAccess *LaterDef;
1133 LaterDef = LaterMA->getDefiningAccess();
1135 return MSSA->
dominates(LaterDef, EarlierMA);
1138bool EarlyCSE::isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt) {
1142 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
1150 MemoryLocation MemLoc = *MemLocOpt;
1151 if (!AvailableInvariants.count(MemLoc))
1156 return AvailableInvariants.lookup(MemLoc) <= GenAt;
1159bool EarlyCSE::handleBranchCondition(Instruction *CondInst,
1160 const CondBrInst *BI,
const BasicBlock *BB,
1161 const BasicBlock *Pred) {
1169 if (Opcode == Instruction::And &&
1172 else if (Opcode == Instruction::Or &&
1180 unsigned PropagateOpcode =
1181 (BI->
getSuccessor(0) == BB) ? Instruction::And : Instruction::Or;
1183 bool MadeChanges =
false;
1184 SmallVector<Instruction *, 4> WorkList;
1185 SmallPtrSet<Instruction *, 4> Visited;
1187 while (!WorkList.
empty()) {
1188 Instruction *Curr = WorkList.pop_back_val();
1190 AvailableValues.insert(Curr, TorF);
1191 LLVM_DEBUG(dbgs() <<
"EarlyCSE CVP: Add conditional value for '"
1192 << Curr->getName() <<
"' as " << *TorF <<
" in "
1193 << BB->getName() <<
"\n");
1194 if (!DebugCounter::shouldExecute(CSECounter)) {
1195 LLVM_DEBUG(dbgs() <<
"Skipping due to debug counter\n");
1198 if (unsigned Count = replaceDominatedUsesWith(Curr, TorF, DT,
1199 BasicBlockEdge(Pred, BB))) {
1206 if (MatchBinOp(Curr, PropagateOpcode,
LHS,
RHS))
1209 if (SimpleValue::canHandle(OPI) && Visited.
insert(OPI).second)
1216Value *EarlyCSE::getMatchingValue(LoadValue &InVal, ParseMemoryInst &MemInst,
1217 unsigned CurrentGeneration) {
1218 if (InVal.DefInst ==
nullptr)
1221 if (!MemInst.isLoad() || MemInst.isVolatile() || !MemInst.isUnordered())
1223 if (MSI->isVolatile())
1226 if (!Val || !Val->isZero())
1228 auto Len = MSI->getLengthInBytes();
1231 Type *InstType = MemInst.getValueType();
1237 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1238 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1243 if (InVal.MatchingId != MemInst.getMatchingId())
1246 if (MemInst.isVolatile() || !MemInst.isUnordered())
1249 if (MemInst.isLoad() && !InVal.IsAtomic && MemInst.isAtomic())
1255 bool MemInstMatching = !MemInst.isLoad();
1256 Instruction *Matching = MemInstMatching ? MemInst.get() : InVal.DefInst;
1263 ? getOrCreateResult(Matching,
Other->getType(),
false)
1265 if (MemInst.isStore() && InVal.DefInst != Result)
1269 bool MatchingNTI = isHandledNonTargetIntrinsic(Matching);
1270 bool OtherNTI = isHandledNonTargetIntrinsic(
Other);
1271 if (OtherNTI != MatchingNTI)
1273 if (OtherNTI && MatchingNTI) {
1279 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1280 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1285 Result = getOrCreateResult(Matching,
Other->getType(),
true);
1299 I->andIRFlags(&From);
1313 assert(
Success &&
"Failed to intersect attributes in callsites that "
1314 "passed identical check");
1320bool EarlyCSE::overridingStores(
const ParseMemoryInst &Earlier,
1321 const ParseMemoryInst &Later) {
1324 assert(Earlier.isUnordered() && !Earlier.isVolatile() &&
1325 "Violated invariant");
1326 if (Earlier.getPointerOperand() != Later.getPointerOperand())
1328 if (!Earlier.getValueType() || !Later.getValueType() ||
1329 Earlier.getValueType() != Later.getValueType())
1331 if (Earlier.getMatchingId() != Later.getMatchingId())
1338 if (!Earlier.isUnordered() || !Later.isUnordered())
1342 bool ENTI = isHandledNonTargetIntrinsic(Earlier.get());
1343 bool LNTI = isHandledNonTargetIntrinsic(Later.get());
1351 return ENTI == LNTI;
1365 ++CurrentGeneration;
1376 if (CondInst && SimpleValue::canHandle(CondInst))
1377 Changed |= handleBranchCondition(CondInst, BI, BB, Pred);
1413 if (CondI && SimpleValue::canHandle(CondI)) {
1418 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping assumption: " << Inst <<
'\n');
1425 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping noalias intrinsic: " << Inst
1432 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping sideeffect: " << Inst <<
'\n');
1438 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping pseudoprobe: " << Inst <<
'\n');
1459 MemoryLocation MemLoc =
1462 if (!AvailableInvariants.count(MemLoc))
1463 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1470 if (SimpleValue::canHandle(CondI)) {
1472 if (
auto *KnownCond = AvailableValues.lookup(CondI)) {
1477 <<
"EarlyCSE removing guard: " << Inst <<
'\n');
1496 LastStore =
nullptr;
1503 LLVM_DEBUG(
dbgs() <<
"EarlyCSE Simplify: " << Inst <<
" to: " << *V
1508 bool Killed =
false;
1530 LastStore =
nullptr;
1533 if (SimpleValue::canHandle(&Inst)) {
1536 "Unexpected ebStrict from SimpleValue::canHandle()");
1537 assert((!CI->getRoundingMode() ||
1538 CI->getRoundingMode() != RoundingMode::Dynamic) &&
1539 "Unexpected dynamic rounding from SimpleValue::canHandle()");
1542 if (
Value *V = AvailableValues.lookup(&Inst)) {
1560 AvailableValues.insert(&Inst, &Inst);
1564 ParseMemoryInst MemInst(&Inst,
TTI);
1566 if (MemInst.isValid() && MemInst.isLoad()) {
1569 if (MemInst.isVolatile() || !MemInst.isUnordered()) {
1570 LastStore =
nullptr;
1571 ++CurrentGeneration;
1574 if (MemInst.isInvariantLoad()) {
1581 if (!AvailableInvariants.count(MemLoc))
1582 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1592 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1595 <<
" to: " << *InVal.DefInst <<
'\n');
1614 AvailableLoads.insert(MemInst.getPointerOperand(),
1615 LoadValue(&Inst, CurrentGeneration,
1616 MemInst.getMatchingId(),
1619 LastStore =
nullptr;
1629 !(MemInst.isValid() && !MemInst.mayReadFromMemory()))
1630 LastStore =
nullptr;
1636 if (CallValue::canHandle(&Inst) &&
1637 (!MemInst.isValid() || !MemInst.isStore()) && !
isa<MemSetInst>(&Inst)) {
1640 std::pair<Instruction *, unsigned> InVal = AvailableCalls.lookup(&Inst);
1641 if (InVal.first !=
nullptr &&
1642 isSameMemGeneration(InVal.second, CurrentGeneration, InVal.first,
1646 <<
" to: " << *InVal.first <<
'\n');
1665 ++CurrentGeneration;
1668 AvailableCalls.insert(&Inst, std::make_pair(&Inst, CurrentGeneration));
1673 if (GEPValue::canHandle(&Inst)) {
1676 GEPValue GEPVal(
GEP,
GEP->accumulateConstantOffset(SQ.
DL,
Offset)
1679 if (
Value *V = AvailableGEPs.lookup(GEPVal)) {
1680 LLVM_DEBUG(
dbgs() <<
"EarlyCSE CSE GEP: " << Inst <<
" to: " << *V
1693 AvailableGEPs.insert(GEPVal, &Inst);
1703 if (FI->getOrdering() == AtomicOrdering::Release) {
1713 if (MemInst.isValid() && MemInst.isStore()) {
1714 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1715 if (InVal.DefInst &&
1718 LLVM_DEBUG(
dbgs() <<
"EarlyCSE DSE (writeback): " << Inst <<
'\n');
1738 ++CurrentGeneration;
1740 if (MemInst.isValid() && MemInst.isStore()) {
1744 if (overridingStores(ParseMemoryInst(LastStore,
TTI), MemInst)) {
1746 <<
" due to: " << Inst <<
'\n');
1751 removeMSSA(*LastStore);
1755 LastStore =
nullptr;
1766 AvailableLoads.insert(MemInst.getPointerOperand(),
1767 LoadValue(&Inst, CurrentGeneration,
1768 MemInst.getMatchingId(),
1779 if (MemInst.isUnordered() && !MemInst.isVolatile())
1782 LastStore =
nullptr;
1790bool EarlyCSE::run() {
1796 std::deque<StackNode *> nodesToProcess;
1801 nodesToProcess.push_back(
new StackNode(
1802 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1803 AvailableGEPs, CurrentGeneration, DT.
getRootNode(),
1806 assert(!CurrentGeneration &&
"Create a new EarlyCSE instance to rerun it.");
1809 while (!nodesToProcess.empty()) {
1812 StackNode *NodeToProcess = nodesToProcess.back();
1823 }
else if (NodeToProcess->
childIter() != NodeToProcess->
end()) {
1826 nodesToProcess.push_back(
new StackNode(
1827 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1833 delete NodeToProcess;
1834 nodesToProcess.pop_back();
1850 EarlyCSE
CSE(
F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1865 OS, MapClassName2PassName);
1881template<
bool UseMemorySSA>
1894 if (skipFunction(
F))
1897 auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
1898 auto &
TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
1899 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
1900 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
1902 UseMemorySSA ? &getAnalysis<MemorySSAWrapperPass>().getMSSA() :
nullptr;
1904 EarlyCSE
CSE(
F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1909 void getAnalysisUsage(AnalysisUsage &AU)
const override {
1930char EarlyCSELegacyPass::ID = 0;
1940using EarlyCSEMemSSALegacyPass =
1941 EarlyCSELegacyCommonPass<
true>;
1944char EarlyCSEMemSSALegacyPass::
ID = 0;
1948 return new EarlyCSEMemSSALegacyPass();
1954 "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 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_>.
static Type * getValueType(Value *V, bool LookThroughCmp=false)
Returns the "element 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")
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.
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.
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.
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_Value()
Match an arbitrary value and ignore it.
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
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)
DXILDebugInfoMap run(Module &M)
@ ebStrict
This corresponds to "fpexcept.strict".
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.
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 CallValue getEmptyKey()
static bool isEqual(const GEPValue &LHS, const GEPValue &RHS)
static unsigned getHashValue(const GEPValue &Val)
static GEPValue getEmptyKey()
static SimpleValue getEmptyKey()
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)
A CRTP mix-in to automatically provide informational APIs needed for passes.