123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- GVN.h - Eliminate redundant values and loads -------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- /// \file
- /// This file provides the interface for LLVM's Global Value Numbering pass
- /// which eliminates fully redundant instructions. It also does somewhat Ad-Hoc
- /// PRE and dead load elimination.
- ///
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_TRANSFORMS_SCALAR_GVN_H
- #define LLVM_TRANSFORMS_SCALAR_GVN_H
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/MapVector.h"
- #include "llvm/ADT/SetVector.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/IR/Dominators.h"
- #include "llvm/IR/InstrTypes.h"
- #include "llvm/IR/PassManager.h"
- #include "llvm/IR/ValueHandle.h"
- #include "llvm/Support/Allocator.h"
- #include "llvm/Support/Compiler.h"
- #include <cstdint>
- #include <optional>
- #include <utility>
- #include <vector>
- namespace llvm {
- class AAResults;
- class AssumeInst;
- class AssumptionCache;
- class BasicBlock;
- class BranchInst;
- class CallInst;
- class ExtractValueInst;
- class Function;
- class FunctionPass;
- class GetElementPtrInst;
- class ImplicitControlFlowTracking;
- class LoadInst;
- class LoopInfo;
- class MemDepResult;
- class MemoryDependenceResults;
- class MemorySSA;
- class MemorySSAUpdater;
- class NonLocalDepResult;
- class OptimizationRemarkEmitter;
- class PHINode;
- class TargetLibraryInfo;
- class Value;
- /// A private "module" namespace for types and utilities used by GVN. These
- /// are implementation details and should not be used by clients.
- namespace gvn LLVM_LIBRARY_VISIBILITY {
- struct AvailableValue;
- struct AvailableValueInBlock;
- class GVNLegacyPass;
- } // end namespace gvn
- /// A set of parameters to control various transforms performed by GVN pass.
- // Each of the optional boolean parameters can be set to:
- /// true - enabling the transformation.
- /// false - disabling the transformation.
- /// None - relying on a global default.
- /// Intended use is to create a default object, modify parameters with
- /// additional setters and then pass it to GVN.
- struct GVNOptions {
- std::optional<bool> AllowPRE;
- std::optional<bool> AllowLoadPRE;
- std::optional<bool> AllowLoadInLoopPRE;
- std::optional<bool> AllowLoadPRESplitBackedge;
- std::optional<bool> AllowMemDep;
- GVNOptions() = default;
- /// Enables or disables PRE in GVN.
- GVNOptions &setPRE(bool PRE) {
- AllowPRE = PRE;
- return *this;
- }
- /// Enables or disables PRE of loads in GVN.
- GVNOptions &setLoadPRE(bool LoadPRE) {
- AllowLoadPRE = LoadPRE;
- return *this;
- }
- GVNOptions &setLoadInLoopPRE(bool LoadInLoopPRE) {
- AllowLoadInLoopPRE = LoadInLoopPRE;
- return *this;
- }
- /// Enables or disables PRE of loads in GVN.
- GVNOptions &setLoadPRESplitBackedge(bool LoadPRESplitBackedge) {
- AllowLoadPRESplitBackedge = LoadPRESplitBackedge;
- return *this;
- }
- /// Enables or disables use of MemDepAnalysis.
- GVNOptions &setMemDep(bool MemDep) {
- AllowMemDep = MemDep;
- return *this;
- }
- };
- /// The core GVN pass object.
- ///
- /// FIXME: We should have a good summary of the GVN algorithm implemented by
- /// this particular pass here.
- class GVNPass : public PassInfoMixin<GVNPass> {
- GVNOptions Options;
- public:
- struct Expression;
- GVNPass(GVNOptions Options = {}) : Options(Options) {}
- /// Run the pass over the function.
- PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
- void printPipeline(raw_ostream &OS,
- function_ref<StringRef(StringRef)> MapClassName2PassName);
- /// This removes the specified instruction from
- /// our various maps and marks it for deletion.
- void markInstructionForDeletion(Instruction *I) {
- VN.erase(I);
- InstrsToErase.push_back(I);
- }
- DominatorTree &getDominatorTree() const { return *DT; }
- AAResults *getAliasAnalysis() const { return VN.getAliasAnalysis(); }
- MemoryDependenceResults &getMemDep() const { return *MD; }
- bool isPREEnabled() const;
- bool isLoadPREEnabled() const;
- bool isLoadInLoopPREEnabled() const;
- bool isLoadPRESplitBackedgeEnabled() const;
- bool isMemDepEnabled() const;
- /// This class holds the mapping between values and value numbers. It is used
- /// as an efficient mechanism to determine the expression-wise equivalence of
- /// two values.
- class ValueTable {
- DenseMap<Value *, uint32_t> valueNumbering;
- DenseMap<Expression, uint32_t> expressionNumbering;
- // Expressions is the vector of Expression. ExprIdx is the mapping from
- // value number to the index of Expression in Expressions. We use it
- // instead of a DenseMap because filling such mapping is faster than
- // filling a DenseMap and the compile time is a little better.
- uint32_t nextExprNumber = 0;
- std::vector<Expression> Expressions;
- std::vector<uint32_t> ExprIdx;
- // Value number to PHINode mapping. Used for phi-translate in scalarpre.
- DenseMap<uint32_t, PHINode *> NumberingPhi;
- // Cache for phi-translate in scalarpre.
- using PhiTranslateMap =
- DenseMap<std::pair<uint32_t, const BasicBlock *>, uint32_t>;
- PhiTranslateMap PhiTranslateTable;
- AAResults *AA = nullptr;
- MemoryDependenceResults *MD = nullptr;
- DominatorTree *DT = nullptr;
- uint32_t nextValueNumber = 1;
- Expression createExpr(Instruction *I);
- Expression createCmpExpr(unsigned Opcode, CmpInst::Predicate Predicate,
- Value *LHS, Value *RHS);
- Expression createExtractvalueExpr(ExtractValueInst *EI);
- Expression createGEPExpr(GetElementPtrInst *GEP);
- uint32_t lookupOrAddCall(CallInst *C);
- uint32_t phiTranslateImpl(const BasicBlock *BB, const BasicBlock *PhiBlock,
- uint32_t Num, GVNPass &Gvn);
- bool areCallValsEqual(uint32_t Num, uint32_t NewNum, const BasicBlock *Pred,
- const BasicBlock *PhiBlock, GVNPass &Gvn);
- std::pair<uint32_t, bool> assignExpNewValueNum(Expression &exp);
- bool areAllValsInBB(uint32_t num, const BasicBlock *BB, GVNPass &Gvn);
- public:
- ValueTable();
- ValueTable(const ValueTable &Arg);
- ValueTable(ValueTable &&Arg);
- ~ValueTable();
- ValueTable &operator=(const ValueTable &Arg);
- uint32_t lookupOrAdd(Value *V);
- uint32_t lookup(Value *V, bool Verify = true) const;
- uint32_t lookupOrAddCmp(unsigned Opcode, CmpInst::Predicate Pred,
- Value *LHS, Value *RHS);
- uint32_t phiTranslate(const BasicBlock *BB, const BasicBlock *PhiBlock,
- uint32_t Num, GVNPass &Gvn);
- void eraseTranslateCacheEntry(uint32_t Num, const BasicBlock &CurrBlock);
- bool exists(Value *V) const;
- void add(Value *V, uint32_t num);
- void clear();
- void erase(Value *v);
- void setAliasAnalysis(AAResults *A) { AA = A; }
- AAResults *getAliasAnalysis() const { return AA; }
- void setMemDep(MemoryDependenceResults *M) { MD = M; }
- void setDomTree(DominatorTree *D) { DT = D; }
- uint32_t getNextUnusedValueNumber() { return nextValueNumber; }
- void verifyRemoved(const Value *) const;
- };
- private:
- friend class gvn::GVNLegacyPass;
- friend struct DenseMapInfo<Expression>;
- MemoryDependenceResults *MD = nullptr;
- DominatorTree *DT = nullptr;
- const TargetLibraryInfo *TLI = nullptr;
- AssumptionCache *AC = nullptr;
- SetVector<BasicBlock *> DeadBlocks;
- OptimizationRemarkEmitter *ORE = nullptr;
- ImplicitControlFlowTracking *ICF = nullptr;
- LoopInfo *LI = nullptr;
- MemorySSAUpdater *MSSAU = nullptr;
- ValueTable VN;
- /// A mapping from value numbers to lists of Value*'s that
- /// have that value number. Use findLeader to query it.
- struct LeaderTableEntry {
- Value *Val;
- const BasicBlock *BB;
- LeaderTableEntry *Next;
- };
- DenseMap<uint32_t, LeaderTableEntry> LeaderTable;
- BumpPtrAllocator TableAllocator;
- // Block-local map of equivalent values to their leader, does not
- // propagate to any successors. Entries added mid-block are applied
- // to the remaining instructions in the block.
- SmallMapVector<Value *, Value *, 4> ReplaceOperandsWithMap;
- SmallVector<Instruction *, 8> InstrsToErase;
- // Map the block to reversed postorder traversal number. It is used to
- // find back edge easily.
- DenseMap<AssertingVH<BasicBlock>, uint32_t> BlockRPONumber;
- // This is set 'true' initially and also when new blocks have been added to
- // the function being analyzed. This boolean is used to control the updating
- // of BlockRPONumber prior to accessing the contents of BlockRPONumber.
- bool InvalidBlockRPONumbers = true;
- using LoadDepVect = SmallVector<NonLocalDepResult, 64>;
- using AvailValInBlkVect = SmallVector<gvn::AvailableValueInBlock, 64>;
- using UnavailBlkVect = SmallVector<BasicBlock *, 64>;
- bool runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
- const TargetLibraryInfo &RunTLI, AAResults &RunAA,
- MemoryDependenceResults *RunMD, LoopInfo *LI,
- OptimizationRemarkEmitter *ORE, MemorySSA *MSSA = nullptr);
- /// Push a new Value to the LeaderTable onto the list for its value number.
- void addToLeaderTable(uint32_t N, Value *V, const BasicBlock *BB) {
- LeaderTableEntry &Curr = LeaderTable[N];
- if (!Curr.Val) {
- Curr.Val = V;
- Curr.BB = BB;
- return;
- }
- LeaderTableEntry *Node = TableAllocator.Allocate<LeaderTableEntry>();
- Node->Val = V;
- Node->BB = BB;
- Node->Next = Curr.Next;
- Curr.Next = Node;
- }
- /// Scan the list of values corresponding to a given
- /// value number, and remove the given instruction if encountered.
- void removeFromLeaderTable(uint32_t N, Instruction *I, BasicBlock *BB) {
- LeaderTableEntry *Prev = nullptr;
- LeaderTableEntry *Curr = &LeaderTable[N];
- while (Curr && (Curr->Val != I || Curr->BB != BB)) {
- Prev = Curr;
- Curr = Curr->Next;
- }
- if (!Curr)
- return;
- if (Prev) {
- Prev->Next = Curr->Next;
- } else {
- if (!Curr->Next) {
- Curr->Val = nullptr;
- Curr->BB = nullptr;
- } else {
- LeaderTableEntry *Next = Curr->Next;
- Curr->Val = Next->Val;
- Curr->BB = Next->BB;
- Curr->Next = Next->Next;
- }
- }
- }
- // List of critical edges to be split between iterations.
- SmallVector<std::pair<Instruction *, unsigned>, 4> toSplit;
- // Helper functions of redundant load elimination
- bool processLoad(LoadInst *L);
- bool processNonLocalLoad(LoadInst *L);
- bool processAssumeIntrinsic(AssumeInst *II);
- /// Given a local dependency (Def or Clobber) determine if a value is
- /// available for the load.
- std::optional<gvn::AvailableValue>
- AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo, Value *Address);
- /// Given a list of non-local dependencies, determine if a value is
- /// available for the load in each specified block. If it is, add it to
- /// ValuesPerBlock. If not, add it to UnavailableBlocks.
- void AnalyzeLoadAvailability(LoadInst *Load, LoadDepVect &Deps,
- AvailValInBlkVect &ValuesPerBlock,
- UnavailBlkVect &UnavailableBlocks);
- bool PerformLoadPRE(LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
- UnavailBlkVect &UnavailableBlocks);
- /// Try to replace a load which executes on each loop iteraiton with Phi
- /// translation of load in preheader and load(s) in conditionally executed
- /// paths.
- bool performLoopLoadPRE(LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
- UnavailBlkVect &UnavailableBlocks);
- /// Eliminates partially redundant \p Load, replacing it with \p
- /// AvailableLoads (connected by Phis if needed).
- void eliminatePartiallyRedundantLoad(
- LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
- MapVector<BasicBlock *, Value *> &AvailableLoads);
- // Other helper routines
- bool processInstruction(Instruction *I);
- bool processBlock(BasicBlock *BB);
- void dump(DenseMap<uint32_t, Value *> &d) const;
- bool iterateOnFunction(Function &F);
- bool performPRE(Function &F);
- bool performScalarPRE(Instruction *I);
- bool performScalarPREInsertion(Instruction *Instr, BasicBlock *Pred,
- BasicBlock *Curr, unsigned int ValNo);
- Value *findLeader(const BasicBlock *BB, uint32_t num);
- void cleanupGlobalSets();
- void verifyRemoved(const Instruction *I) const;
- bool splitCriticalEdges();
- BasicBlock *splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ);
- bool replaceOperandsForInBlockEquality(Instruction *I) const;
- bool propagateEquality(Value *LHS, Value *RHS, const BasicBlockEdge &Root,
- bool DominatesByEdge);
- bool processFoldableCondBr(BranchInst *BI);
- void addDeadBlock(BasicBlock *BB);
- void assignValNumForDeadCode();
- void assignBlockRPONumber(Function &F);
- };
- /// Create a legacy GVN pass. This also allows parameterizing whether or not
- /// MemDep is enabled.
- FunctionPass *createGVNPass(bool NoMemDepAnalysis = false);
- /// A simple and fast domtree-based GVN pass to hoist common expressions
- /// from sibling branches.
- struct GVNHoistPass : PassInfoMixin<GVNHoistPass> {
- /// Run the pass over the function.
- PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
- };
- /// Uses an "inverted" value numbering to decide the similarity of
- /// expressions and sinks similar expressions into successors.
- struct GVNSinkPass : PassInfoMixin<GVNSinkPass> {
- /// Run the pass over the function.
- PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
- };
- } // end namespace llvm
- #endif // LLVM_TRANSFORMS_SCALAR_GVN_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|