diff options
Diffstat (limited to 'gnu/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp')
| -rw-r--r-- | gnu/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp | 685 |
1 files changed, 0 insertions, 685 deletions
diff --git a/gnu/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp b/gnu/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp deleted file mode 100644 index 19bd9ebcc15..00000000000 --- a/gnu/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp +++ /dev/null @@ -1,685 +0,0 @@ -//===- LoopLoadElimination.cpp - Loop Load Elimination Pass ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implement a loop-aware load elimination pass. -// -// It uses LoopAccessAnalysis to identify loop-carried dependences with a -// distance of one between stores and loads. These form the candidates for the -// transformation. The source value of each store then propagated to the user -// of the corresponding load. This makes the load dead. -// -// The pass can also version the loop and add memchecks in order to prove that -// may-aliasing stores can't change the value in memory before it's read by the -// load. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Transforms/Scalar/LoopLoadElimination.h" -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DepthFirstIterator.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/AssumptionCache.h" -#include "llvm/Analysis/GlobalsModRef.h" -#include "llvm/Analysis/LoopAccessAnalysis.h" -#include "llvm/Analysis/LoopAnalysisManager.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/ScalarEvolution.h" -#include "llvm/Analysis/ScalarEvolutionExpander.h" -#include "llvm/Analysis/ScalarEvolutionExpressions.h" -#include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Dominators.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/PassManager.h" -#include "llvm/IR/Type.h" -#include "llvm/IR/Value.h" -#include "llvm/Pass.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils.h" -#include "llvm/Transforms/Utils/LoopVersioning.h" -#include <algorithm> -#include <cassert> -#include <forward_list> -#include <set> -#include <tuple> -#include <utility> - -using namespace llvm; - -#define LLE_OPTION "loop-load-elim" -#define DEBUG_TYPE LLE_OPTION - -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)); - -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")); - -STATISTIC(NumLoopLoadEliminted, "Number of loads eliminated by LLE"); - -namespace { - -/// Represent a store-to-forwarding candidate. -struct StoreToLoadForwardingCandidate { - LoadInst *Load; - StoreInst *Store; - - StoreToLoadForwardingCandidate(LoadInst *Load, StoreInst *Store) - : Load(Load), Store(Store) {} - - /// Return true if the dependence from the store to the load has a - /// distance of one. E.g. A[i+1] = A[i] - bool isDependenceDistanceOfOne(PredicatedScalarEvolution &PSE, - Loop *L) const { - Value *LoadPtr = Load->getPointerOperand(); - Value *StorePtr = Store->getPointerOperand(); - Type *LoadPtrType = LoadPtr->getType(); - Type *LoadType = LoadPtrType->getPointerElementType(); - - assert(LoadPtrType->getPointerAddressSpace() == - StorePtr->getType()->getPointerAddressSpace() && - LoadType == StorePtr->getType()->getPointerElementType() && - "Should be a known dependence"); - - // Currently we only support accesses with unit stride. FIXME: we should be - // able to handle non unit stirde as well as long as the stride is equal to - // the dependence distance. - if (getPtrStride(PSE, LoadPtr, L) != 1 || - getPtrStride(PSE, StorePtr, L) != 1) - return false; - - auto &DL = Load->getParent()->getModule()->getDataLayout(); - unsigned TypeByteSize = DL.getTypeAllocSize(const_cast<Type *>(LoadType)); - - auto *LoadPtrSCEV = cast<SCEVAddRecExpr>(PSE.getSCEV(LoadPtr)); - auto *StorePtrSCEV = cast<SCEVAddRecExpr>(PSE.getSCEV(StorePtr)); - - // We don't need to check non-wrapping here because forward/backward - // dependence wouldn't be valid if these weren't monotonic accesses. - auto *Dist = cast<SCEVConstant>( - PSE.getSE()->getMinusSCEV(StorePtrSCEV, LoadPtrSCEV)); - const APInt &Val = Dist->getAPInt(); - return Val == TypeByteSize; - } - - Value *getLoadPtr() const { return Load->getPointerOperand(); } - -#ifndef NDEBUG - friend raw_ostream &operator<<(raw_ostream &OS, - const StoreToLoadForwardingCandidate &Cand) { - OS << *Cand.Store << " -->\n"; - OS.indent(2) << *Cand.Load << "\n"; - return OS; - } -#endif -}; - -} // end anonymous namespace - -/// Check if the store dominates all latches, so as long as there is no -/// intervening store this value will be loaded in the next iteration. -static bool doesStoreDominatesAllLatches(BasicBlock *StoreBlock, Loop *L, - DominatorTree *DT) { - SmallVector<BasicBlock *, 8> Latches; - L->getLoopLatches(Latches); - return llvm::all_of(Latches, [&](const BasicBlock *Latch) { - return DT->dominates(StoreBlock, Latch); - }); -} - -/// Return true if the load is not executed on all paths in the loop. -static bool isLoadConditional(LoadInst *Load, Loop *L) { - return Load->getParent() != L->getHeader(); -} - -namespace { - -/// The per-loop class that does most of the work. -class LoadEliminationForLoop { -public: - LoadEliminationForLoop(Loop *L, LoopInfo *LI, const LoopAccessInfo &LAI, - DominatorTree *DT) - : L(L), LI(LI), LAI(LAI), DT(DT), PSE(LAI.getPSE()) {} - - /// Look through the loop-carried and loop-independent dependences in - /// this loop and find store->load dependences. - /// - /// Note that no candidate is returned if LAA has failed to analyze the loop - /// (e.g. if it's not bottom-tested, contains volatile memops, etc.) - std::forward_list<StoreToLoadForwardingCandidate> - findStoreToLoadDependences(const LoopAccessInfo &LAI) { - std::forward_list<StoreToLoadForwardingCandidate> Candidates; - - const auto *Deps = LAI.getDepChecker().getDependences(); - if (!Deps) - return Candidates; - - // Find store->load dependences (consequently true dep). Both lexically - // forward and backward dependences qualify. Disqualify loads that have - // other unknown dependences. - - SmallPtrSet<Instruction *, 4> LoadsWithUnknownDepedence; - - for (const auto &Dep : *Deps) { - Instruction *Source = Dep.getSource(LAI); - Instruction *Destination = Dep.getDestination(LAI); - - if (Dep.Type == MemoryDepChecker::Dependence::Unknown) { - if (isa<LoadInst>(Source)) - LoadsWithUnknownDepedence.insert(Source); - if (isa<LoadInst>(Destination)) - LoadsWithUnknownDepedence.insert(Destination); - continue; - } - - if (Dep.isBackward()) - // Note that the designations source and destination follow the program - // order, i.e. source is always first. (The direction is given by the - // DepType.) - std::swap(Source, Destination); - else - assert(Dep.isForward() && "Needs to be a forward dependence"); - - auto *Store = dyn_cast<StoreInst>(Source); - if (!Store) - continue; - auto *Load = dyn_cast<LoadInst>(Destination); - if (!Load) - continue; - - // Only progagate the value if they are of the same type. - if (Store->getPointerOperandType() != Load->getPointerOperandType()) - continue; - - Candidates.emplace_front(Load, Store); - } - - if (!LoadsWithUnknownDepedence.empty()) - Candidates.remove_if([&](const StoreToLoadForwardingCandidate &C) { - return LoadsWithUnknownDepedence.count(C.Load); - }); - - return Candidates; - } - - /// Return the index of the instruction according to program order. - unsigned getInstrIndex(Instruction *Inst) { - auto I = InstOrder.find(Inst); - assert(I != InstOrder.end() && "No index for instruction"); - return I->second; - } - - /// If a load has multiple candidates associated (i.e. different - /// stores), it means that it could be forwarding from multiple stores - /// depending on control flow. Remove these candidates. - /// - /// Here, we rely on LAA to include the relevant loop-independent dependences. - /// LAA is known to omit these in the very simple case when the read and the - /// write within an alias set always takes place using the *same* pointer. - /// - /// However, we know that this is not the case here, i.e. we can rely on LAA - /// to provide us with loop-independent dependences for the cases we're - /// interested. Consider the case for example where a loop-independent - /// dependece S1->S2 invalidates the forwarding S3->S2. - /// - /// A[i] = ... (S1) - /// ... = A[i] (S2) - /// A[i+1] = ... (S3) - /// - /// LAA will perform dependence analysis here because there are two - /// *different* pointers involved in the same alias set (&A[i] and &A[i+1]). - void removeDependencesFromMultipleStores( - std::forward_list<StoreToLoadForwardingCandidate> &Candidates) { - // If Store is nullptr it means that we have multiple stores forwarding to - // this store. - using LoadToSingleCandT = - DenseMap<LoadInst *, const StoreToLoadForwardingCandidate *>; - LoadToSingleCandT LoadToSingleCand; - - for (const auto &Cand : Candidates) { - bool NewElt; - LoadToSingleCandT::iterator Iter; - - std::tie(Iter, NewElt) = - LoadToSingleCand.insert(std::make_pair(Cand.Load, &Cand)); - if (!NewElt) { - const StoreToLoadForwardingCandidate *&OtherCand = Iter->second; - // Already multiple stores forward to this load. - if (OtherCand == nullptr) - continue; - - // Handle the very basic case when the two stores are in the same block - // so deciding which one forwards is easy. The later one forwards as - // long as they both have a dependence distance of one to the load. - if (Cand.Store->getParent() == OtherCand->Store->getParent() && - Cand.isDependenceDistanceOfOne(PSE, L) && - OtherCand->isDependenceDistanceOfOne(PSE, L)) { - // They are in the same block, the later one will forward to the load. - if (getInstrIndex(OtherCand->Store) < getInstrIndex(Cand.Store)) - OtherCand = &Cand; - } else - OtherCand = nullptr; - } - } - - Candidates.remove_if([&](const StoreToLoadForwardingCandidate &Cand) { - if (LoadToSingleCand[Cand.Load] != &Cand) { - LLVM_DEBUG( - dbgs() << "Removing from candidates: \n" - << Cand - << " The load may have multiple stores forwarding to " - << "it\n"); - return true; - } - return false; - }); - } - - /// Given two pointers operations by their RuntimePointerChecking - /// indices, return true if they require an alias check. - /// - /// We need a check if one is a pointer for a candidate load and the other is - /// a pointer for a possibly intervening store. - bool needsChecking(unsigned PtrIdx1, unsigned PtrIdx2, - const SmallPtrSet<Value *, 4> &PtrsWrittenOnFwdingPath, - const std::set<Value *> &CandLoadPtrs) { - Value *Ptr1 = - LAI.getRuntimePointerChecking()->getPointerInfo(PtrIdx1).PointerValue; - Value *Ptr2 = - LAI.getRuntimePointerChecking()->getPointerInfo(PtrIdx2).PointerValue; - return ((PtrsWrittenOnFwdingPath.count(Ptr1) && CandLoadPtrs.count(Ptr2)) || - (PtrsWrittenOnFwdingPath.count(Ptr2) && CandLoadPtrs.count(Ptr1))); - } - - /// Return pointers that are possibly written to on the path from a - /// forwarding store to a load. - /// - /// These pointers need to be alias-checked against the forwarding candidates. - SmallPtrSet<Value *, 4> findPointersWrittenOnForwardingPath( - const SmallVectorImpl<StoreToLoadForwardingCandidate> &Candidates) { - // From FirstStore to LastLoad neither of the elimination candidate loads - // should overlap with any of the stores. - // - // E.g.: - // - // st1 C[i] - // ld1 B[i] <-------, - // ld0 A[i] <----, | * LastLoad - // ... | | - // st2 E[i] | | - // st3 B[i+1] -- | -' * FirstStore - // st0 A[i+1] ---' - // st4 D[i] - // - // st0 forwards to ld0 if the accesses in st4 and st1 don't overlap with - // ld0. - - LoadInst *LastLoad = - std::max_element(Candidates.begin(), Candidates.end(), - [&](const StoreToLoadForwardingCandidate &A, - const StoreToLoadForwardingCandidate &B) { - return getInstrIndex(A.Load) < getInstrIndex(B.Load); - }) - ->Load; - StoreInst *FirstStore = - std::min_element(Candidates.begin(), Candidates.end(), - [&](const StoreToLoadForwardingCandidate &A, - const StoreToLoadForwardingCandidate &B) { - return getInstrIndex(A.Store) < - getInstrIndex(B.Store); - }) - ->Store; - - // We're looking for stores after the first forwarding store until the end - // of the loop, then from the beginning of the loop until the last - // forwarded-to load. Collect the pointer for the stores. - SmallPtrSet<Value *, 4> PtrsWrittenOnFwdingPath; - - auto InsertStorePtr = [&](Instruction *I) { - if (auto *S = dyn_cast<StoreInst>(I)) - PtrsWrittenOnFwdingPath.insert(S->getPointerOperand()); - }; - const auto &MemInstrs = LAI.getDepChecker().getMemoryInstructions(); - std::for_each(MemInstrs.begin() + getInstrIndex(FirstStore) + 1, - MemInstrs.end(), InsertStorePtr); - std::for_each(MemInstrs.begin(), &MemInstrs[getInstrIndex(LastLoad)], - InsertStorePtr); - - return PtrsWrittenOnFwdingPath; - } - - /// Determine the pointer alias checks to prove that there are no - /// intervening stores. - SmallVector<RuntimePointerChecking::PointerCheck, 4> collectMemchecks( - const SmallVectorImpl<StoreToLoadForwardingCandidate> &Candidates) { - - SmallPtrSet<Value *, 4> PtrsWrittenOnFwdingPath = - findPointersWrittenOnForwardingPath(Candidates); - - // Collect the pointers of the candidate loads. - // FIXME: SmallPtrSet does not work with std::inserter. - std::set<Value *> CandLoadPtrs; - transform(Candidates, - std::inserter(CandLoadPtrs, CandLoadPtrs.begin()), - std::mem_fn(&StoreToLoadForwardingCandidate::getLoadPtr)); - - const auto &AllChecks = LAI.getRuntimePointerChecking()->getChecks(); - SmallVector<RuntimePointerChecking::PointerCheck, 4> Checks; - - copy_if(AllChecks, std::back_inserter(Checks), - [&](const RuntimePointerChecking::PointerCheck &Check) { - for (auto PtrIdx1 : Check.first->Members) - for (auto PtrIdx2 : Check.second->Members) - if (needsChecking(PtrIdx1, PtrIdx2, PtrsWrittenOnFwdingPath, - CandLoadPtrs)) - return true; - return false; - }); - - LLVM_DEBUG(dbgs() << "\nPointer Checks (count: " << Checks.size() - << "):\n"); - LLVM_DEBUG(LAI.getRuntimePointerChecking()->printChecks(dbgs(), Checks)); - - return Checks; - } - - /// Perform the transformation for a candidate. - void - propagateStoredValueToLoadUsers(const StoreToLoadForwardingCandidate &Cand, - SCEVExpander &SEE) { - // loop: - // %x = load %gep_i - // = ... %x - // store %y, %gep_i_plus_1 - // - // => - // - // ph: - // %x.initial = load %gep_0 - // loop: - // %x.storeforward = phi [%x.initial, %ph] [%y, %loop] - // %x = load %gep_i <---- now dead - // = ... %x.storeforward - // store %y, %gep_i_plus_1 - - Value *Ptr = Cand.Load->getPointerOperand(); - auto *PtrSCEV = cast<SCEVAddRecExpr>(PSE.getSCEV(Ptr)); - auto *PH = L->getLoopPreheader(); - Value *InitialPtr = SEE.expandCodeFor(PtrSCEV->getStart(), Ptr->getType(), - PH->getTerminator()); - Value *Initial = - new LoadInst(InitialPtr, "load_initial", /* isVolatile */ false, - Cand.Load->getAlignment(), PH->getTerminator()); - - PHINode *PHI = PHINode::Create(Initial->getType(), 2, "store_forwarded", - &L->getHeader()->front()); - PHI->addIncoming(Initial, PH); - PHI->addIncoming(Cand.Store->getOperand(0), L->getLoopLatch()); - - Cand.Load->replaceAllUsesWith(PHI); - } - - /// Top-level driver for each loop: find store->load forwarding - /// candidates, add run-time checks and perform transformation. - bool processLoop() { - LLVM_DEBUG(dbgs() << "\nIn \"" << L->getHeader()->getParent()->getName() - << "\" checking " << *L << "\n"); - - // Look for store-to-load forwarding cases across the - // backedge. E.g.: - // - // loop: - // %x = load %gep_i - // = ... %x - // store %y, %gep_i_plus_1 - // - // => - // - // ph: - // %x.initial = load %gep_0 - // loop: - // %x.storeforward = phi [%x.initial, %ph] [%y, %loop] - // %x = load %gep_i <---- now dead - // = ... %x.storeforward - // store %y, %gep_i_plus_1 - - // First start with store->load dependences. - auto StoreToLoadDependences = findStoreToLoadDependences(LAI); - if (StoreToLoadDependences.empty()) - return false; - - // Generate an index for each load and store according to the original - // program order. This will be used later. - InstOrder = LAI.getDepChecker().generateInstructionOrderMap(); - - // To keep things simple for now, remove those where the load is potentially - // fed by multiple stores. - removeDependencesFromMultipleStores(StoreToLoadDependences); - if (StoreToLoadDependences.empty()) - return false; - - // Filter the candidates further. - SmallVector<StoreToLoadForwardingCandidate, 4> Candidates; - unsigned NumForwarding = 0; - for (const StoreToLoadForwardingCandidate Cand : StoreToLoadDependences) { - LLVM_DEBUG(dbgs() << "Candidate " << Cand); - - // Make sure that the stored values is available everywhere in the loop in - // the next iteration. - if (!doesStoreDominatesAllLatches(Cand.Store->getParent(), L, DT)) - continue; - - // If the load is conditional we can't hoist its 0-iteration instance to - // the preheader because that would make it unconditional. Thus we would - // access a memory location that the original loop did not access. - if (isLoadConditional(Cand.Load, L)) - continue; - - // Check whether the SCEV difference is the same as the induction step, - // thus we load the value in the next iteration. - if (!Cand.isDependenceDistanceOfOne(PSE, L)) - continue; - - ++NumForwarding; - LLVM_DEBUG( - dbgs() - << NumForwarding - << ". Valid store-to-load forwarding across the loop backedge\n"); - Candidates.push_back(Cand); - } - if (Candidates.empty()) - return false; - - // Check intervening may-alias stores. These need runtime checks for alias - // disambiguation. - SmallVector<RuntimePointerChecking::PointerCheck, 4> Checks = - collectMemchecks(Candidates); - - // Too many checks are likely to outweigh the benefits of forwarding. - if (Checks.size() > Candidates.size() * CheckPerElim) { - LLVM_DEBUG(dbgs() << "Too many run-time checks needed.\n"); - return false; - } - - if (LAI.getPSE().getUnionPredicate().getComplexity() > - LoadElimSCEVCheckThreshold) { - LLVM_DEBUG(dbgs() << "Too many SCEV run-time checks needed.\n"); - return false; - } - - if (!Checks.empty() || !LAI.getPSE().getUnionPredicate().isAlwaysTrue()) { - if (L->getHeader()->getParent()->optForSize()) { - LLVM_DEBUG( - dbgs() << "Versioning is needed but not allowed when optimizing " - "for size.\n"); - return false; - } - - if (!L->isLoopSimplifyForm()) { - LLVM_DEBUG(dbgs() << "Loop is not is loop-simplify form"); - return false; - } - - // Point of no-return, start the transformation. First, version the loop - // if necessary. - - LoopVersioning LV(LAI, L, LI, DT, PSE.getSE(), false); - LV.setAliasChecks(std::move(Checks)); - LV.setSCEVChecks(LAI.getPSE().getUnionPredicate()); - LV.versionLoop(); - } - - // Next, propagate the value stored by the store to the users of the load. - // Also for the first iteration, generate the initial value of the load. - SCEVExpander SEE(*PSE.getSE(), L->getHeader()->getModule()->getDataLayout(), - "storeforward"); - for (const auto &Cand : Candidates) - propagateStoredValueToLoadUsers(Cand, SEE); - NumLoopLoadEliminted += NumForwarding; - - return true; - } - -private: - Loop *L; - - /// Maps the load/store instructions to their index according to - /// program order. - DenseMap<Instruction *, unsigned> InstOrder; - - // Analyses used. - LoopInfo *LI; - const LoopAccessInfo &LAI; - DominatorTree *DT; - PredicatedScalarEvolution PSE; -}; - -} // end anonymous namespace - -static bool -eliminateLoadsAcrossLoops(Function &F, LoopInfo &LI, DominatorTree &DT, - function_ref<const LoopAccessInfo &(Loop &)> GetLAI) { - // Build up a worklist of inner-loops to transform to avoid iterator - // invalidation. - // FIXME: This logic comes from other passes that actually change the loop - // nest structure. It isn't clear this is necessary (or useful) for a pass - // which merely optimizes the use of loads in a loop. - SmallVector<Loop *, 8> Worklist; - - for (Loop *TopLevelLoop : LI) - for (Loop *L : depth_first(TopLevelLoop)) - // We only handle inner-most loops. - if (L->empty()) - Worklist.push_back(L); - - // Now walk the identified inner loops. - bool Changed = false; - for (Loop *L : Worklist) { - // The actual work is performed by LoadEliminationForLoop. - LoadEliminationForLoop LEL(L, &LI, GetLAI(*L), &DT); - Changed |= LEL.processLoop(); - } - return Changed; -} - -namespace { - -/// The pass. Most of the work is delegated to the per-loop -/// LoadEliminationForLoop class. -class LoopLoadElimination : public FunctionPass { -public: - static char ID; - - LoopLoadElimination() : FunctionPass(ID) { - initializeLoopLoadEliminationPass(*PassRegistry::getPassRegistry()); - } - - bool runOnFunction(Function &F) override { - if (skipFunction(F)) - return false; - - auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); - auto &LAA = getAnalysis<LoopAccessLegacyAnalysis>(); - auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); - - // Process each loop nest in the function. - return eliminateLoadsAcrossLoops( - F, LI, DT, - [&LAA](Loop &L) -> const LoopAccessInfo & { return LAA.getInfo(&L); }); - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequiredID(LoopSimplifyID); - AU.addRequired<LoopInfoWrapperPass>(); - AU.addPreserved<LoopInfoWrapperPass>(); - AU.addRequired<LoopAccessLegacyAnalysis>(); - AU.addRequired<ScalarEvolutionWrapperPass>(); - AU.addRequired<DominatorTreeWrapperPass>(); - AU.addPreserved<DominatorTreeWrapperPass>(); - AU.addPreserved<GlobalsAAWrapperPass>(); - } -}; - -} // end anonymous namespace - -char LoopLoadElimination::ID; - -static const char LLE_name[] = "Loop Load Elimination"; - -INITIALIZE_PASS_BEGIN(LoopLoadElimination, LLE_OPTION, LLE_name, false, false) -INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) -INITIALIZE_PASS_DEPENDENCY(LoopAccessLegacyAnalysis) -INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) -INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass) -INITIALIZE_PASS_DEPENDENCY(LoopSimplify) -INITIALIZE_PASS_END(LoopLoadElimination, LLE_OPTION, LLE_name, false, false) - -FunctionPass *llvm::createLoopLoadEliminationPass() { - return new LoopLoadElimination(); -} - -PreservedAnalyses LoopLoadEliminationPass::run(Function &F, - FunctionAnalysisManager &AM) { - auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F); - auto &LI = AM.getResult<LoopAnalysis>(F); - auto &TTI = AM.getResult<TargetIRAnalysis>(F); - auto &DT = AM.getResult<DominatorTreeAnalysis>(F); - auto &TLI = AM.getResult<TargetLibraryAnalysis>(F); - auto &AA = AM.getResult<AAManager>(F); - auto &AC = AM.getResult<AssumptionAnalysis>(F); - - auto &LAM = AM.getResult<LoopAnalysisManagerFunctionProxy>(F).getManager(); - bool Changed = eliminateLoadsAcrossLoops( - F, LI, DT, [&](Loop &L) -> const LoopAccessInfo & { - LoopStandardAnalysisResults AR = {AA, AC, DT, LI, - SE, TLI, TTI, nullptr}; - return LAM.getResult<LoopAccessAnalysis>(L, AR); - }); - - if (!Changed) - return PreservedAnalyses::all(); - - PreservedAnalyses PA; - return PA; -} |
