80#define DEBUG_TYPE "gvn-hoist"
82STATISTIC(NumHoisted,
"Number of instructions hoisted");
83STATISTIC(NumRemoved,
"Number of instructions removed");
84STATISTIC(NumLoadsHoisted,
"Number of loads hoisted");
85STATISTIC(NumLoadsRemoved,
"Number of loads removed");
86STATISTIC(NumStoresHoisted,
"Number of stores hoisted");
87STATISTIC(NumStoresRemoved,
"Number of stores removed");
88STATISTIC(NumCallsHoisted,
"Number of calls hoisted");
89STATISTIC(NumCallsRemoved,
"Number of calls removed");
93 cl::desc(
"Max number of instructions to hoist "
94 "(default unlimited = -1)"));
98 cl::desc(
"Max number of basic blocks on the path between "
99 "hoisting locations (default = 4, unlimited = -1)"));
103 cl::desc(
"Hoist instructions from the beginning of the BB up to the "
104 "maximum specified depth (default = 100, unlimited = -1)"));
108 cl::desc(
"Maximum length of dependent chains to hoist "
109 "(default = 10, unlimited = -1)"));
124using VNType = std::pair<unsigned, uintptr_t>;
183 if (Load->isSimple()) {
184 unsigned V = VN.
lookupOrAdd(Load->getPointerOperand());
187 VNtoLoads[{V, (uintptr_t)Load->getType()}].push_back(Load);
202 if (!Store->isSimple())
205 Value *
Ptr = Store->getPointerOperand();
206 Value *Val = Store->getValueOperand();
226 auto Entry = std::make_pair(V,
InvalidVN);
228 if (Call->doesNotAccessMemory())
229 VNtoCallsScalars[Entry].push_back(Call);
230 else if (Call->onlyReadsMemory())
231 VNtoCallsLoads[Entry].push_back(Call);
233 VNtoCallsStores[Entry].push_back(Call);
248 : DT(DT), PDT(PDT), AA(AA), MD(MD), MSSA(MSSA),
270 std::unique_ptr<MemorySSAUpdater> MSSAUpdater;
275 unsigned NumFuncArgs;
276 const bool HoistingGeps =
false;
278 enum InsKind { Unknown, Scalar, Load, Store };
286 unsigned I1DFS = DFSNumber.
lookup(I1);
287 unsigned I2DFS = DFSNumber.
lookup(I2);
289 return I1DFS < I2DFS;
297 int &NBBsOnAllPaths);
307 int &NBBsOnAllPaths);
314 int &NBBsOnAllPaths);
324 int &NBBsOnAllPaths) {
325 return !hasEHOnPath(HoistBB, BB, NBBsOnAllPaths);
353 RenameStackType &RenameStack);
356 RenameStackType &RenameStack);
363 auto Root = PDT->
getNode(
nullptr);
372 RenameStackType RenameStack;
374 fillRenameStack(BB, ValueBBs, RenameStack);
377 fillChiArgs(BB, CHIBBs, RenameStack);
385 void findHoistableCandidates(
OutValuesType &CHIBBs, InsKind K,
393 std::vector<VNType> Ranks;
394 for (
const auto &Entry : Map) {
395 Ranks.push_back(
Entry.first);
417 for (
const auto &R : Ranks) {
423 for (
const auto &
I : V) {
434 IDFs.setDefiningBlocks(VNBlocks);
436 IDFs.calculate(IDFBlocks);
439 for (
unsigned i = 0; i <
V.size(); ++i) {
440 InValue[
V[i]->getParent()].push_back(std::make_pair(VN, V[i]));
444 CHIArg EmptyChi = {VN,
nullptr,
nullptr};
445 for (
auto *IDFBB : IDFBlocks) {
446 for (
unsigned i = 0; i <
V.size(); ++i) {
449 OutValue[IDFBB].push_back(EmptyChi);
451 << IDFBB->getName() <<
", for Insn: " << *V[i]);
459 insertCHI(InValue, OutValue);
461 findHoistableCandidates(OutValue, K, HPL);
504 std::pair<unsigned, unsigned> hoistExpressions(
Function &
F);
508 NumFuncArgs =
F.arg_size();
510 VN.setAliasAnalysis(AA);
516 DFSNumber[BB] = ++BBI;
518 for (
const auto &Inst : *BB)
519 DFSNumber[&Inst] = ++
I;
529 auto HoistStat = hoistExpressions(
F);
530 if (HoistStat.first + HoistStat.second == 0)
533 if (HoistStat.second > 0)
549 if (isa<ConstantExpr>(V))
551 if (isa<UndefValue>(V))
553 if (isa<Constant>(V))
555 else if (
auto *
A = dyn_cast<Argument>(V))
556 return 3 +
A->getArgNo();
560 auto Result = DFSNumber.
lookup(V);
562 return 4 + NumFuncArgs + Result;
568 auto It = BBSideEffects.
find(BB);
569 if (It != BBSideEffects.
end())
573 BBSideEffects[BB] =
true;
578 BBSideEffects[BB] =
true;
582 BBSideEffects[BB] =
false;
595 bool ReachedNewPt =
false;
598 if (
const MemoryUse *MU = dyn_cast<MemoryUse>(&MA)) {
602 if (BB == OldBB && firstInBB(OldPt,
Insn))
608 if (firstInBB(
Insn, NewPt))
621 int &NBBsOnAllPaths) {
623 if (NBBsOnAllPaths == 0)
633 if ((BB != SrcBB) && HoistBarrier.
count(BB))
640 int &NBBsOnAllPaths) {
645 "def does not dominate new hoisting point");
659 if (hasEHhelper(BB, OldBB, NBBsOnAllPaths))
663 if (hasMemoryUse(NewPt, Def, BB))
667 if (NBBsOnAllPaths != -1)
677 int &NBBsOnAllPaths) {
693 if (hasEHhelper(BB, SrcBB, NBBsOnAllPaths))
697 if (NBBsOnAllPaths != -1)
706bool GVNHoist::safeToHoistLdSt(
const Instruction *NewPt,
708 GVNHoist::InsKind K,
int &NBBsOnAllPaths) {
725 if (
auto *UD = dyn_cast<MemoryUseOrDef>(
D))
726 if (!firstInBB(UD->getMemoryInst(), NewPt))
731 if (K == InsKind::Store) {
732 if (hasEHOrLoadsOnPath(NewPt, cast<MemoryDef>(U), NBBsOnAllPaths))
734 }
else if (hasEHOnPath(NewBB, OldBB, NBBsOnAllPaths))
773 if (K == InsKind::Scalar) {
774 if (safeToHoistScalar(BB,
Insn->getParent(), NumBBsOnAllPaths))
778 if (safeToHoistLdSt(
T,
Insn, UD, K, NumBBsOnAllPaths))
786 auto it1 = ValueBBs.
find(BB);
787 if (it1 != ValueBBs.
end()) {
790 <<
" for pushing instructions on stack";);
791 for (std::pair<VNType, Instruction *> &VI :
reverse(it1->second)) {
794 RenameStack[
VI.first].push_back(
VI.second);
803 auto P = CHIBBs.
find(Pred);
804 if (
P == CHIBBs.
end()) {
807 LLVM_DEBUG(
dbgs() <<
"\nLooking at CHIs in: " << Pred->getName(););
810 auto &VCHI =
P->second;
811 for (
auto It = VCHI.begin(), E = VCHI.end(); It != E;) {
814 auto si = RenameStack.
find(
C.VN);
818 if (si != RenameStack.
end() && si->second.size() &&
821 C.I = si->second.pop_back_val();
823 <<
"\nCHI Inserted in BB: " <<
C.Dest->getName() << *
C.I
824 <<
", VN: " <<
C.VN.first <<
", " <<
C.VN.second);
827 It = std::find_if(It, VCHI.end(), [It](
CHIArg &
A) { return A != *It; });
852 auto PrevIt = CHIs.
begin();
853 while (PrevIt != PHIIt) {
860 checkSafety(
make_range(PrevIt, PHIIt), BB, K, Safe);
872 PHIIt = std::find_if(PrevIt, CHIs.
end(),
873 [PrevIt](
CHIArg &
A) { return A != *PrevIt; });
878bool GVNHoist::allOperandsAvailable(
const Instruction *
I,
880 for (
const Use &
Op :
I->operands())
881 if (
const auto *Inst = dyn_cast<Instruction>(&
Op))
882 if (!DT->
dominates(Inst->getParent(), HoistPt))
888bool GVNHoist::allGepOperandsAvailable(
const Instruction *
I,
890 for (
const Use &
Op :
I->operands())
891 if (
const auto *Inst = dyn_cast<Instruction>(&
Op))
892 if (!DT->
dominates(Inst->getParent(), HoistPt)) {
894 dyn_cast<GetElementPtrInst>(Inst)) {
895 if (!allGepOperandsAvailable(GepOp, HoistPt))
910 assert(allGepOperandsAvailable(Gep, HoistPt) &&
"GEP operands not available");
922 makeGepsAvailable(ClonedGep, HoistPt, InstructionsToHoist, GepOp);
934 for (
const Instruction *OtherInst : InstructionsToHoist) {
936 if (
auto *OtherLd = dyn_cast<LoadInst>(OtherInst))
937 OtherGep = cast<GetElementPtrInst>(OtherLd->getPointerOperand());
939 OtherGep = cast<GetElementPtrInst>(
946 if (OtherGep != Gep) {
957 if (
auto *ReplacementLoad = dyn_cast<LoadInst>(Repl)) {
958 ReplacementLoad->setAlignment(
959 std::min(ReplacementLoad->getAlign(), cast<LoadInst>(
I)->getAlign()));
961 }
else if (
auto *ReplacementStore = dyn_cast<StoreInst>(Repl)) {
962 ReplacementStore->setAlignment(
963 std::min(ReplacementStore->getAlign(), cast<StoreInst>(
I)->getAlign()));
965 }
else if (
auto *ReplacementAlloca = dyn_cast<AllocaInst>(Repl)) {
966 ReplacementAlloca->setAlignment(std::max(ReplacementAlloca->getAlign(),
967 cast<AllocaInst>(
I)->getAlign()));
968 }
else if (isa<CallInst>(Repl)) {
979 updateAlignment(
I, Repl);
984 MSSAUpdater->removeMemoryAccess(OldMA);
989 I->replaceAllUsesWith(Repl);
992 I->eraseFromParent();
1001 if (
MemoryPhi *Phi = dyn_cast<MemoryPhi>(U))
1005 auto In =
Phi->incoming_values();
1007 Phi->replaceAllUsesWith(NewMemAcc);
1008 MSSAUpdater->removeMemoryAccess(Phi);
1013unsigned GVNHoist::removeAndReplace(
const SmallVecInsn &Candidates,
1017 if (MoveAccess && NewMemAcc) {
1024 unsigned NR = rauw(Candidates, Repl, NewMemAcc);
1028 raMPHIuw(NewMemAcc);
1032bool GVNHoist::makeGepOperandsAvailable(
1038 if (
auto *Ld = dyn_cast<LoadInst>(Repl)) {
1039 Gep = dyn_cast<GetElementPtrInst>(Ld->getPointerOperand());
1040 }
else if (
auto *St = dyn_cast<StoreInst>(Repl)) {
1041 Gep = dyn_cast<GetElementPtrInst>(St->getPointerOperand());
1042 Val = dyn_cast<Instruction>(St->getValueOperand());
1045 if (isa<GetElementPtrInst>(Val)) {
1047 if (!allGepOperandsAvailable(Val, HoistPt))
1055 if (!Gep || !allGepOperandsAvailable(Gep, HoistPt))
1058 makeGepsAvailable(Repl, HoistPt, InstructionsToHoist, Gep);
1060 if (Val && isa<GetElementPtrInst>(Val))
1061 makeGepsAvailable(Repl, HoistPt, InstructionsToHoist, Val);
1067 unsigned NI = 0,
NL = 0, NS = 0,
NC = 0, NR = 0;
1075 if (
I->getParent() == DestBB)
1079 if (!Repl || firstInBB(
I, Repl))
1084 bool MoveAccess =
true;
1087 assert(allOperandsAvailable(Repl, DestBB) &&
1088 "instruction depends on operands that are not available");
1093 Repl = InstructionsToHoist.front();
1098 if (!allOperandsAvailable(Repl, DestBB)) {
1105 if (!makeGepOperandsAvailable(Repl, DestBB, InstructionsToHoist))
1114 DFSNumber[Repl] = DFSNumber[
Last]++;
1119 NR += removeAndReplace(InstructionsToHoist, Repl, DestBB, MoveAccess);
1121 if (isa<LoadInst>(Repl))
1123 else if (isa<StoreInst>(Repl))
1125 else if (isa<CallInst>(Repl))
1134 NumHoisted +=
NL + NS +
NC + NI;
1136 NumLoadsHoisted +=
NL;
1137 NumStoresHoisted += NS;
1138 NumCallsHoisted +=
NC;
1139 return {NI,
NL +
NC + NS};
1142std::pair<unsigned, unsigned> GVNHoist::hoistExpressions(
Function &
F) {
1148 int InstructionNb = 0;
1162 if (
I1.isTerminator())
1165 if (
auto *Load = dyn_cast<LoadInst>(&I1))
1167 else if (
auto *Store = dyn_cast<StoreInst>(&I1))
1168 SI.insert(Store, VN);
1169 else if (
auto *Call = dyn_cast<CallInst>(&I1)) {
1170 if (
auto *
Intr = dyn_cast<IntrinsicInst>(Call)) {
1171 if (isa<DbgInfoIntrinsic>(
Intr) ||
1172 Intr->getIntrinsicID() == Intrinsic::assume ||
1173 Intr->getIntrinsicID() == Intrinsic::sideeffect)
1176 if (
Call->mayHaveSideEffects())
1179 if (
Call->isConvergent())
1183 }
else if (HoistingGeps || !isa<GetElementPtrInst>(&I1))
1193 computeInsertionPoints(
II.getVNTable(), HPL, InsKind::Scalar);
1194 computeInsertionPoints(LI.
getVNTable(), HPL, InsKind::Load);
1195 computeInsertionPoints(
SI.getVNTable(), HPL, InsKind::Store);
SmallVector< AArch64_IMM::ImmInsnModel, 4 > Insn
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
static cl::opt< int > MaxHoistedThreshold("gvn-max-hoisted", cl::Hidden, cl::init(-1), cl::desc("Max number of instructions to hoist " "(default unlimited = -1)"))
static cl::opt< int > MaxChainLength("gvn-hoist-max-chain-length", cl::Hidden, cl::init(10), cl::desc("Maximum length of dependent chains to hoist " "(default = 10, unlimited = -1)"))
static cl::opt< int > MaxDepthInBB("gvn-hoist-max-depth", cl::Hidden, cl::init(100), cl::desc("Hoist instructions from the beginning of the BB up to the " "maximum specified depth (default = 100, unlimited = -1)"))
static cl::opt< int > MaxNumberOfBBSInPath("gvn-hoist-max-bbs", cl::Hidden, cl::init(4), cl::desc("Max number of basic blocks on the path between " "hoisting locations (default = 4, unlimited = -1)"))
This file provides the interface for LLVM's Global Value Numbering pass which eliminates fully redund...
This is the interface for a simple mod/ref and alias analysis over globals.
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
This defines the Use class.
This file exposes an interface to building/using memory SSA to walk memory instructions using a use/d...
uint64_t IntrinsicInst * II
This header defines various interfaces for pass management in LLVM.
static void r2(uint32_t &A, uint32_t &B, uint32_t &C, uint32_t &D, uint32_t &E, int I, uint32_t *Buf)
static void r1(uint32_t &A, uint32_t &B, uint32_t &C, uint32_t &D, uint32_t &E, int I, uint32_t *Buf)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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)
A manager for alias analyses.
A container for analyses that lazily runs them and caches their results.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
bool hasAddressTaken() const
Returns true if there are any uses of this basic block other than direct branches,...
bool isEHPad() const
Return true if this basic block is an exception handling block.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
void insert(CallInst *Call, GVNPass::ValueTable &VN)
const VNtoInsns & getLoadVNTable() const
const VNtoInsns & getScalarVNTable() const
const VNtoInsns & getStoreVNTable() const
This class represents a function call, abstracting a target machine's calling convention.
This class represents an Operation in the Expression.
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
iterator find(const_arg_type_t< KeyT > Val)
Implements a dense probed hash-table based set.
Analysis pass which computes a DominatorTree.
DomTreeNodeBase< NodeT > * getNode(const NodeT *BB) const
getNode - return the (Post)DominatorTree node for the specified basic block.
bool properlyDominates(const DomTreeNodeBase< NodeT > *A, const DomTreeNodeBase< NodeT > *B) const
properlyDominates - Returns true iff A dominates B and A != B.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
GVNHoist(DominatorTree *DT, PostDominatorTree *PDT, AliasAnalysis *AA, MemoryDependenceResults *MD, MemorySSA *MSSA)
unsigned int rank(const Value *V) const
This class holds the mapping between values and value numbers.
uint32_t lookupOrAdd(Value *V)
lookup_or_add - Returns the value number for the specified value, assigning it a new number if it did...
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
const VNtoInsns & getVNTable() const
void insert(Instruction *I, GVNPass::ValueTable &VN)
bool mayThrow(bool IncludePhaseOneUnwind=false) const LLVM_READONLY
Return true if this instruction may throw an exception.
Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
unsigned getNumSuccessors() const LLVM_READONLY
Return the number of successors that this instruction has.
void dropLocation()
Drop the instruction's debug location.
void insertBefore(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified instruction.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
void andIRFlags(const Value *V)
Logical 'and' of any supported wrapping, exact, and fast-math flags of V and this instruction.
void dropUnknownNonDebugMetadata(ArrayRef< unsigned > KnownIDs=std::nullopt)
Drop all unknown metadata except for debug locations.
void applyMergedLocation(DILocation *LocA, DILocation *LocB)
Merge 2 debug locations and apply it to the Instruction.
void moveBefore(Instruction *MovePos)
Unlink this instruction from its current basic block and insert it into the basic block that MovePos ...
const VNtoInsns & getVNTable() const
void insert(LoadInst *Load, GVNPass::ValueTable &VN)
An instruction for reading from memory.
Represents a read-write access to memory, whether it is a must-alias, or a may-alias.
An analysis that produces MemoryDependenceResults for a function.
Provides a lazy, caching interface for making common memory aliasing information queries,...
void removeInstruction(Instruction *InstToRemove)
Removes an instruction from the dependence analysis, updating the dependence of instructions that pre...
Represents phi nodes for memory accesses.
An analysis that produces MemorySSA for a function.
static bool defClobbersUseOrDef(MemoryDef *MD, const MemoryUseOrDef *MU, AliasAnalysis &AA)
Encapsulates MemorySSA, including all data associated with memory accesses.
const AccessList * getBlockAccesses(const BasicBlock *BB) const
Return the list of MemoryAccess's for a given basic block.
void verifyMemorySSA(VerificationLevel=VerificationLevel::Fast) const
Verify that MemorySSA is self consistent (IE definitions dominate all uses, uses appear in the right ...
MemoryUseOrDef * getMemoryAccess(const Instruction *I) const
Given a memory Mod/Ref'ing instruction, get the MemorySSA access associated with it.
void ensureOptimizedUses()
By default, uses are not optimized during MemorySSA construction.
bool locallyDominates(const MemoryAccess *A, const MemoryAccess *B) const
Given two memory accesses in the same basic block, determine whether MemoryAccess A dominates MemoryA...
bool isLiveOnEntryDef(const MemoryAccess *MA) const
Return true if MA represents the live on entry value.
Class that has the common methods + fields of memory uses/defs.
Represents read-only accesses to memory.
Analysis pass which computes a PostDominatorTree.
PostDominatorTree Class - Concrete subclass of DominatorTree that is used to compute the post-dominat...
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.
void preserve()
Mark an analysis as preserved.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
typename SuperClass::iterator iterator
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
void insert(StoreInst *Store, GVNPass::ValueTable &VN)
const VNtoInsns & getVNTable() const
An instruction for storing to memory.
A Use represents the edge between a Value definition and its users.
bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Value * getOperand(unsigned i) const
unsigned getNumOperands() const
LLVM Value Representation.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
const ParentTy * getParent() const
An intrusive list with ownership and callbacks specified/controlled by ilist_traits,...
A range adaptor for a pair of iterators.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
@ C
The default llvm calling convention, compatible with C.
initializer< Ty > init(const Ty &Val)
NodeAddr< PhiNode * > Phi
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
void stable_sort(R &&Range)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
auto successors(const MachineBasicBlock *BB)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
std::pair< BasicBlock *, SmallVecInsn > HoistingPointInfo
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
SmallVectorImpl< CHIArg >::iterator CHIIt
idf_iterator< T > idf_end(const T &G)
void combineMetadataForCSE(Instruction *K, const Instruction *J, bool DoesKMove)
Combine the metadata of two instructions so that K can replace J.
bool VerifyMemorySSA
Enables verification of MemorySSA.
idf_iterator< T > idf_begin(const T &G)
bool isGuaranteedToTransferExecutionToSuccessor(const Instruction *I)
Return true if this function can prove that the instruction I will always transfer execution to one o...
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
auto predecessors(const MachineBasicBlock *BB)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
SmallVector< Instruction *, 4 > SmallVecInsn
iterator_range< df_iterator< T > > depth_first(const T &G)
std::pair< unsigned, uintptr_t > VNType
Implement std::hash so that hash_code can be used in STL containers.
bool operator!=(const CHIArg &A) const
bool operator==(const CHIArg &A) const
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Run the pass over the function.
Utility type to build an inheritance chain that makes it easy to rank overload candidates.