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());
278 if (ScalarOptions::Global.earlycse_debug_hash)
287 if (LHSI->
getOpcode() != RHSI->getOpcode())
294 CI && CI->isConvergent() && LHSI->
getParent() != RHSI->getParent())
302 if (!LHSBinOp->isCommutative())
306 "same opcode, but different instruction type?");
310 return LHSBinOp->getOperand(0) == RHSBinOp->
getOperand(1) &&
311 LHSBinOp->getOperand(1) == RHSBinOp->
getOperand(0);
315 "same opcode, but different instruction type?");
318 return LHSCmp->getOperand(0) == RHSCmp->
getOperand(1) &&
319 LHSCmp->getOperand(1) == RHSCmp->
getOperand(0) &&
320 LHSCmp->getSwappedPredicate() == RHSCmp->
getPredicate();
325 if (LII && RII && LII->getIntrinsicID() == RII->getIntrinsicID() &&
326 LII->isCommutative() && LII->arg_size() >= 2) {
327 return LII->getArgOperand(0) == RII->getArgOperand(1) &&
328 LII->getArgOperand(1) == RII->getArgOperand(0) &&
329 std::equal(LII->arg_begin() + 2, LII->arg_end(),
330 RII->arg_begin() + 2, RII->arg_end()) &&
331 LII->hasSameSpecialState(RII,
false,
338 return GCR1->getOperand(0) == GCR2->getOperand(0) &&
339 GCR1->getBasePtr() == GCR2->getBasePtr() &&
340 GCR1->getDerivedPtr() == GCR2->getDerivedPtr();
343 Value *CondL, *CondR, *LHSA, *RHSA, *LHSB, *RHSB;
347 if (CondL == CondR && LHSA == RHSA && LHSB == RHSB)
358 if (LHSA == RHSB && LHSB == RHSA) {
390 CallValue(Instruction *
I) : Inst(
I) {
391 assert(canHandle(
I) &&
"Inst can't be handled!");
394 static bool canHandle(Instruction *Inst) {
414 static bool isEqual(CallValue LHS, CallValue RHS);
445 std::optional<int64_t> ConstantOffset;
447 GEPValue(Instruction *
I) : Inst(
I) {
448 assert(canHandle(
I) &&
"Inst can't be handled!");
451 GEPValue(Instruction *
I, std::optional<int64_t> ConstantOffset)
452 : Inst(
I), ConstantOffset(ConstantOffset) {
453 assert(canHandle(
I) &&
"Inst can't be handled!");
456 static bool canHandle(Instruction *Inst) {
465 static bool isEqual(
const GEPValue &LHS,
const GEPValue &RHS);
470 if (Val.ConstantOffset.has_value())
472 Val.ConstantOffset.value());
480 if (LGEP->getPointerOperand() != RGEP->getPointerOperand())
482 if (
LHS.ConstantOffset.has_value() &&
RHS.ConstantOffset.has_value())
483 return LHS.ConstantOffset.value() ==
RHS.ConstantOffset.value();
484 return LGEP->isIdenticalToWhenDefined(RGEP);
502 const TargetLibraryInfo &TLI;
503 const TargetTransformInfo &TTI;
506 const SimplifyQuery SQ;
508 std::unique_ptr<MemorySSAUpdater> MSSAUpdater;
512 ScopedHashTableVal<SimpleValue, Value *>>;
514 ScopedHashTable<SimpleValue, Value *, DenseMapInfo<SimpleValue>,
523 ScopedHTType AvailableValues;
541 unsigned Generation = 0;
543 bool IsAtomic =
false;
546 LoadValue() =
default;
547 LoadValue(Instruction *Inst,
unsigned Generation,
unsigned MatchingId,
548 bool IsAtomic,
bool IsLoad)
549 : DefInst(Inst), Generation(Generation), MatchingId(MatchingId),
550 IsAtomic(IsAtomic), IsLoad(IsLoad) {}
553 using LoadMapAllocator =
555 ScopedHashTableVal<Value *, LoadValue>>;
557 ScopedHashTable<Value *, LoadValue, DenseMapInfo<Value *>,
560 LoadHTType AvailableLoads;
565 using InvariantMapAllocator =
567 ScopedHashTableVal<MemoryLocation, unsigned>>;
568 using InvariantHTType =
569 ScopedHashTable<MemoryLocation, unsigned, DenseMapInfo<MemoryLocation>,
570 InvariantMapAllocator>;
571 InvariantHTType AvailableInvariants;
578 ScopedHashTable<CallValue, std::pair<Instruction *, unsigned>>;
579 CallHTType AvailableCalls;
581 using GEPMapAllocatorTy =
583 ScopedHashTableVal<GEPValue, Value *>>;
584 using GEPHTType = ScopedHashTable<GEPValue, Value *, DenseMapInfo<GEPValue>,
586 GEPHTType AvailableGEPs;
589 unsigned CurrentGeneration = 0;
592 EarlyCSE(
const DataLayout &
DL,
const TargetLibraryInfo &TLI,
593 const TargetTransformInfo &TTI, DominatorTree &DT,
595 : TLI(TLI), TTI(TTI), DT(DT), AC(AC), SQ(
DL, &TLI, &DT, &AC), MSSA(MSSA),
596 MSSAUpdater(std::make_unique<MemorySSAUpdater>(MSSA)) {}
601 unsigned ClobberCounter = 0;
607 NodeScope(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
608 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
609 GEPHTType &AvailableGEPs)
610 : Scope(AvailableValues), LoadScope(AvailableLoads),
611 InvariantScope(AvailableInvariants), CallScope(AvailableCalls),
612 GEPScope(AvailableGEPs) {}
613 NodeScope(
const NodeScope &) =
delete;
614 NodeScope &operator=(
const NodeScope &) =
delete;
630 StackNode(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
631 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
632 GEPHTType &AvailableGEPs,
unsigned cg,
DomTreeNode *n,
633 DomTreeNode::const_iterator child,
634 DomTreeNode::const_iterator end)
635 : CurrentGeneration(cg), ChildGeneration(cg), Node(n), ChildIter(child),
637 Scopes(AvailableValues, AvailableLoads, AvailableInvariants,
638 AvailableCalls, AvailableGEPs) {}
639 StackNode(
const StackNode &) =
delete;
640 StackNode &operator=(
const StackNode &) =
delete;
643 unsigned currentGeneration()
const {
return CurrentGeneration; }
644 unsigned childGeneration()
const {
return ChildGeneration; }
647 DomTreeNode::const_iterator childIter()
const {
return ChildIter; }
655 DomTreeNode::const_iterator
end()
const {
return EndIter; }
656 bool isProcessed()
const {
return Processed; }
657 void process() { Processed =
true; }
660 unsigned CurrentGeneration;
661 unsigned ChildGeneration;
663 DomTreeNode::const_iterator ChildIter;
664 DomTreeNode::const_iterator EndIter;
666 bool Processed =
false;
671 class ParseMemoryInst {
673 ParseMemoryInst(Instruction *Inst,
const TargetTransformInfo &
TTI)
676 IntrID =
II->getIntrinsicID();
679 if (isHandledNonTargetIntrinsic(IntrID)) {
681 case Intrinsic::masked_load:
682 Info.PtrVal = Inst->getOperand(0);
683 Info.MatchingId = Intrinsic::masked_load;
685 Info.WriteMem =
false;
686 Info.IsVolatile =
false;
688 case Intrinsic::masked_store:
689 Info.PtrVal = Inst->getOperand(1);
696 Info.MatchingId = Intrinsic::masked_load;
697 Info.ReadMem =
false;
698 Info.WriteMem =
true;
699 Info.IsVolatile =
false;
703 Info.PtrVal =
MI->getDest();
705 Info.ReadMem =
false;
706 Info.WriteMem =
true;
707 Info.IsVolatile =
MI->isVolatile();
723 return Info.WriteMem;
729 return Info.Ordering != AtomicOrdering::NotAtomic;
730 return Inst->isAtomic();
733 bool isUnordered()
const {
735 return Info.isUnordered();
738 return LI->isUnordered();
740 return SI->isUnordered();
743 return !Inst->isAtomic();
746 bool isVolatile()
const {
748 return Info.IsVolatile;
751 return LI->isVolatile();
753 return SI->isVolatile();
761 return LI->hasMetadata(LLVMContext::MD_invariant_load);
771 int getMatchingId()
const {
773 return Info.MatchingId;
785 return Inst->getAccessType();
788 bool mayReadFromMemory()
const {
791 return Inst->mayReadFromMemory();
794 bool mayWriteToMemory()
const {
796 return Info.WriteMem;
797 return Inst->mayWriteToMemory();
802 MemIntrinsicInfo Info;
810 case Intrinsic::masked_load:
811 case Intrinsic::masked_store:
816 static bool isHandledNonTargetIntrinsic(
const Value *V) {
818 return isHandledNonTargetIntrinsic(
II->getIntrinsicID());
824 bool handleBranchCondition(Instruction *CondInst,
const CondBrInst *BI,
825 const BasicBlock *BB,
const BasicBlock *Pred);
828 unsigned CurrentGeneration);
830 bool overridingStores(
const ParseMemoryInst &Earlier,
831 const ParseMemoryInst &Later);
833 Value *getOrCreateResult(Instruction *Inst,
Type *ExpectedType,
834 bool CanCreate)
const {
839 switch (
II->getIntrinsicID()) {
840 case Intrinsic::masked_load:
843 case Intrinsic::masked_store:
844 V =
II->getOperand(0);
847 return TTI.getOrCreateResultFromMemIntrinsic(
II, ExpectedType,
854 return V->getType() == ExpectedType ?
V :
nullptr;
859 bool isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt);
861 bool isSameMemGeneration(
unsigned EarlierGeneration,
unsigned LaterGeneration,
862 Instruction *EarlierInst, Instruction *LaterInst);
864 bool isNonTargetIntrinsicMatch(
const IntrinsicInst *Earlier,
865 const IntrinsicInst *Later) {
866 auto IsSubmask = [](
const Value *Mask0,
const Value *Mask1) {
876 if (Vec0->getType() != Vec1->getType())
878 for (
int i = 0, e = Vec0->getNumOperands(); i != e; ++i) {
879 Constant *Elem0 = Vec0->getOperand(i);
880 Constant *Elem1 = Vec1->getOperand(i);
882 if (Int0 && Int0->isZero())
895 auto PtrOp = [](
const IntrinsicInst *
II) {
896 if (
II->getIntrinsicID() == Intrinsic::masked_load)
897 return II->getOperand(0);
898 if (
II->getIntrinsicID() == Intrinsic::masked_store)
899 return II->getOperand(1);
902 auto MaskOp = [](
const IntrinsicInst *
II) {
903 if (
II->getIntrinsicID() == Intrinsic::masked_load)
904 return II->getOperand(1);
905 if (
II->getIntrinsicID() == Intrinsic::masked_store)
906 return II->getOperand(2);
909 auto ThruOp = [](
const IntrinsicInst *
II) {
910 if (
II->getIntrinsicID() == Intrinsic::masked_load)
911 return II->getOperand(2);
915 if (PtrOp(Earlier) != PtrOp(Later))
922 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_load) {
928 if (MaskOp(Earlier) == MaskOp(Later) && ThruOp(Earlier) == ThruOp(Later))
932 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
934 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_load) {
939 if (!IsSubmask(MaskOp(Later), MaskOp(Earlier)))
943 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_store) {
947 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
949 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_store) {
954 return IsSubmask(MaskOp(Earlier), MaskOp(Later));
959 void removeMSSA(Instruction &Inst) {
963 MSSA->verifyMemorySSA();
970 MSSAUpdater->removeMemoryAccess(&Inst,
true);
992bool EarlyCSE::isSameMemGeneration(
unsigned EarlierGeneration,
993 unsigned LaterGeneration,
997 if (EarlierGeneration == LaterGeneration)
1021 MemoryAccess *LaterDef;
1022 if (ClobberCounter < ScalarOptions::Global.earlycse_mssa_optimization_cap) {
1026 LaterDef = LaterMA->getDefiningAccess();
1028 return MSSA->
dominates(LaterDef, EarlierMA);
1031bool EarlyCSE::isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt) {
1035 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
1043 MemoryLocation MemLoc = *MemLocOpt;
1044 if (!AvailableInvariants.count(MemLoc))
1049 return AvailableInvariants.lookup(MemLoc) <= GenAt;
1052bool EarlyCSE::handleBranchCondition(Instruction *CondInst,
1053 const CondBrInst *BI,
const BasicBlock *BB,
1054 const BasicBlock *Pred) {
1062 if (Opcode == Instruction::And &&
1065 else if (Opcode == Instruction::Or &&
1073 unsigned PropagateOpcode =
1074 (BI->
getSuccessor(0) == BB) ? Instruction::And : Instruction::Or;
1076 bool MadeChanges =
false;
1077 SmallVector<Instruction *, 4> WorkList;
1078 SmallPtrSet<Instruction *, 4> Visited;
1080 while (!WorkList.
empty()) {
1081 Instruction *Curr = WorkList.pop_back_val();
1083 AvailableValues.insert(Curr, TorF);
1084 LLVM_DEBUG(dbgs() <<
"EarlyCSE CVP: Add conditional value for '"
1085 << Curr->getName() <<
"' as " << *TorF <<
" in "
1086 << BB->getName() <<
"\n");
1087 if (!DebugCounter::shouldExecute(CSECounter)) {
1088 LLVM_DEBUG(dbgs() <<
"Skipping due to debug counter\n");
1091 if (unsigned Count = replaceDominatedUsesWith(Curr, TorF, DT,
1092 BasicBlockEdge(Pred, BB))) {
1099 if (MatchBinOp(Curr, PropagateOpcode,
LHS,
RHS))
1102 if (SimpleValue::canHandle(OPI) && Visited.
insert(OPI).second)
1109Value *EarlyCSE::getMatchingValue(LoadValue &InVal, ParseMemoryInst &MemInst,
1110 unsigned CurrentGeneration) {
1111 if (InVal.DefInst ==
nullptr)
1114 if (!MemInst.isLoad() || MemInst.isVolatile() || !MemInst.isUnordered() ||
1115 MemInst.getMatchingId() != -1)
1117 if (MSI->isVolatile())
1120 if (!Val || !Val->isZero())
1122 auto Len = MSI->getLengthInBytes();
1125 Type *InstType = MemInst.getValueType();
1131 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1132 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1137 if (InVal.MatchingId != MemInst.getMatchingId())
1140 if (MemInst.isVolatile() || !MemInst.isUnordered())
1143 if (MemInst.isLoad() && !InVal.IsAtomic && MemInst.isAtomic())
1149 bool MemInstMatching = !MemInst.isLoad();
1150 Instruction *Matching = MemInstMatching ? MemInst.get() : InVal.DefInst;
1157 ? getOrCreateResult(Matching,
Other->getType(),
false)
1159 if (MemInst.isStore() && InVal.DefInst != Result)
1163 bool MatchingNTI = isHandledNonTargetIntrinsic(Matching);
1164 bool OtherNTI = isHandledNonTargetIntrinsic(
Other);
1165 if (OtherNTI != MatchingNTI)
1167 if (OtherNTI && MatchingNTI) {
1173 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1174 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1179 Result = getOrCreateResult(Matching,
Other->getType(),
true);
1193 I->andIRFlags(&From);
1207 assert(
Success &&
"Failed to intersect attributes in callsites that "
1208 "passed identical check");
1214bool EarlyCSE::overridingStores(
const ParseMemoryInst &Earlier,
1215 const ParseMemoryInst &Later) {
1218 assert(Earlier.isUnordered() && !Earlier.isVolatile() &&
1219 "Violated invariant");
1220 if (Earlier.getPointerOperand() != Later.getPointerOperand())
1222 if (!Earlier.getValueType() || !Later.getValueType() ||
1223 Earlier.getValueType() != Later.getValueType())
1225 if (Earlier.getMatchingId() != Later.getMatchingId())
1232 if (!Earlier.isUnordered() || !Later.isUnordered())
1236 bool ENTI = isHandledNonTargetIntrinsic(Earlier.get());
1237 bool LNTI = isHandledNonTargetIntrinsic(Later.get());
1245 return ENTI == LNTI;
1259 ++CurrentGeneration;
1270 if (CondInst && SimpleValue::canHandle(CondInst))
1271 Changed |= handleBranchCondition(CondInst, BI, BB, Pred);
1307 if (CondI && SimpleValue::canHandle(CondI)) {
1312 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping assumption: " << Inst <<
'\n');
1319 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping noalias intrinsic: " << Inst
1326 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping sideeffect: " << Inst <<
'\n');
1332 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping pseudoprobe: " << Inst <<
'\n');
1353 MemoryLocation MemLoc =
1356 if (!AvailableInvariants.count(MemLoc))
1357 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1364 if (SimpleValue::canHandle(CondI)) {
1366 if (
auto *KnownCond = AvailableValues.lookup(CondI)) {
1371 <<
"EarlyCSE removing guard: " << Inst <<
'\n');
1390 LastStore =
nullptr;
1397 LLVM_DEBUG(
dbgs() <<
"EarlyCSE Simplify: " << Inst <<
" to: " << *V
1402 bool Killed =
false;
1424 LastStore =
nullptr;
1427 if (SimpleValue::canHandle(&Inst)) {
1430 "Unexpected ebStrict from SimpleValue::canHandle()");
1431 assert((!CI->getRoundingMode() ||
1432 CI->getRoundingMode() != RoundingMode::Dynamic) &&
1433 "Unexpected dynamic rounding from SimpleValue::canHandle()");
1436 if (
Value *V = AvailableValues.lookup(&Inst)) {
1454 AvailableValues.insert(&Inst, &Inst);
1458 ParseMemoryInst MemInst(&Inst,
TTI);
1460 if (MemInst.isValid() && MemInst.isLoad()) {
1463 if (MemInst.isVolatile() || !MemInst.isUnordered()) {
1464 LastStore =
nullptr;
1465 ++CurrentGeneration;
1468 if (MemInst.isInvariantLoad()) {
1475 if (!AvailableInvariants.count(MemLoc))
1476 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1486 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1489 <<
" to: " << *InVal.DefInst <<
'\n');
1508 AvailableLoads.insert(MemInst.getPointerOperand(),
1509 LoadValue(&Inst, CurrentGeneration,
1510 MemInst.getMatchingId(),
1513 LastStore =
nullptr;
1523 !(MemInst.isValid() && !MemInst.mayReadFromMemory()))
1524 LastStore =
nullptr;
1530 if (CallValue::canHandle(&Inst) &&
1531 (!MemInst.isValid() || !MemInst.isStore()) && !
isa<MemSetInst>(&Inst)) {
1534 std::pair<Instruction *, unsigned> InVal = AvailableCalls.lookup(&Inst);
1535 if (InVal.first !=
nullptr &&
1536 isSameMemGeneration(InVal.second, CurrentGeneration, InVal.first,
1540 <<
" to: " << *InVal.first <<
'\n');
1559 ++CurrentGeneration;
1562 AvailableCalls.insert(&Inst, std::make_pair(&Inst, CurrentGeneration));
1567 if (GEPValue::canHandle(&Inst)) {
1570 GEPValue GEPVal(
GEP,
GEP->accumulateConstantOffset(SQ.
DL,
Offset)
1573 if (
Value *V = AvailableGEPs.lookup(GEPVal)) {
1574 LLVM_DEBUG(
dbgs() <<
"EarlyCSE CSE GEP: " << Inst <<
" to: " << *V
1587 AvailableGEPs.insert(GEPVal, &Inst);
1597 if (FI->getOrdering() == AtomicOrdering::Release) {
1607 if (MemInst.isValid() && MemInst.isStore()) {
1608 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1609 if (InVal.DefInst &&
1612 LLVM_DEBUG(
dbgs() <<
"EarlyCSE DSE (writeback): " << Inst <<
'\n');
1632 ++CurrentGeneration;
1634 if (MemInst.isValid() && MemInst.isStore()) {
1638 if (overridingStores(ParseMemoryInst(LastStore,
TTI), MemInst)) {
1640 <<
" due to: " << Inst <<
'\n');
1645 removeMSSA(*LastStore);
1649 LastStore =
nullptr;
1660 AvailableLoads.insert(MemInst.getPointerOperand(),
1661 LoadValue(&Inst, CurrentGeneration,
1662 MemInst.getMatchingId(),
1673 if (MemInst.isUnordered() && !MemInst.isVolatile())
1676 LastStore =
nullptr;
1684bool EarlyCSE::run() {
1690 std::deque<StackNode *> nodesToProcess;
1695 nodesToProcess.push_back(
new StackNode(
1696 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1697 AvailableGEPs, CurrentGeneration, DT.
getRootNode(),
1700 assert(!CurrentGeneration &&
"Create a new EarlyCSE instance to rerun it.");
1703 while (!nodesToProcess.empty()) {
1706 StackNode *NodeToProcess = nodesToProcess.back();
1717 }
else if (NodeToProcess->
childIter() != NodeToProcess->
end()) {
1720 nodesToProcess.push_back(
new StackNode(
1721 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1727 delete NodeToProcess;
1728 nodesToProcess.pop_back();
1744 EarlyCSE
CSE(
F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1758 static_cast<PassInfoMixin<EarlyCSEPass> *
>(
this)->
printPipeline(
1759 OS, MapClassName2PassName);
1775template<
bool UseMemorySSA>
1788 if (skipFunction(
F))
1791 auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
1792 auto &
TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
1793 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
1794 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
1796 UseMemorySSA ? &getAnalysis<MemorySSAWrapperPass>().getMSSA() :
nullptr;
1798 EarlyCSE
CSE(
F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1803 void getAnalysisUsage(AnalysisUsage &AU)
const override {
1824char EarlyCSELegacyPass::ID = 0;
1834using EarlyCSEMemSSALegacyPass =
1835 EarlyCSELegacyCommonPass<
true>;
1838char EarlyCSEMemSSALegacyPass::ID = 0;
1842 return new EarlyCSEMemSSALegacyPass();
1848 "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.
static LLVM_ABI MemoryLocation get(const LoadInst *LI)
Return a location with information about the memory reference by the given instruction.
static LLVM_ABI std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
static LLVM_ABI MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx, const TargetLibraryInfo *TLI)
Return a location representing a particular argument of a call.
An analysis that produces MemorySSA for a function.
MemoryAccess * getClobberingMemoryAccess(const Instruction *I, BatchAAResults &AA)
Given a memory Mod/Ref/ModRef'ing instruction, calling this will give you the nearest dominating Memo...
Legacy analysis pass which computes MemorySSA.
LLVM_ABI bool dominates(const MemoryAccess *A, const MemoryAccess *B) const
Given two memory accesses in potentially different blocks, determine whether MemoryAccess A dominates...
LLVM_ABI MemorySSAWalker * getWalker()
MemoryUseOrDef * getMemoryAccess(const Instruction *I) const
Given a memory Mod/Ref'ing instruction, get the MemorySSA access associated with it.
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
ScopedHashTableScope< SimpleValue, Value *, DenseMapInfo< SimpleValue >, AllocatorTy > ScopeTy
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
Analysis pass providing the TargetTransformInfo.
Analysis pass providing the TargetLibraryInfo.
Value * getOperand(unsigned i) const
iterator_range< value_op_iterator > operand_values()
LLVM Value Representation.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
constexpr ScalarTy getFixedValue() const
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BasicBlock
Various leaf nodes.
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
auto m_Cmp()
Matches any compare instruction and ignore it.
bool match(Val *V, const Pattern &P)
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
auto m_Value()
Match an arbitrary value and ignore it.
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
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)