59#include <forward_list>
65#define LLE_OPTION "loop-load-elim"
66#define DEBUG_TYPE LLE_OPTION
69 "runtime-check-per-loop-load-elim",
cl::Hidden,
70 cl::desc(
"Max number of memchecks allowed per eliminated load on average"),
75 cl::desc(
"The maximum number of SCEV checks allowed for Loop "
78STATISTIC(NumLoopLoadEliminted,
"Number of loads eliminated by LLE");
83struct StoreToLoadForwardingCandidate {
93 bool isDependenceDistanceOfOne(PredicatedScalarEvolution &PSE,
Loop *L,
94 const DominatorTree &DT)
const {
95 Value *LoadPtr = Load->getPointerOperand();
96 Value *StorePtr = Store->getPointerOperand();
98 auto &
DL = Load->getDataLayout();
102 DL.getTypeSizeInBits(LoadType) ==
104 "Should be a known dependence");
107 getPtrStride(PSE, LoadType, LoadPtr, L, DT).value_or(0);
108 int64_t StrideStore =
109 getPtrStride(PSE, LoadType, StorePtr, L, DT).value_or(0);
110 if (!StrideLoad || !StrideStore || StrideLoad != StrideStore)
120 if (std::abs(StrideLoad) != 1)
123 unsigned TypeByteSize =
DL.getTypeAllocSize(LoadType);
134 const APInt &Val = Dist->getAPInt();
135 return Val == TypeByteSize * StrideLoad;
138 Value *getLoadPtr()
const {
return Load->getPointerOperand(); }
141 friend raw_ostream &
operator<<(raw_ostream &OS,
142 const StoreToLoadForwardingCandidate &Cand) {
143 OS << *Cand.Store <<
" -->\n";
144 OS.
indent(2) << *Cand.Load <<
"\n";
157 L->getLoopLatches(Latches);
165 return Load->getParent() != L->getHeader();
171class LoadEliminationForLoop {
173 LoadEliminationForLoop(
Loop *L, LoopInfo *LI,
const LoopAccessInfo &LAI,
174 DominatorTree *DT, BlockFrequencyInfo *BFI,
175 ProfileSummaryInfo* PSI)
176 : L(L), LI(LI), LAI(LAI), DT(DT), BFI(BFI), PSI(PSI), PSE(LAI.getPSE()) {}
183 std::forward_list<StoreToLoadForwardingCandidate>
184 findStoreToLoadDependences(
const LoopAccessInfo &LAI) {
185 std::forward_list<StoreToLoadForwardingCandidate> Candidates;
187 const auto &DepChecker = LAI.getDepChecker();
188 const auto *Deps = DepChecker.getDependences();
196 SmallPtrSet<Instruction *, 4> LoadsWithUnsafeDependence;
198 for (
const auto &Dep : *Deps) {
200 Instruction *Destination = Dep.getDestination(DepChecker);
206 LoadsWithUnsafeDependence.
insert(Source);
208 LoadsWithUnsafeDependence.
insert(Destination);
212 if (Dep.isBackward())
218 assert(Dep.isForward() &&
"Needs to be a forward dependence");
230 Store->getDataLayout())) {
240 if (!LoadsWithUnsafeDependence.
empty())
241 Candidates.remove_if([&](
const StoreToLoadForwardingCandidate &
C) {
242 return LoadsWithUnsafeDependence.
count(
C.Load);
249 unsigned getInstrIndex(Instruction *Inst) {
250 auto I = InstOrder.find(Inst);
251 assert(
I != InstOrder.end() &&
"No index for instruction");
274 void removeDependencesFromMultipleStores(
275 std::forward_list<StoreToLoadForwardingCandidate> &Candidates) {
278 using LoadToSingleCandT =
279 DenseMap<LoadInst *, const StoreToLoadForwardingCandidate *>;
280 LoadToSingleCandT LoadToSingleCand;
282 for (
const auto &Cand : Candidates) {
284 LoadToSingleCandT::iterator Iter;
286 std::tie(Iter, NewElt) =
287 LoadToSingleCand.insert(std::make_pair(Cand.Load, &Cand));
289 const StoreToLoadForwardingCandidate *&OtherCand = Iter->second;
291 if (OtherCand ==
nullptr)
297 if (Cand.Store->getParent() == OtherCand->Store->
getParent() &&
298 Cand.isDependenceDistanceOfOne(PSE, L, *DT) &&
299 OtherCand->isDependenceDistanceOfOne(PSE, L, *DT)) {
301 if (getInstrIndex(OtherCand->Store) < getInstrIndex(Cand.Store))
308 Candidates.remove_if([&](
const StoreToLoadForwardingCandidate &Cand) {
309 if (LoadToSingleCand[Cand.Load] != &Cand) {
311 dbgs() <<
"Removing from candidates: \n"
313 <<
" The load may have multiple stores forwarding to "
326 bool needsChecking(
unsigned PtrIdx1,
unsigned PtrIdx2,
327 const SmallPtrSetImpl<Value *> &PtrsWrittenOnFwdingPath,
328 const SmallPtrSetImpl<Value *> &CandLoadPtrs) {
330 LAI.getRuntimePointerChecking()->getPointerInfo(PtrIdx1).PointerValue;
332 LAI.getRuntimePointerChecking()->getPointerInfo(PtrIdx2).PointerValue;
333 return ((PtrsWrittenOnFwdingPath.
count(Ptr1) && CandLoadPtrs.
count(Ptr2)) ||
334 (PtrsWrittenOnFwdingPath.
count(Ptr2) && CandLoadPtrs.
count(Ptr1)));
341 SmallPtrSet<Value *, 4> findPointersWrittenOnForwardingPath(
342 const SmallVectorImpl<StoreToLoadForwardingCandidate> &Candidates) {
362 [&](
const StoreToLoadForwardingCandidate &
A,
363 const StoreToLoadForwardingCandidate &
B) {
364 return getInstrIndex(
A.Load) <
365 getInstrIndex(
B.Load);
368 StoreInst *FirstStore =
370 [&](
const StoreToLoadForwardingCandidate &
A,
371 const StoreToLoadForwardingCandidate &
B) {
372 return getInstrIndex(
A.Store) <
373 getInstrIndex(
B.Store);
380 SmallPtrSet<Value *, 4> PtrsWrittenOnFwdingPath;
384 PtrsWrittenOnFwdingPath.insert(S->getPointerOperand());
386 const auto &MemInstrs = LAI.getDepChecker().getMemoryInstructions();
387 std::for_each(MemInstrs.begin() + getInstrIndex(FirstStore) + 1,
388 MemInstrs.end(), InsertStorePtr);
389 std::for_each(MemInstrs.begin(), &MemInstrs[getInstrIndex(LastLoad)],
392 return PtrsWrittenOnFwdingPath;
397 SmallVector<RuntimePointerCheck, 4> collectMemchecks(
398 const SmallVectorImpl<StoreToLoadForwardingCandidate> &Candidates) {
400 SmallPtrSet<Value *, 4> PtrsWrittenOnFwdingPath =
401 findPointersWrittenOnForwardingPath(Candidates);
404 SmallPtrSet<Value *, 4> CandLoadPtrs;
405 for (
const auto &Candidate : Candidates)
406 CandLoadPtrs.
insert(Candidate.getLoadPtr());
408 const auto &AllChecks = LAI.getRuntimePointerChecking()->getChecks();
409 SmallVector<RuntimePointerCheck, 4> Checks;
411 copy_if(AllChecks, std::back_inserter(Checks),
413 for (
auto PtrIdx1 :
Check.first->Members)
414 for (
auto PtrIdx2 :
Check.second->Members)
415 if (needsChecking(PtrIdx1, PtrIdx2, PtrsWrittenOnFwdingPath,
423 LLVM_DEBUG(LAI.getRuntimePointerChecking()->printChecks(
dbgs(), Checks));
430 propagateStoredValueToLoadUsers(
const StoreToLoadForwardingCandidate &Cand,
449 auto *PH = L->getLoopPreheader();
450 assert(PH &&
"Preheader should exist!");
451 Value *InitialPtr =
SEE.expandCodeFor(PtrSCEV->getStart(), Ptr->
getType(),
452 PH->getTerminator());
454 new LoadInst(Cand.Load->
getType(), InitialPtr,
"load_initial",
456 PH->getTerminator()->getIterator());
464 PHI->insertBefore(L->getHeader()->begin());
465 PHI->addIncoming(Initial, PH);
472 assert(
DL.getTypeSizeInBits(LoadType) ==
DL.getTypeSizeInBits(StoreType) &&
473 "The type sizes should match!");
476 if (LoadType != StoreType) {
478 "store_forward_cast",
486 PHI->addIncoming(StoreValue, L->getLoopLatch());
495 LLVM_DEBUG(
dbgs() <<
"\nIn \"" << L->getHeader()->getParent()->getName()
496 <<
"\" checking " << *L <<
"\n");
517 auto StoreToLoadDependences = findStoreToLoadDependences(LAI);
518 if (StoreToLoadDependences.empty())
523 InstOrder = LAI.getDepChecker().generateInstructionOrderMap();
527 removeDependencesFromMultipleStores(StoreToLoadDependences);
528 if (StoreToLoadDependences.empty())
533 for (
const StoreToLoadForwardingCandidate &Cand : StoreToLoadDependences) {
549 if (!Cand.isDependenceDistanceOfOne(PSE, L, *DT))
553 "Loading from something other than indvar?");
556 "Storing to something other than indvar?");
562 <<
". Valid store-to-load forwarding across the loop backedge\n");
564 if (Candidates.
empty())
569 SmallVector<RuntimePointerCheck, 4> Checks = collectMemchecks(Candidates);
577 if (LAI.getPSE().getPredicate().getComplexity() >
583 if (!L->isLoopSimplifyForm()) {
588 if (!Checks.
empty() || !LAI.getPSE().getPredicate().isAlwaysTrue()) {
589 if (LAI.hasConvergentOp()) {
591 "convergent calls\n");
595 auto *HeaderBB = L->getHeader();
597 PGSOQueryType::IRPass)) {
599 dbgs() <<
"Versioning is needed but not allowed when optimizing "
608 if (!L->isRecursivelyLCSSAForm(*DT, *LI))
611 LoopVersioning LV(LAI, Checks, L, LI, DT, PSE.getSE());
616 auto NoLongerGoodCandidate = [
this](
617 const StoreToLoadForwardingCandidate &Cand) {
628 SCEVExpander
SEE(*PSE.getSE(),
"storeforward");
629 for (
const auto &Cand : Candidates)
630 propagateStoredValueToLoadUsers(Cand,
SEE);
631 NumLoopLoadEliminted += Candidates.size();
641 DenseMap<Instruction *, unsigned> InstOrder;
645 const LoopAccessInfo &LAI;
647 BlockFrequencyInfo *BFI;
648 ProfileSummaryInfo *PSI;
649 PredicatedScalarEvolution PSE;
669 for (
Loop *TopLevelLoop : LI)
673 if (L->isInnermost())
678 for (
Loop *L : Worklist) {
680 if (!L->isRotatedForm() || !L->getExitingBlock())
683 LoadEliminationForLoop LEL(L, &LI, LAIs.
getInfo(*L), &DT, BFI, PSI);
703 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 cl::opt< unsigned > LoadElimSCEVCheckThreshold("loop-load-elimination-scev-check-threshold", cl::init(8), cl::Hidden, cl::desc("The maximum number of SCEV checks allowed for Loop " "Load Elimination"))
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...
static cl::opt< unsigned > CheckPerElim("runtime-check-per-loop-load-elim", cl::Hidden, cl::desc("Max number of memchecks allowed per eliminated load on average"), cl::init(1))
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, SCEV::NoWrapFlags 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.
initializer< Ty > init(const Ty &Val)
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)