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 {
88 : Load(Load), Store(Store) {}
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> LoadsWithUnknownDependence;
198 for (
const auto &Dep : *Deps) {
200 Instruction *Destination = Dep.getDestination(DepChecker);
206 LoadsWithUnknownDependence.
insert(Source);
208 LoadsWithUnknownDependence.
insert(Destination);
212 if (Dep.isBackward())
218 assert(Dep.isForward() &&
"Needs to be a forward dependence");
230 Store->getDataLayout()))
233 Candidates.emplace_front(Load, Store);
236 if (!LoadsWithUnknownDependence.
empty())
237 Candidates.remove_if([&](
const StoreToLoadForwardingCandidate &
C) {
238 return LoadsWithUnknownDependence.
count(
C.Load);
245 unsigned getInstrIndex(Instruction *Inst) {
246 auto I = InstOrder.find(Inst);
247 assert(
I != InstOrder.end() &&
"No index for instruction");
270 void removeDependencesFromMultipleStores(
271 std::forward_list<StoreToLoadForwardingCandidate> &Candidates) {
274 using LoadToSingleCandT =
275 DenseMap<LoadInst *, const StoreToLoadForwardingCandidate *>;
276 LoadToSingleCandT LoadToSingleCand;
278 for (
const auto &Cand : Candidates) {
280 LoadToSingleCandT::iterator Iter;
282 std::tie(Iter, NewElt) =
283 LoadToSingleCand.insert(std::make_pair(Cand.Load, &Cand));
285 const StoreToLoadForwardingCandidate *&OtherCand = Iter->second;
287 if (OtherCand ==
nullptr)
293 if (Cand.Store->getParent() == OtherCand->Store->
getParent() &&
294 Cand.isDependenceDistanceOfOne(PSE, L, *DT) &&
295 OtherCand->isDependenceDistanceOfOne(PSE, L, *DT)) {
297 if (getInstrIndex(OtherCand->Store) < getInstrIndex(Cand.Store))
304 Candidates.remove_if([&](
const StoreToLoadForwardingCandidate &Cand) {
305 if (LoadToSingleCand[Cand.Load] != &Cand) {
307 dbgs() <<
"Removing from candidates: \n"
309 <<
" The load may have multiple stores forwarding to "
322 bool needsChecking(
unsigned PtrIdx1,
unsigned PtrIdx2,
323 const SmallPtrSetImpl<Value *> &PtrsWrittenOnFwdingPath,
324 const SmallPtrSetImpl<Value *> &CandLoadPtrs) {
326 LAI.getRuntimePointerChecking()->getPointerInfo(PtrIdx1).PointerValue;
328 LAI.getRuntimePointerChecking()->getPointerInfo(PtrIdx2).PointerValue;
329 return ((PtrsWrittenOnFwdingPath.
count(Ptr1) && CandLoadPtrs.
count(Ptr2)) ||
330 (PtrsWrittenOnFwdingPath.
count(Ptr2) && CandLoadPtrs.
count(Ptr1)));
337 SmallPtrSet<Value *, 4> findPointersWrittenOnForwardingPath(
338 const SmallVectorImpl<StoreToLoadForwardingCandidate> &Candidates) {
358 [&](
const StoreToLoadForwardingCandidate &
A,
359 const StoreToLoadForwardingCandidate &
B) {
360 return getInstrIndex(
A.Load) <
361 getInstrIndex(
B.Load);
364 StoreInst *FirstStore =
366 [&](
const StoreToLoadForwardingCandidate &
A,
367 const StoreToLoadForwardingCandidate &
B) {
368 return getInstrIndex(
A.Store) <
369 getInstrIndex(
B.Store);
376 SmallPtrSet<Value *, 4> PtrsWrittenOnFwdingPath;
380 PtrsWrittenOnFwdingPath.insert(S->getPointerOperand());
382 const auto &MemInstrs = LAI.getDepChecker().getMemoryInstructions();
383 std::for_each(MemInstrs.begin() + getInstrIndex(FirstStore) + 1,
384 MemInstrs.end(), InsertStorePtr);
385 std::for_each(MemInstrs.begin(), &MemInstrs[getInstrIndex(LastLoad)],
388 return PtrsWrittenOnFwdingPath;
393 SmallVector<RuntimePointerCheck, 4> collectMemchecks(
394 const SmallVectorImpl<StoreToLoadForwardingCandidate> &Candidates) {
396 SmallPtrSet<Value *, 4> PtrsWrittenOnFwdingPath =
397 findPointersWrittenOnForwardingPath(Candidates);
400 SmallPtrSet<Value *, 4> CandLoadPtrs;
401 for (
const auto &Candidate : Candidates)
402 CandLoadPtrs.
insert(Candidate.getLoadPtr());
404 const auto &AllChecks = LAI.getRuntimePointerChecking()->getChecks();
405 SmallVector<RuntimePointerCheck, 4> Checks;
407 copy_if(AllChecks, std::back_inserter(Checks),
409 for (
auto PtrIdx1 :
Check.first->Members)
410 for (
auto PtrIdx2 :
Check.second->Members)
411 if (needsChecking(PtrIdx1, PtrIdx2, PtrsWrittenOnFwdingPath,
419 LLVM_DEBUG(LAI.getRuntimePointerChecking()->printChecks(
dbgs(), Checks));
426 propagateStoredValueToLoadUsers(
const StoreToLoadForwardingCandidate &Cand,
445 auto *PH = L->getLoopPreheader();
446 assert(PH &&
"Preheader should exist!");
447 Value *InitialPtr =
SEE.expandCodeFor(PtrSCEV->getStart(), Ptr->
getType(),
448 PH->getTerminator());
450 new LoadInst(Cand.Load->
getType(), InitialPtr,
"load_initial",
452 PH->getTerminator()->getIterator());
460 PHI->insertBefore(L->getHeader()->begin());
461 PHI->addIncoming(Initial, PH);
468 assert(
DL.getTypeSizeInBits(LoadType) ==
DL.getTypeSizeInBits(StoreType) &&
469 "The type sizes should match!");
472 if (LoadType != StoreType) {
474 "store_forward_cast",
482 PHI->addIncoming(StoreValue, L->getLoopLatch());
491 LLVM_DEBUG(
dbgs() <<
"\nIn \"" << L->getHeader()->getParent()->getName()
492 <<
"\" checking " << *L <<
"\n");
513 auto StoreToLoadDependences = findStoreToLoadDependences(LAI);
514 if (StoreToLoadDependences.empty())
519 InstOrder = LAI.getDepChecker().generateInstructionOrderMap();
523 removeDependencesFromMultipleStores(StoreToLoadDependences);
524 if (StoreToLoadDependences.empty())
529 for (
const StoreToLoadForwardingCandidate &Cand : StoreToLoadDependences) {
545 if (!Cand.isDependenceDistanceOfOne(PSE, L, *DT))
549 "Loading from something other than indvar?");
552 "Storing to something other than indvar?");
558 <<
". Valid store-to-load forwarding across the loop backedge\n");
560 if (Candidates.
empty())
565 SmallVector<RuntimePointerCheck, 4> Checks = collectMemchecks(Candidates);
573 if (LAI.getPSE().getPredicate().getComplexity() >
579 if (!L->isLoopSimplifyForm()) {
584 if (!Checks.
empty() || !LAI.getPSE().getPredicate().isAlwaysTrue()) {
585 if (LAI.hasConvergentOp()) {
587 "convergent calls\n");
591 auto *HeaderBB = L->getHeader();
593 PGSOQueryType::IRPass)) {
595 dbgs() <<
"Versioning is needed but not allowed when optimizing "
604 if (!L->isRecursivelyLCSSAForm(*DT, *LI))
607 LoopVersioning LV(LAI, Checks, L, LI, DT, PSE.getSE());
612 auto NoLongerGoodCandidate = [
this](
613 const StoreToLoadForwardingCandidate &Cand) {
624 SCEVExpander
SEE(*PSE.getSE(),
"storeforward");
625 for (
const auto &Cand : Candidates)
626 propagateStoredValueToLoadUsers(Cand,
SEE);
627 NumLoopLoadEliminted += Candidates.size();
637 DenseMap<Instruction *, unsigned> InstOrder;
641 const LoopAccessInfo &LAI;
643 BlockFrequencyInfo *BFI;
644 ProfileSummaryInfo *PSI;
645 PredicatedScalarEvolution PSE;
665 for (
Loop *TopLevelLoop : LI)
669 if (L->isInnermost())
674 for (
Loop *L : Worklist) {
676 if (!L->isRotatedForm() || !L->getExitingBlock())
679 LoadEliminationForLoop LEL(L, &LI, LAIs.
getInfo(*L), &DT, BFI, PSI);
699 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< 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::FlagAnyWrap, 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.
@ C
The default llvm calling convention, compatible with C.
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.
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.
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.
LLVM_ABI std::optional< int64_t > getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr, const Loop *Lp, const DominatorTree &DT, const DenseMap< Value *, const SCEV * > &StridesMap=DenseMap< Value *, const SCEV * >(), bool ShouldCheckWrap=true, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
If the pointer has a constant stride return it in units of the access type size.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)