#include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AssumeBundleQueries.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/DomTreeUpdater.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/InstructionPrecedenceTracking.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/Loads.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/PHITransAddr.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/Value.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/SSAUpdater.h"
#include "llvm/Transforms/Utils/VNCoercion.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <optional>
#include <utility>
usingnamespacellvm;
usingnamespacellvm::gvn;
usingnamespacellvm::VNCoercion;
usingnamespacePatternMatch;
#define DEBUG_TYPE …
STATISTIC(NumGVNInstr, "Number of instructions deleted");
STATISTIC(NumGVNLoad, "Number of loads deleted");
STATISTIC(NumGVNPRE, "Number of instructions PRE'd");
STATISTIC(NumGVNBlocks, "Number of blocks merged");
STATISTIC(NumGVNSimpl, "Number of instructions simplified");
STATISTIC(NumGVNEqProp, "Number of equalities propagated");
STATISTIC(NumPRELoad, "Number of loads PRE'd");
STATISTIC(NumPRELoopLoad, "Number of loop loads PRE'd");
STATISTIC(NumPRELoadMoved2CEPred,
"Number of loads moved to predecessor of a critical edge in PRE");
STATISTIC(IsValueFullyAvailableInBlockNumSpeculationsMax,
"Number of blocks speculated as available in "
"IsValueFullyAvailableInBlock(), max");
STATISTIC(MaxBBSpeculationCutoffReachedTimes,
"Number of times we we reached gvn-max-block-speculations cut-off "
"preventing further exploration");
static cl::opt<bool> GVNEnablePRE("enable-pre", cl::init(true), cl::Hidden);
static cl::opt<bool> GVNEnableLoadPRE("enable-load-pre", cl::init(true));
static cl::opt<bool> GVNEnableLoadInLoopPRE("enable-load-in-loop-pre",
cl::init(true));
static cl::opt<bool>
GVNEnableSplitBackedgeInLoadPRE("enable-split-backedge-in-load-pre",
cl::init(false));
static cl::opt<bool> GVNEnableMemDep("enable-gvn-memdep", cl::init(true));
static cl::opt<uint32_t> MaxNumDeps(
"gvn-max-num-deps", cl::Hidden, cl::init(100),
cl::desc("Max number of dependences to attempt Load PRE (default = 100)"));
static cl::opt<uint32_t> MaxBBSpeculations(
"gvn-max-block-speculations", cl::Hidden, cl::init(600),
cl::desc("Max number of blocks we're willing to speculate on (and recurse "
"into) when deducing if a value is fully available or not in GVN "
"(default = 600)"));
static cl::opt<uint32_t> MaxNumVisitedInsts(
"gvn-max-num-visited-insts", cl::Hidden, cl::init(100),
cl::desc("Max number of visited instructions when trying to find "
"dominating value of select dependency (default = 100)"));
static cl::opt<uint32_t> MaxNumInsnsPerBlock(
"gvn-max-num-insns", cl::Hidden, cl::init(100),
cl::desc("Max number of instructions to scan in each basic block in GVN "
"(default = 100)"));
struct llvm::GVNPass::Expression { … };
namespace llvm {
template <> struct DenseMapInfo<GVNPass::Expression> { … };
}
struct llvm::gvn::AvailableValue { … };
struct llvm::gvn::AvailableValueInBlock { … };
GVNPass::Expression GVNPass::ValueTable::createExpr(Instruction *I) { … }
GVNPass::Expression GVNPass::ValueTable::createCmpExpr(
unsigned Opcode, CmpInst::Predicate Predicate, Value *LHS, Value *RHS) { … }
GVNPass::Expression
GVNPass::ValueTable::createExtractvalueExpr(ExtractValueInst *EI) { … }
GVNPass::Expression GVNPass::ValueTable::createGEPExpr(GetElementPtrInst *GEP) { … }
GVNPass::ValueTable::ValueTable() = default;
GVNPass::ValueTable::ValueTable(const ValueTable &) = default;
GVNPass::ValueTable::ValueTable(ValueTable &&) = default;
GVNPass::ValueTable::~ValueTable() = default;
GVNPass::ValueTable &
GVNPass::ValueTable::operator=(const GVNPass::ValueTable &Arg) = default;
void GVNPass::ValueTable::add(Value *V, uint32_t num) { … }
uint32_t GVNPass::ValueTable::lookupOrAddCall(CallInst *C) { … }
bool GVNPass::ValueTable::exists(Value *V) const { … }
uint32_t GVNPass::ValueTable::lookupOrAdd(Value *V) { … }
uint32_t GVNPass::ValueTable::lookup(Value *V, bool Verify) const { … }
uint32_t GVNPass::ValueTable::lookupOrAddCmp(unsigned Opcode,
CmpInst::Predicate Predicate,
Value *LHS, Value *RHS) { … }
void GVNPass::ValueTable::clear() { … }
void GVNPass::ValueTable::erase(Value *V) { … }
void GVNPass::ValueTable::verifyRemoved(const Value *V) const { … }
void GVNPass::LeaderMap::insert(uint32_t N, Value *V, const BasicBlock *BB) { … }
void GVNPass::LeaderMap::erase(uint32_t N, Instruction *I,
const BasicBlock *BB) { … }
void GVNPass::LeaderMap::verifyRemoved(const Value *V) const { … }
bool GVNPass::isPREEnabled() const { … }
bool GVNPass::isLoadPREEnabled() const { … }
bool GVNPass::isLoadInLoopPREEnabled() const { … }
bool GVNPass::isLoadPRESplitBackedgeEnabled() const { … }
bool GVNPass::isMemDepEnabled() const { … }
PreservedAnalyses GVNPass::run(Function &F, FunctionAnalysisManager &AM) { … }
void GVNPass::printPipeline(
raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) { … }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void GVNPass::dump(DenseMap<uint32_t, Value *> &d) const {
errs() << "{\n";
for (auto &I : d) {
errs() << I.first << "\n";
I.second->dump();
}
errs() << "}\n";
}
#endif
enum class AvailabilityState : char { … };
static bool IsValueFullyAvailableInBlock(
BasicBlock *BB,
DenseMap<BasicBlock *, AvailabilityState> &FullyAvailableBlocks) { … }
static void replaceValuesPerBlockEntry(
SmallVectorImpl<AvailableValueInBlock> &ValuesPerBlock, Value *OldValue,
Value *NewValue) { … }
static Value *
ConstructSSAForLoadSet(LoadInst *Load,
SmallVectorImpl<AvailableValueInBlock> &ValuesPerBlock,
GVNPass &gvn) { … }
Value *AvailableValue::MaterializeAdjustedValue(LoadInst *Load,
Instruction *InsertPt,
GVNPass &gvn) const { … }
static bool isLifetimeStart(const Instruction *Inst) { … }
static bool liesBetween(const Instruction *From, Instruction *Between,
const Instruction *To, DominatorTree *DT) { … }
static void reportMayClobberedLoad(LoadInst *Load, MemDepResult DepInfo,
DominatorTree *DT,
OptimizationRemarkEmitter *ORE) { … }
static Value *findDominatingValue(const MemoryLocation &Loc, Type *LoadTy,
Instruction *From, AAResults *AA) { … }
std::optional<AvailableValue>
GVNPass::AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo,
Value *Address) { … }
void GVNPass::AnalyzeLoadAvailability(LoadInst *Load, LoadDepVect &Deps,
AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks) { … }
LoadInst *GVNPass::findLoadToHoistIntoPred(BasicBlock *Pred, BasicBlock *LoadBB,
LoadInst *Load) { … }
void GVNPass::eliminatePartiallyRedundantLoad(
LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
MapVector<BasicBlock *, Value *> &AvailableLoads,
MapVector<BasicBlock *, LoadInst *> *CriticalEdgePredAndLoad) { … }
bool GVNPass::PerformLoadPRE(LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks) { … }
bool GVNPass::performLoopLoadPRE(LoadInst *Load,
AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks) { … }
static void reportLoadElim(LoadInst *Load, Value *AvailableValue,
OptimizationRemarkEmitter *ORE) { … }
bool GVNPass::processNonLocalLoad(LoadInst *Load) { … }
static bool impliesEquivalanceIfTrue(CmpInst* Cmp) { … }
static bool impliesEquivalanceIfFalse(CmpInst* Cmp) { … }
static bool hasUsersIn(Value *V, BasicBlock *BB) { … }
bool GVNPass::processAssumeIntrinsic(AssumeInst *IntrinsicI) { … }
static void patchAndReplaceAllUsesWith(Instruction *I, Value *Repl) { … }
bool GVNPass::processLoad(LoadInst *L) { … }
std::pair<uint32_t, bool>
GVNPass::ValueTable::assignExpNewValueNum(Expression &Exp) { … }
bool GVNPass::ValueTable::areAllValsInBB(uint32_t Num, const BasicBlock *BB,
GVNPass &Gvn) { … }
uint32_t GVNPass::ValueTable::phiTranslate(const BasicBlock *Pred,
const BasicBlock *PhiBlock,
uint32_t Num, GVNPass &Gvn) { … }
bool GVNPass::ValueTable::areCallValsEqual(uint32_t Num, uint32_t NewNum,
const BasicBlock *Pred,
const BasicBlock *PhiBlock,
GVNPass &Gvn) { … }
uint32_t GVNPass::ValueTable::phiTranslateImpl(const BasicBlock *Pred,
const BasicBlock *PhiBlock,
uint32_t Num, GVNPass &Gvn) { … }
void GVNPass::ValueTable::eraseTranslateCacheEntry(
uint32_t Num, const BasicBlock &CurrBlock) { … }
Value *GVNPass::findLeader(const BasicBlock *BB, uint32_t num) { … }
static bool isOnlyReachableViaThisEdge(const BasicBlockEdge &E,
DominatorTree *DT) { … }
void GVNPass::assignBlockRPONumber(Function &F) { … }
bool GVNPass::replaceOperandsForInBlockEquality(Instruction *Instr) const { … }
bool GVNPass::propagateEquality(Value *LHS, Value *RHS,
const BasicBlockEdge &Root,
bool DominatesByEdge) { … }
bool GVNPass::processInstruction(Instruction *I) { … }
bool GVNPass::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
const TargetLibraryInfo &RunTLI, AAResults &RunAA,
MemoryDependenceResults *RunMD, LoopInfo &LI,
OptimizationRemarkEmitter *RunORE, MemorySSA *MSSA) { … }
bool GVNPass::processBlock(BasicBlock *BB) { … }
bool GVNPass::performScalarPREInsertion(Instruction *Instr, BasicBlock *Pred,
BasicBlock *Curr, unsigned int ValNo) { … }
bool GVNPass::performScalarPRE(Instruction *CurInst) { … }
bool GVNPass::performPRE(Function &F) { … }
BasicBlock *GVNPass::splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ) { … }
bool GVNPass::splitCriticalEdges() { … }
bool GVNPass::iterateOnFunction(Function &F) { … }
void GVNPass::cleanupGlobalSets() { … }
void GVNPass::removeInstruction(Instruction *I) { … }
void GVNPass::verifyRemoved(const Instruction *Inst) const { … }
void GVNPass::addDeadBlock(BasicBlock *BB) { … }
bool GVNPass::processFoldableCondBr(BranchInst *BI) { … }
void GVNPass::assignValNumForDeadCode() { … }
class llvm::gvn::GVNLegacyPass : public FunctionPass { … };
char GVNLegacyPass::ID = …;
INITIALIZE_PASS_BEGIN(GVNLegacyPass, "gvn", "Global Value Numbering", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(MemoryDependenceWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass)
INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass)
INITIALIZE_PASS_END(GVNLegacyPass, "gvn", "Global Value Numbering", false, false)
FunctionPass *llvm::createGVNPass(bool NoMemDepAnalysis) { … }