#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 <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;
namespace gvn LLVM_LIBRARY_VISIBILITY {
struct AvailableValue;
struct AvailableValueInBlock;
class GVNLegacyPass;
}
struct GVNOptions {
Optional<bool> AllowPRE = None;
Optional<bool> AllowLoadPRE = None;
Optional<bool> AllowLoadInLoopPRE = None;
Optional<bool> AllowLoadPRESplitBackedge = None;
Optional<bool> AllowMemDep = None;
GVNOptions() = default;
GVNOptions &setPRE(bool PRE) {
AllowPRE = PRE;
return *this;
}
GVNOptions &setLoadPRE(bool LoadPRE) {
AllowLoadPRE = LoadPRE;
return *this;
}
GVNOptions &setLoadInLoopPRE(bool LoadInLoopPRE) {
AllowLoadInLoopPRE = LoadInLoopPRE;
return *this;
}
GVNOptions &setLoadPRESplitBackedge(bool LoadPRESplitBackedge) {
AllowLoadPRESplitBackedge = LoadPRESplitBackedge;
return *this;
}
GVNOptions &setMemDep(bool MemDep) {
AllowMemDep = MemDep;
return *this;
}
};
class GVNPass : public PassInfoMixin<GVNPass> {
GVNOptions Options;
public:
struct Expression;
GVNPass(GVNOptions Options = {}) : Options(Options) {}
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
void printPipeline(raw_ostream &OS,
function_ref<StringRef(StringRef)> MapClassName2PassName);
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;
class ValueTable {
DenseMap<Value *, uint32_t> valueNumbering;
DenseMap<Expression, uint32_t> expressionNumbering;
uint32_t nextExprNumber = 0;
std::vector<Expression> Expressions;
std::vector<uint32_t> ExprIdx;
DenseMap<uint32_t, PHINode *> NumberingPhi;
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;
struct LeaderTableEntry {
Value *Val;
const BasicBlock *BB;
LeaderTableEntry *Next;
};
DenseMap<uint32_t, LeaderTableEntry> LeaderTable;
BumpPtrAllocator TableAllocator;
SmallMapVector<Value *, Value *, 4> ReplaceOperandsWithMap;
SmallVector<Instruction *, 8> InstrsToErase;
DenseMap<AssertingVH<BasicBlock>, uint32_t> 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);
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;
}
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;
}
}
}
SmallVector<std::pair<Instruction *, unsigned>, 4> toSplit;
bool processLoad(LoadInst *L);
bool processNonLocalLoad(LoadInst *L);
bool processAssumeIntrinsic(AssumeInst *II);
bool AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo,
Value *Address, gvn::AvailableValue &Res);
void AnalyzeLoadAvailability(LoadInst *Load, LoadDepVect &Deps,
AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks);
bool PerformLoadPRE(LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks);
bool performLoopLoadPRE(LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks);
void eliminatePartiallyRedundantLoad(
LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
MapVector<BasicBlock *, Value *> &AvailableLoads);
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);
};
FunctionPass *createGVNPass(bool NoMemDepAnalysis = false);
struct GVNHoistPass : PassInfoMixin<GVNHoistPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
struct GVNSinkPass : PassInfoMixin<GVNSinkPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
}
#endif