59#include <forward_list>
65#define LLE_OPTION "loop-load-elim"
66#define DEBUG_TYPE LLE_OPTION
68STATISTIC(NumLoopLoadEliminted,
"Number of loads eliminated by LLE");
73struct StoreToLoadForwardingCandidate {
83 bool isDependenceDistanceOfOne(PredicatedScalarEvolution &PSE,
Loop *L,
84 const DominatorTree &DT)
const {
85 Value *LoadPtr = Load->getPointerOperand();
86 Value *StorePtr = Store->getPointerOperand();
88 auto &
DL = Load->getDataLayout();
92 DL.getTypeSizeInBits(LoadType) ==
94 "Should be a known dependence");
99 getPtrStride(PSE, LoadType, StorePtr, L, DT).value_or(0);
100 if (!StrideLoad || !StrideStore || StrideLoad != StrideStore)
110 if (std::abs(StrideLoad) != 1)
113 unsigned TypeByteSize =
DL.getTypeAllocSize(LoadType);
124 const APInt &Val = Dist->getAPInt();
125 return Val == TypeByteSize * StrideLoad;
128 Value *getLoadPtr()
const {
return Load->getPointerOperand(); }
131 friend raw_ostream &
operator<<(raw_ostream &OS,
132 const StoreToLoadForwardingCandidate &Cand) {
133 OS << *Cand.Store <<
" -->\n";
134 OS.
indent(2) << *Cand.Load <<
"\n";
147 L->getLoopLatches(Latches);
155 return Load->getParent() != L->getHeader();
161class LoadEliminationForLoop {
163 LoadEliminationForLoop(
Loop *L, LoopInfo *LI,
const LoopAccessInfo &LAI,
164 DominatorTree *DT, BlockFrequencyInfo *BFI,
165 ProfileSummaryInfo* PSI)
166 : L(L), LI(LI), LAI(LAI), DT(DT), BFI(BFI), PSI(PSI), PSE(LAI.getPSE()) {}
173 std::forward_list<StoreToLoadForwardingCandidate>
174 findStoreToLoadDependences(
const LoopAccessInfo &LAI) {
175 std::forward_list<StoreToLoadForwardingCandidate> Candidates;
177 const auto &DepChecker = LAI.getDepChecker();
178 const auto *Deps = DepChecker.getDependences();
186 SmallPtrSet<Instruction *, 4> LoadsWithUnsafeDependence;
188 for (
const auto &Dep : *Deps) {
190 Instruction *Destination = Dep.getDestination(DepChecker);
196 LoadsWithUnsafeDependence.
insert(Source);
198 LoadsWithUnsafeDependence.
insert(Destination);
202 if (Dep.isBackward())
208 assert(Dep.isForward() &&
"Needs to be a forward dependence");
220 Store->getDataLayout())) {
230 if (!LoadsWithUnsafeDependence.
empty())
231 Candidates.remove_if([&](
const StoreToLoadForwardingCandidate &
C) {
232 return LoadsWithUnsafeDependence.
count(
C.Load);
239 unsigned getInstrIndex(Instruction *Inst) {
240 auto I = InstOrder.find(Inst);
241 assert(
I != InstOrder.end() &&
"No index for instruction");
264 void removeDependencesFromMultipleStores(
265 std::forward_list<StoreToLoadForwardingCandidate> &Candidates) {
268 using LoadToSingleCandT =
269 DenseMap<LoadInst *, const StoreToLoadForwardingCandidate *>;
270 LoadToSingleCandT LoadToSingleCand;
272 for (
const auto &Cand : Candidates) {
274 LoadToSingleCandT::iterator Iter;
276 std::tie(Iter, NewElt) =
277 LoadToSingleCand.insert(std::make_pair(Cand.Load, &Cand));
279 const StoreToLoadForwardingCandidate *&OtherCand = Iter->second;
281 if (OtherCand ==
nullptr)
287 if (Cand.Store->getParent() == OtherCand->Store->
getParent() &&
288 Cand.isDependenceDistanceOfOne(PSE, L, *DT) &&
289 OtherCand->isDependenceDistanceOfOne(PSE, L, *DT)) {
291 if (getInstrIndex(OtherCand->Store) < getInstrIndex(Cand.Store))
298 Candidates.remove_if([&](
const StoreToLoadForwardingCandidate &Cand) {
299 if (LoadToSingleCand[Cand.Load] != &Cand) {
301 dbgs() <<
"Removing from candidates: \n"
303 <<
" The load may have multiple stores forwarding to "
316 bool needsChecking(
unsigned PtrIdx1,
unsigned PtrIdx2,
317 const SmallPtrSetImpl<Value *> &PtrsWrittenOnFwdingPath,
318 const SmallPtrSetImpl<Value *> &CandLoadPtrs) {
320 LAI.getRuntimePointerChecking()->getPointerInfo(PtrIdx1).PointerValue;
322 LAI.getRuntimePointerChecking()->getPointerInfo(PtrIdx2).PointerValue;
323 return ((PtrsWrittenOnFwdingPath.
count(Ptr1) && CandLoadPtrs.
count(Ptr2)) ||
324 (PtrsWrittenOnFwdingPath.
count(Ptr2) && CandLoadPtrs.
count(Ptr1)));
331 SmallPtrSet<Value *, 4> findPointersWrittenOnForwardingPath(
332 const SmallVectorImpl<StoreToLoadForwardingCandidate> &Candidates) {
352 [&](
const StoreToLoadForwardingCandidate &
A,
353 const StoreToLoadForwardingCandidate &
B) {
354 return getInstrIndex(
A.Load) <
355 getInstrIndex(
B.Load);
358 StoreInst *FirstStore =
360 [&](
const StoreToLoadForwardingCandidate &
A,
361 const StoreToLoadForwardingCandidate &
B) {
362 return getInstrIndex(
A.Store) <
363 getInstrIndex(
B.Store);
370 SmallPtrSet<Value *, 4> PtrsWrittenOnFwdingPath;
374 PtrsWrittenOnFwdingPath.insert(S->getPointerOperand());
376 const auto &MemInstrs = LAI.getDepChecker().getMemoryInstructions();
377 std::for_each(MemInstrs.begin() + getInstrIndex(FirstStore) + 1,
378 MemInstrs.end(), InsertStorePtr);
379 std::for_each(MemInstrs.begin(), &MemInstrs[getInstrIndex(LastLoad)],
382 return PtrsWrittenOnFwdingPath;
387 SmallVector<RuntimePointerCheck, 4> collectMemchecks(
388 const SmallVectorImpl<StoreToLoadForwardingCandidate> &Candidates) {
390 SmallPtrSet<Value *, 4> PtrsWrittenOnFwdingPath =
391 findPointersWrittenOnForwardingPath(Candidates);
394 SmallPtrSet<Value *, 4> CandLoadPtrs;
395 for (
const auto &Candidate : Candidates)
396 CandLoadPtrs.
insert(Candidate.getLoadPtr());
398 const auto &AllChecks = LAI.getRuntimePointerChecking()->getChecks();
399 SmallVector<RuntimePointerCheck, 4> Checks;
401 copy_if(AllChecks, std::back_inserter(Checks),
403 for (
auto PtrIdx1 :
Check.first->Members)
404 for (
auto PtrIdx2 :
Check.second->Members)
405 if (needsChecking(PtrIdx1, PtrIdx2, PtrsWrittenOnFwdingPath,
413 LLVM_DEBUG(LAI.getRuntimePointerChecking()->printChecks(
dbgs(), Checks));
420 propagateStoredValueToLoadUsers(
const StoreToLoadForwardingCandidate &Cand,
439 auto *PH = L->getLoopPreheader();
440 assert(PH &&
"Preheader should exist!");
441 Value *InitialPtr =
SEE.expandCodeFor(PtrSCEV->getStart(), Ptr->
getType(),
442 PH->getTerminator());
444 new LoadInst(Cand.Load->
getType(), InitialPtr,
"load_initial",
446 PH->getTerminator()->getIterator());
454 PHI->insertBefore(L->getHeader()->begin());
455 PHI->addIncoming(Initial, PH);
462 assert(
DL.getTypeSizeInBits(LoadType) ==
DL.getTypeSizeInBits(StoreType) &&
463 "The type sizes should match!");
466 if (LoadType != StoreType) {
468 "store_forward_cast",
476 PHI->addIncoming(StoreValue, L->getLoopLatch());
485 const ScalarOptions &Opts = ScalarOptions::Global;
486 LLVM_DEBUG(
dbgs() <<
"\nIn \"" << L->getHeader()->getParent()->getName()
487 <<
"\" checking " << *L <<
"\n");
508 auto StoreToLoadDependences = findStoreToLoadDependences(LAI);
509 if (StoreToLoadDependences.empty())
514 InstOrder = LAI.getDepChecker().generateInstructionOrderMap();
518 removeDependencesFromMultipleStores(StoreToLoadDependences);
519 if (StoreToLoadDependences.empty())
524 for (
const StoreToLoadForwardingCandidate &Cand : StoreToLoadDependences) {
540 if (!Cand.isDependenceDistanceOfOne(PSE, L, *DT))
544 "Loading from something other than indvar?");
547 "Storing to something other than indvar?");
553 <<
". Valid store-to-load forwarding across the loop backedge\n");
555 if (Candidates.
empty())
560 SmallVector<RuntimePointerCheck, 4> Checks = collectMemchecks(Candidates);
564 Candidates.
size() * Opts.runtime_check_per_loop_load_elim) {
569 if (LAI.getPSE().getPredicate().getComplexity() >
570 Opts.loop_load_elimination_scev_check_threshold) {
575 if (!L->isLoopSimplifyForm()) {
580 if (!Checks.
empty() || !LAI.getPSE().getPredicate().isAlwaysTrue()) {
581 if (LAI.hasConvergentOp()) {
583 "convergent calls\n");
587 auto *HeaderBB = L->getHeader();
589 PGSOQueryType::IRPass)) {
591 dbgs() <<
"Versioning is needed but not allowed when optimizing "
600 if (!L->isRecursivelyLCSSAForm(*DT, *LI))
603 LoopVersioning LV(LAI, Checks, L, LI, DT, PSE.getSE());
608 auto NoLongerGoodCandidate = [
this](
609 const StoreToLoadForwardingCandidate &Cand) {
620 SCEVExpander
SEE(*PSE.getSE(),
"storeforward");
621 for (
const auto &Cand : Candidates)
622 propagateStoredValueToLoadUsers(Cand,
SEE);
623 NumLoopLoadEliminted += Candidates.size();
633 DenseMap<Instruction *, unsigned> InstOrder;
637 const LoopAccessInfo &LAI;
639 BlockFrequencyInfo *BFI;
640 ProfileSummaryInfo *PSI;
641 PredicatedScalarEvolution PSE;
661 for (
Loop *TopLevelLoop : LI)
665 if (L->isInnermost())
670 for (
Loop *L : Worklist) {
672 if (!L->isRotatedForm() || !L->getExitingBlock())
675 LoadEliminationForLoop LEL(L, &LI, LAIs.
getInfo(*L), &DT, BFI, PSI);
695 auto *BFI = (PSI && PSI->hasProfileSummary()) ?
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseMap class.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
This is the interface for a simple mod/ref and alias analysis over globals.
This header defines various interfaces for pass management in LLVM.
This header provides classes for managing per-loop analyses.
static bool eliminateLoadsAcrossLoops(Function &F, LoopInfo &LI, DominatorTree &DT, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, ScalarEvolution *SE, AssumptionCache *AC, LoopAccessInfoManager &LAIs)
static bool isLoadConditional(LoadInst *Load, Loop *L)
Return true if the load is not executed on all paths in the loop.
static bool doesStoreDominatesAllLatches(BasicBlock *StoreBlock, Loop *L, DominatorTree *DT)
Check if the store dominates all latches, so as long as there is no intervening store this value will...
This header defines the LoopLoadEliminationPass object.
static bool processLoop(Loop &L, const AArch64Subtarget &ST, DataLayout DL)
This file defines the SmallPtrSet class.
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)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
Analysis pass which computes BlockFrequencyInfo.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
static LLVM_ABI bool isBitOrNoopPointerCastable(Type *SrcTy, Type *DestTy, const DataLayout &DL)
Check whether a bitcast, inttoptr, or ptrtoint cast between these types is valid and a no-op.
static LLVM_ABI CastInst * CreateBitOrPointerCast(Value *S, Type *Ty, const Twine &Name="", InsertPosition InsertBefore=nullptr)
Create a BitCast, a PtrToInt, or an IntToPTr cast instruction.
static DebugLoc getDropped()
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
An instruction for reading from memory.
Value * getPointerOperand()
Align getAlign() const
Return the alignment of the access that is being performed.
This analysis provides dependence information for the memory accesses of a loop.
LLVM_ABI const LoopAccessInfo & getInfo(Loop &L, bool AllowPartial=false)
Analysis pass that exposes the LoopInfo for a function.
Represents a single loop in the control flow graph.
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
ScalarEvolution * getSE() const
Returns the ScalarEvolution analysis used.
LLVM_ABI const SCEV * getSCEV(Value *V)
Returns the SCEV expression of V, in the context of the current SCEV predicate.
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 & preserve()
Mark an analysis as preserved.
An analysis pass based on the new PM to deliver ProfileSummaryInfo.
Analysis providing profile information.
Analysis pass that exposes the ScalarEvolution for a function.
The main scalar evolution driver.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEVFlags Flags=SCEV::FlagNone, unsigned Depth=0)
Return LHS-RHS.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
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)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Value * getValueOperand()
Value * getPointerOperand()
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
const ParentTy * getParent() const
self_iterator getIterator()
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI bool simplifyLoop(Loop *L, DominatorTree *DT, LoopInfo *LI, ScalarEvolution *SE, AssumptionCache *AC, MemorySSAUpdater *MSSAU, bool PreserveLCSSA)
Simplify each loop in a loop nest recursively.
auto min_element(R &&Range)
Provide wrappers to std::min_element which take ranges instead of having to pass begin/end explicitly...
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
OuterAnalysisManagerProxy< ModuleAnalysisManager, Function > ModuleAnalysisManagerFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
LLVM_ABI bool formLCSSARecursively(Loop &L, const DominatorTree &DT, const LoopInfo *LI, ScalarEvolution *SE)
Put a loop nest into LCSSA form.
LLVM_ABI bool shouldOptimizeForSize(const MachineFunction *MF, ProfileSummaryInfo *PSI, const MachineBlockFrequencyInfo *BFI, PGSOQueryType QueryType=PGSOQueryType::Other)
Returns true if machine function MF is suggested to be size-optimized based on the profile.
std::pair< const RuntimeCheckingPtrGroup *, const RuntimeCheckingPtrGroup * > RuntimePointerCheck
A memcheck which made up of a pair of grouped pointers.
LLVM_ABI std::optional< int64_t > getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr, const Loop *Lp, const DominatorTree &DT, const SymbolicStrideMap &StridesMap=SymbolicStrideMap(), bool ShouldCheckWrap=true, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
If the pointer has a constant stride return it in units of the access type size.
OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P)
Provide wrappers to std::copy_if which take ranges instead of having to pass begin/end explicitly.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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...
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
Type * getLoadStoreType(const Value *I)
A helper function that returns the type of a load or store instruction.
iterator_range< df_iterator< T > > depth_first(const T &G)
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)