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"));
97 assert(canHandle(
I) &&
"Inst can't be handled!");
100 static bool canHandle(Instruction *Inst) {
105 if (Function *
F = CI->getCalledFunction()) {
106 switch (
F->getIntrinsicID()) {
107 case Intrinsic::experimental_constrained_fadd:
108 case Intrinsic::experimental_constrained_fsub:
109 case Intrinsic::experimental_constrained_fmul:
110 case Intrinsic::experimental_constrained_fdiv:
111 case Intrinsic::experimental_constrained_frem:
112 case Intrinsic::experimental_constrained_fptosi:
113 case Intrinsic::experimental_constrained_sitofp:
114 case Intrinsic::experimental_constrained_fptoui:
115 case Intrinsic::experimental_constrained_uitofp:
116 case Intrinsic::experimental_constrained_fcmp:
117 case Intrinsic::experimental_constrained_fcmps: {
119 if (CFP->getExceptionBehavior() &&
124 if (CFP->getRoundingMode() &&
125 CFP->getRoundingMode() == RoundingMode::Dynamic)
131 return CI->doesNotAccessMemory() &&
139 !CI->getFunction()->isPresplitCoroutine();
154 static bool isEqual(SimpleValue LHS, SimpleValue RHS);
222 if (BinOp->isCommutative() && BinOp->getOperand(0) > BinOp->getOperand(1))
237 if (std::tie(
LHS, Pred) > std::tie(
RHS, SwappedPred)) {
279 return hash_combine(CI->getOpcode(), CI->getType(), CI->getOperand(0));
282 return hash_combine(FI->getOpcode(), FI->getOperand(0));
285 return hash_combine(EVI->getOpcode(), EVI->getOperand(0),
289 return hash_combine(IVI->getOpcode(), IVI->getOperand(0),
295 "Invalid/unknown instruction");
299 if (
II &&
II->isCommutative() &&
II->arg_size() >= 2) {
312 return hash_combine(GCR->getOpcode(), GCR->getOperand(0),
313 GCR->getBasePtr(), GCR->getDerivedPtr());
340 if (LHSI->
getOpcode() != RHSI->getOpcode())
347 CI && CI->isConvergent() && LHSI->
getParent() != RHSI->getParent())
355 if (!LHSBinOp->isCommutative())
359 "same opcode, but different instruction type?");
363 return LHSBinOp->getOperand(0) == RHSBinOp->
getOperand(1) &&
364 LHSBinOp->getOperand(1) == RHSBinOp->
getOperand(0);
368 "same opcode, but different instruction type?");
371 return LHSCmp->getOperand(0) == RHSCmp->
getOperand(1) &&
372 LHSCmp->getOperand(1) == RHSCmp->
getOperand(0) &&
373 LHSCmp->getSwappedPredicate() == RHSCmp->
getPredicate();
378 if (LII && RII && LII->getIntrinsicID() == RII->getIntrinsicID() &&
379 LII->isCommutative() && LII->arg_size() >= 2) {
380 return LII->getArgOperand(0) == RII->getArgOperand(1) &&
381 LII->getArgOperand(1) == RII->getArgOperand(0) &&
382 std::equal(LII->arg_begin() + 2, LII->arg_end(),
383 RII->arg_begin() + 2, RII->arg_end()) &&
384 LII->hasSameSpecialState(RII,
false,
391 return GCR1->getOperand(0) == GCR2->getOperand(0) &&
392 GCR1->getBasePtr() == GCR2->getBasePtr() &&
393 GCR1->getDerivedPtr() == GCR2->getDerivedPtr();
399 Value *CondL, *CondR, *LHSA, *RHSA, *LHSB, *RHSB;
406 return ((LHSA == RHSA && LHSB == RHSB) ||
407 (LHSA == RHSB && LHSB == RHSA));
410 if (CondL == CondR && LHSA == RHSA && LHSB == RHSB)
432 if (LHSA == RHSB && LHSB == RHSA) {
464 CallValue(Instruction *
I) : Inst(
I) {
465 assert(canHandle(
I) &&
"Inst can't be handled!");
468 static bool canHandle(Instruction *Inst) {
488 static bool isEqual(CallValue LHS, CallValue RHS);
519 std::optional<int64_t> ConstantOffset;
521 GEPValue(Instruction *
I) : Inst(
I) {
522 assert(canHandle(
I) &&
"Inst can't be handled!");
525 GEPValue(Instruction *
I, std::optional<int64_t> ConstantOffset)
526 : Inst(
I), ConstantOffset(ConstantOffset) {
527 assert(canHandle(
I) &&
"Inst can't be handled!");
530 static bool canHandle(Instruction *Inst) {
539 static bool isEqual(
const GEPValue &LHS,
const GEPValue &RHS);
544 if (Val.ConstantOffset.has_value())
546 Val.ConstantOffset.value());
554 if (LGEP->getPointerOperand() != RGEP->getPointerOperand())
556 if (
LHS.ConstantOffset.has_value() &&
RHS.ConstantOffset.has_value())
557 return LHS.ConstantOffset.value() ==
RHS.ConstantOffset.value();
558 return LGEP->isIdenticalToWhenDefined(RGEP);
576 const TargetLibraryInfo &TLI;
577 const TargetTransformInfo &TTI;
580 const SimplifyQuery SQ;
582 std::unique_ptr<MemorySSAUpdater> MSSAUpdater;
586 ScopedHashTableVal<SimpleValue, Value *>>;
588 ScopedHashTable<SimpleValue, Value *, DenseMapInfo<SimpleValue>,
597 ScopedHTType AvailableValues;
615 unsigned Generation = 0;
617 bool IsAtomic =
false;
620 LoadValue() =
default;
621 LoadValue(Instruction *Inst,
unsigned Generation,
unsigned MatchingId,
622 bool IsAtomic,
bool IsLoad)
623 : DefInst(Inst), Generation(Generation), MatchingId(MatchingId),
624 IsAtomic(IsAtomic), IsLoad(IsLoad) {}
627 using LoadMapAllocator =
629 ScopedHashTableVal<Value *, LoadValue>>;
631 ScopedHashTable<Value *, LoadValue, DenseMapInfo<Value *>,
634 LoadHTType AvailableLoads;
639 using InvariantMapAllocator =
641 ScopedHashTableVal<MemoryLocation, unsigned>>;
642 using InvariantHTType =
643 ScopedHashTable<MemoryLocation, unsigned, DenseMapInfo<MemoryLocation>,
644 InvariantMapAllocator>;
645 InvariantHTType AvailableInvariants;
652 ScopedHashTable<CallValue, std::pair<Instruction *, unsigned>>;
653 CallHTType AvailableCalls;
655 using GEPMapAllocatorTy =
657 ScopedHashTableVal<GEPValue, Value *>>;
658 using GEPHTType = ScopedHashTable<GEPValue, Value *, DenseMapInfo<GEPValue>,
660 GEPHTType AvailableGEPs;
663 unsigned CurrentGeneration = 0;
666 EarlyCSE(
const DataLayout &
DL,
const TargetLibraryInfo &TLI,
667 const TargetTransformInfo &TTI, DominatorTree &DT,
669 : TLI(TLI), TTI(TTI), DT(DT), AC(AC), SQ(
DL, &TLI, &DT, &AC), MSSA(MSSA),
670 MSSAUpdater(std::make_unique<MemorySSAUpdater>(MSSA)) {}
675 unsigned ClobberCounter = 0;
681 NodeScope(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
682 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
683 GEPHTType &AvailableGEPs)
684 : Scope(AvailableValues), LoadScope(AvailableLoads),
685 InvariantScope(AvailableInvariants), CallScope(AvailableCalls),
686 GEPScope(AvailableGEPs) {}
687 NodeScope(
const NodeScope &) =
delete;
688 NodeScope &operator=(
const NodeScope &) =
delete;
704 StackNode(ScopedHTType &AvailableValues, LoadHTType &AvailableLoads,
705 InvariantHTType &AvailableInvariants, CallHTType &AvailableCalls,
706 GEPHTType &AvailableGEPs,
unsigned cg,
DomTreeNode *n,
707 DomTreeNode::const_iterator child,
708 DomTreeNode::const_iterator end)
709 : CurrentGeneration(cg), ChildGeneration(cg), Node(n), ChildIter(child),
711 Scopes(AvailableValues, AvailableLoads, AvailableInvariants,
712 AvailableCalls, AvailableGEPs) {}
713 StackNode(
const StackNode &) =
delete;
714 StackNode &operator=(
const StackNode &) =
delete;
717 unsigned currentGeneration()
const {
return CurrentGeneration; }
718 unsigned childGeneration()
const {
return ChildGeneration; }
721 DomTreeNode::const_iterator childIter()
const {
return ChildIter; }
729 DomTreeNode::const_iterator
end()
const {
return EndIter; }
730 bool isProcessed()
const {
return Processed; }
731 void process() { Processed =
true; }
734 unsigned CurrentGeneration;
735 unsigned ChildGeneration;
737 DomTreeNode::const_iterator ChildIter;
738 DomTreeNode::const_iterator EndIter;
740 bool Processed =
false;
745 class ParseMemoryInst {
747 ParseMemoryInst(Instruction *Inst,
const TargetTransformInfo &
TTI)
750 IntrID =
II->getIntrinsicID();
753 if (isHandledNonTargetIntrinsic(IntrID)) {
755 case Intrinsic::masked_load:
756 Info.PtrVal = Inst->getOperand(0);
757 Info.MatchingId = Intrinsic::masked_load;
759 Info.WriteMem =
false;
760 Info.IsVolatile =
false;
762 case Intrinsic::masked_store:
763 Info.PtrVal = Inst->getOperand(1);
770 Info.MatchingId = Intrinsic::masked_load;
771 Info.ReadMem =
false;
772 Info.WriteMem =
true;
773 Info.IsVolatile =
false;
777 Info.PtrVal =
MI->getDest();
779 Info.ReadMem =
false;
780 Info.WriteMem =
true;
781 Info.IsVolatile =
MI->isVolatile();
797 return Info.WriteMem;
801 bool isAtomic()
const {
803 return Info.Ordering != AtomicOrdering::NotAtomic;
804 return Inst->isAtomic();
807 bool isUnordered()
const {
809 return Info.isUnordered();
812 return LI->isUnordered();
814 return SI->isUnordered();
817 return !Inst->isAtomic();
820 bool isVolatile()
const {
822 return Info.IsVolatile;
825 return LI->isVolatile();
827 return SI->isVolatile();
835 return LI->hasMetadata(LLVMContext::MD_invariant_load);
845 int getMatchingId()
const {
847 return Info.MatchingId;
859 return Inst->getAccessType();
862 bool mayReadFromMemory()
const {
865 return Inst->mayReadFromMemory();
868 bool mayWriteToMemory()
const {
870 return Info.WriteMem;
871 return Inst->mayWriteToMemory();
876 MemIntrinsicInfo Info;
884 case Intrinsic::masked_load:
885 case Intrinsic::masked_store:
890 static bool isHandledNonTargetIntrinsic(
const Value *V) {
892 return isHandledNonTargetIntrinsic(
II->getIntrinsicID());
898 bool handleBranchCondition(Instruction *CondInst,
const CondBrInst *BI,
899 const BasicBlock *BB,
const BasicBlock *Pred);
902 unsigned CurrentGeneration);
904 bool overridingStores(
const ParseMemoryInst &Earlier,
905 const ParseMemoryInst &Later);
907 Value *getOrCreateResult(Instruction *Inst,
Type *ExpectedType,
908 bool CanCreate)
const {
913 switch (
II->getIntrinsicID()) {
914 case Intrinsic::masked_load:
917 case Intrinsic::masked_store:
918 V =
II->getOperand(0);
921 return TTI.getOrCreateResultFromMemIntrinsic(
II, ExpectedType,
928 return V->getType() == ExpectedType ?
V :
nullptr;
933 bool isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt);
935 bool isSameMemGeneration(
unsigned EarlierGeneration,
unsigned LaterGeneration,
936 Instruction *EarlierInst, Instruction *LaterInst);
938 bool isNonTargetIntrinsicMatch(
const IntrinsicInst *Earlier,
939 const IntrinsicInst *Later) {
940 auto IsSubmask = [](
const Value *Mask0,
const Value *Mask1) {
950 if (Vec0->getType() != Vec1->getType())
952 for (
int i = 0, e = Vec0->getNumOperands(); i != e; ++i) {
953 Constant *Elem0 = Vec0->getOperand(i);
954 Constant *Elem1 = Vec1->getOperand(i);
956 if (Int0 && Int0->isZero())
969 auto PtrOp = [](
const IntrinsicInst *
II) {
970 if (
II->getIntrinsicID() == Intrinsic::masked_load)
971 return II->getOperand(0);
972 if (
II->getIntrinsicID() == Intrinsic::masked_store)
973 return II->getOperand(1);
976 auto MaskOp = [](
const IntrinsicInst *
II) {
977 if (
II->getIntrinsicID() == Intrinsic::masked_load)
978 return II->getOperand(1);
979 if (
II->getIntrinsicID() == Intrinsic::masked_store)
980 return II->getOperand(2);
983 auto ThruOp = [](
const IntrinsicInst *
II) {
984 if (
II->getIntrinsicID() == Intrinsic::masked_load)
985 return II->getOperand(2);
989 if (PtrOp(Earlier) != PtrOp(Later))
996 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_load) {
1002 if (MaskOp(Earlier) == MaskOp(Later) && ThruOp(Earlier) == ThruOp(Later))
1006 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
1008 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_load) {
1013 if (!IsSubmask(MaskOp(Later), MaskOp(Earlier)))
1017 if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_store) {
1021 return IsSubmask(MaskOp(Later), MaskOp(Earlier));
1023 if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_store) {
1028 return IsSubmask(MaskOp(Earlier), MaskOp(Later));
1033 void removeMSSA(Instruction &Inst) {
1037 MSSA->verifyMemorySSA();
1044 MSSAUpdater->removeMemoryAccess(&Inst,
true);
1066bool EarlyCSE::isSameMemGeneration(
unsigned EarlierGeneration,
1067 unsigned LaterGeneration,
1071 if (EarlierGeneration == LaterGeneration)
1095 MemoryAccess *LaterDef;
1100 LaterDef = LaterMA->getDefiningAccess();
1102 return MSSA->
dominates(LaterDef, EarlierMA);
1105bool EarlyCSE::isOperatingOnInvariantMemAt(Instruction *
I,
unsigned GenAt) {
1109 if (LI->hasMetadata(LLVMContext::MD_invariant_load))
1117 MemoryLocation MemLoc = *MemLocOpt;
1118 if (!AvailableInvariants.count(MemLoc))
1123 return AvailableInvariants.lookup(MemLoc) <= GenAt;
1126bool EarlyCSE::handleBranchCondition(Instruction *CondInst,
1127 const CondBrInst *BI,
const BasicBlock *BB,
1128 const BasicBlock *Pred) {
1136 if (Opcode == Instruction::And &&
1139 else if (Opcode == Instruction::Or &&
1147 unsigned PropagateOpcode =
1148 (BI->
getSuccessor(0) == BB) ? Instruction::And : Instruction::Or;
1150 bool MadeChanges =
false;
1151 SmallVector<Instruction *, 4> WorkList;
1152 SmallPtrSet<Instruction *, 4> Visited;
1154 while (!WorkList.
empty()) {
1155 Instruction *Curr = WorkList.pop_back_val();
1157 AvailableValues.insert(Curr, TorF);
1158 LLVM_DEBUG(dbgs() <<
"EarlyCSE CVP: Add conditional value for '"
1159 << Curr->getName() <<
"' as " << *TorF <<
" in "
1160 << BB->getName() <<
"\n");
1161 if (!DebugCounter::shouldExecute(CSECounter)) {
1162 LLVM_DEBUG(dbgs() <<
"Skipping due to debug counter\n");
1165 if (unsigned Count = replaceDominatedUsesWith(Curr, TorF, DT,
1166 BasicBlockEdge(Pred, BB))) {
1173 if (MatchBinOp(Curr, PropagateOpcode,
LHS,
RHS))
1176 if (SimpleValue::canHandle(OPI) && Visited.
insert(OPI).second)
1183Value *EarlyCSE::getMatchingValue(LoadValue &InVal, ParseMemoryInst &MemInst,
1184 unsigned CurrentGeneration) {
1185 if (InVal.DefInst ==
nullptr)
1188 if (!MemInst.isLoad() || MemInst.isVolatile() || !MemInst.isUnordered())
1190 if (MSI->isVolatile())
1193 if (!Val || !Val->isZero())
1195 auto Len = MSI->getLengthInBytes();
1198 Type *InstType = MemInst.getValueType();
1204 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1205 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1210 if (InVal.MatchingId != MemInst.getMatchingId())
1213 if (MemInst.isVolatile() || !MemInst.isUnordered())
1216 if (MemInst.isLoad() && !InVal.IsAtomic && MemInst.isAtomic())
1222 bool MemInstMatching = !MemInst.isLoad();
1223 Instruction *Matching = MemInstMatching ? MemInst.get() : InVal.DefInst;
1230 ? getOrCreateResult(Matching,
Other->getType(),
false)
1232 if (MemInst.isStore() && InVal.DefInst != Result)
1236 bool MatchingNTI = isHandledNonTargetIntrinsic(Matching);
1237 bool OtherNTI = isHandledNonTargetIntrinsic(
Other);
1238 if (OtherNTI != MatchingNTI)
1240 if (OtherNTI && MatchingNTI) {
1246 if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.
Generation) &&
1247 !isSameMemGeneration(InVal.
Generation, CurrentGeneration, InVal.DefInst,
1252 Result = getOrCreateResult(Matching,
Other->getType(),
true);
1266 I->andIRFlags(&From);
1280 assert(
Success &&
"Failed to intersect attributes in callsites that "
1281 "passed identical check");
1287bool EarlyCSE::overridingStores(
const ParseMemoryInst &Earlier,
1288 const ParseMemoryInst &Later) {
1291 assert(Earlier.isUnordered() && !Earlier.isVolatile() &&
1292 "Violated invariant");
1293 if (Earlier.getPointerOperand() != Later.getPointerOperand())
1295 if (!Earlier.getValueType() || !Later.getValueType() ||
1296 Earlier.getValueType() != Later.getValueType())
1298 if (Earlier.getMatchingId() != Later.getMatchingId())
1305 if (!Earlier.isUnordered() || !Later.isUnordered())
1309 bool ENTI = isHandledNonTargetIntrinsic(Earlier.get());
1310 bool LNTI = isHandledNonTargetIntrinsic(Later.get());
1318 return ENTI == LNTI;
1332 ++CurrentGeneration;
1343 if (CondInst && SimpleValue::canHandle(CondInst))
1344 Changed |= handleBranchCondition(CondInst, BI, BB, Pred);
1380 if (CondI && SimpleValue::canHandle(CondI)) {
1385 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping assumption: " << Inst <<
'\n');
1392 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping noalias intrinsic: " << Inst
1399 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping sideeffect: " << Inst <<
'\n');
1405 LLVM_DEBUG(
dbgs() <<
"EarlyCSE skipping pseudoprobe: " << Inst <<
'\n');
1426 MemoryLocation MemLoc =
1429 if (!AvailableInvariants.count(MemLoc))
1430 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1437 if (SimpleValue::canHandle(CondI)) {
1439 if (
auto *KnownCond = AvailableValues.lookup(CondI)) {
1444 <<
"EarlyCSE removing guard: " << Inst <<
'\n');
1463 LastStore =
nullptr;
1470 LLVM_DEBUG(
dbgs() <<
"EarlyCSE Simplify: " << Inst <<
" to: " << *V
1475 bool Killed =
false;
1497 LastStore =
nullptr;
1500 if (SimpleValue::canHandle(&Inst)) {
1503 "Unexpected ebStrict from SimpleValue::canHandle()");
1504 assert((!CI->getRoundingMode() ||
1505 CI->getRoundingMode() != RoundingMode::Dynamic) &&
1506 "Unexpected dynamic rounding from SimpleValue::canHandle()");
1509 if (
Value *V = AvailableValues.lookup(&Inst)) {
1527 AvailableValues.insert(&Inst, &Inst);
1531 ParseMemoryInst MemInst(&Inst,
TTI);
1533 if (MemInst.isValid() && MemInst.isLoad()) {
1536 if (MemInst.isVolatile() || !MemInst.isUnordered()) {
1537 LastStore =
nullptr;
1538 ++CurrentGeneration;
1541 if (MemInst.isInvariantLoad()) {
1548 if (!AvailableInvariants.count(MemLoc))
1549 AvailableInvariants.insert(MemLoc, CurrentGeneration);
1559 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1562 <<
" to: " << *InVal.DefInst <<
'\n');
1581 AvailableLoads.insert(MemInst.getPointerOperand(),
1582 LoadValue(&Inst, CurrentGeneration,
1583 MemInst.getMatchingId(),
1586 LastStore =
nullptr;
1596 !(MemInst.isValid() && !MemInst.mayReadFromMemory()))
1597 LastStore =
nullptr;
1603 if (CallValue::canHandle(&Inst) &&
1604 (!MemInst.isValid() || !MemInst.isStore()) && !
isa<MemSetInst>(&Inst)) {
1607 std::pair<Instruction *, unsigned> InVal = AvailableCalls.lookup(&Inst);
1608 if (InVal.first !=
nullptr &&
1609 isSameMemGeneration(InVal.second, CurrentGeneration, InVal.first,
1613 <<
" to: " << *InVal.first <<
'\n');
1632 ++CurrentGeneration;
1635 AvailableCalls.insert(&Inst, std::make_pair(&Inst, CurrentGeneration));
1640 if (GEPValue::canHandle(&Inst)) {
1643 GEPValue GEPVal(
GEP,
GEP->accumulateConstantOffset(SQ.
DL,
Offset)
1646 if (
Value *V = AvailableGEPs.lookup(GEPVal)) {
1647 LLVM_DEBUG(
dbgs() <<
"EarlyCSE CSE GEP: " << Inst <<
" to: " << *V
1660 AvailableGEPs.insert(GEPVal, &Inst);
1670 if (FI->getOrdering() == AtomicOrdering::Release) {
1680 if (MemInst.isValid() && MemInst.isStore()) {
1681 LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand());
1682 if (InVal.DefInst &&
1685 LLVM_DEBUG(
dbgs() <<
"EarlyCSE DSE (writeback): " << Inst <<
'\n');
1705 ++CurrentGeneration;
1707 if (MemInst.isValid() && MemInst.isStore()) {
1711 if (overridingStores(ParseMemoryInst(LastStore,
TTI), MemInst)) {
1713 <<
" due to: " << Inst <<
'\n');
1718 removeMSSA(*LastStore);
1722 LastStore =
nullptr;
1733 AvailableLoads.insert(MemInst.getPointerOperand(),
1734 LoadValue(&Inst, CurrentGeneration,
1735 MemInst.getMatchingId(),
1746 if (MemInst.isUnordered() && !MemInst.isVolatile())
1749 LastStore =
nullptr;
1757bool EarlyCSE::run() {
1763 std::deque<StackNode *> nodesToProcess;
1768 nodesToProcess.push_back(
new StackNode(
1769 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1770 AvailableGEPs, CurrentGeneration, DT.
getRootNode(),
1773 assert(!CurrentGeneration &&
"Create a new EarlyCSE instance to rerun it.");
1776 while (!nodesToProcess.empty()) {
1779 StackNode *NodeToProcess = nodesToProcess.back();
1790 }
else if (NodeToProcess->
childIter() != NodeToProcess->
end()) {
1793 nodesToProcess.push_back(
new StackNode(
1794 AvailableValues, AvailableLoads, AvailableInvariants, AvailableCalls,
1800 delete NodeToProcess;
1801 nodesToProcess.pop_back();
1817 EarlyCSE
CSE(
F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1832 OS, MapClassName2PassName);
1848template<
bool UseMemorySSA>
1861 if (skipFunction(
F))
1864 auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
1865 auto &
TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
1866 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
1867 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
1869 UseMemorySSA ? &getAnalysis<MemorySSAWrapperPass>().getMSSA() :
nullptr;
1871 EarlyCSE
CSE(
F.getDataLayout(), TLI,
TTI, DT, AC, MSSA);
1876 void getAnalysisUsage(AnalysisUsage &AU)
const override {
1897char EarlyCSELegacyPass::ID = 0;
1907using EarlyCSEMemSSALegacyPass =
1908 EarlyCSELegacyCommonPass<
true>;
1911char EarlyCSEMemSSALegacyPass::
ID = 0;
1915 return new EarlyCSEMemSSALegacyPass();
1921 "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 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 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)
A CRTP mix-in to automatically provide informational APIs needed for passes.