| //===- llvm/Analysis/AliasSetTracker.h - Build Alias Sets -------*- C++ -*-===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file defines two classes: AliasSetTracker and AliasSet. These interface | |
| // are used to classify a collection of pointer references into a maximal number | |
| // of disjoint sets. Each AliasSet object constructed by the AliasSetTracker | |
| // object refers to memory disjoint from the other sets. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_ANALYSIS_ALIASSETTRACKER_H | |
| #define LLVM_ANALYSIS_ALIASSETTRACKER_H | |
| #include "llvm/Support/CallSite.h" | |
| #include "llvm/Support/ValueHandle.h" | |
| #include "llvm/ADT/DenseMap.h" | |
| #include "llvm/ADT/ilist.h" | |
| #include "llvm/ADT/ilist_node.h" | |
| #include <vector> | |
| namespace llvm { | |
| class AliasAnalysis; | |
| class LoadInst; | |
| class StoreInst; | |
| class VAArgInst; | |
| class AliasSetTracker; | |
| class AliasSet; | |
| class AliasSet : public ilist_node<AliasSet> { | |
| friend class AliasSetTracker; | |
| class PointerRec { | |
| Value *Val; // The pointer this record corresponds to. | |
| PointerRec **PrevInList, *NextInList; | |
| AliasSet *AS; | |
| uint64_t Size; | |
| const MDNode *TBAAInfo; | |
| public: | |
| PointerRec(Value *V) | |
| : Val(V), PrevInList(0), NextInList(0), AS(0), Size(0), | |
| TBAAInfo(DenseMapInfo<const MDNode *>::getEmptyKey()) {} | |
| Value *getValue() const { return Val; } | |
| PointerRec *getNext() const { return NextInList; } | |
| bool hasAliasSet() const { return AS != 0; } | |
| PointerRec** setPrevInList(PointerRec **PIL) { | |
| PrevInList = PIL; | |
| return &NextInList; | |
| } | |
| void updateSizeAndTBAAInfo(uint64_t NewSize, const MDNode *NewTBAAInfo) { | |
| if (NewSize > Size) Size = NewSize; | |
| if (TBAAInfo == DenseMapInfo<const MDNode *>::getEmptyKey()) | |
| // We don't have a TBAAInfo yet. Set it to NewTBAAInfo. | |
| TBAAInfo = NewTBAAInfo; | |
| else if (TBAAInfo != NewTBAAInfo) | |
| // NewTBAAInfo conflicts with TBAAInfo. | |
| TBAAInfo = DenseMapInfo<const MDNode *>::getTombstoneKey(); | |
| } | |
| uint64_t getSize() const { return Size; } | |
| /// getTBAAInfo - Return the TBAAInfo, or null if there is no | |
| /// information or conflicting information. | |
| const MDNode *getTBAAInfo() const { | |
| // If we have missing or conflicting TBAAInfo, return null. | |
| if (TBAAInfo == DenseMapInfo<const MDNode *>::getEmptyKey() || | |
| TBAAInfo == DenseMapInfo<const MDNode *>::getTombstoneKey()) | |
| return 0; | |
| return TBAAInfo; | |
| } | |
| AliasSet *getAliasSet(AliasSetTracker &AST) { | |
| assert(AS && "No AliasSet yet!"); | |
| if (AS->Forward) { | |
| AliasSet *OldAS = AS; | |
| AS = OldAS->getForwardedTarget(AST); | |
| AS->addRef(); | |
| OldAS->dropRef(AST); | |
| } | |
| return AS; | |
| } | |
| void setAliasSet(AliasSet *as) { | |
| assert(AS == 0 && "Already have an alias set!"); | |
| AS = as; | |
| } | |
| void eraseFromList() { | |
| if (NextInList) NextInList->PrevInList = PrevInList; | |
| *PrevInList = NextInList; | |
| if (AS->PtrListEnd == &NextInList) { | |
| AS->PtrListEnd = PrevInList; | |
| assert(*AS->PtrListEnd == 0 && "List not terminated right!"); | |
| } | |
| delete this; | |
| } | |
| }; | |
| PointerRec *PtrList, **PtrListEnd; // Doubly linked list of nodes. | |
| AliasSet *Forward; // Forwarding pointer. | |
| AliasSet *Next, *Prev; // Doubly linked list of AliasSets. | |
| // All instructions without a specific address in this alias set. | |
| std::vector<AssertingVH<Instruction> > UnknownInsts; | |
| // RefCount - Number of nodes pointing to this AliasSet plus the number of | |
| // AliasSets forwarding to it. | |
| unsigned RefCount : 28; | |
| /// AccessType - Keep track of whether this alias set merely refers to the | |
| /// locations of memory, whether it modifies the memory, or whether it does | |
| /// both. The lattice goes from "NoModRef" to either Refs or Mods, then to | |
| /// ModRef as necessary. | |
| /// | |
| enum AccessType { | |
| NoModRef = 0, Refs = 1, // Ref = bit 1 | |
| Mods = 2, ModRef = 3 // Mod = bit 2 | |
| }; | |
| unsigned AccessTy : 2; | |
| /// AliasType - Keep track the relationships between the pointers in the set. | |
| /// Lattice goes from MustAlias to MayAlias. | |
| /// | |
| enum AliasType { | |
| MustAlias = 0, MayAlias = 1 | |
| }; | |
| unsigned AliasTy : 1; | |
| // Volatile - True if this alias set contains volatile loads or stores. | |
| bool Volatile : 1; | |
| void addRef() { ++RefCount; } | |
| void dropRef(AliasSetTracker &AST) { | |
| assert(RefCount >= 1 && "Invalid reference count detected!"); | |
| if (--RefCount == 0) | |
| removeFromTracker(AST); | |
| } | |
| Instruction *getUnknownInst(unsigned i) const { | |
| assert(i < UnknownInsts.size()); | |
| return UnknownInsts[i]; | |
| } | |
| public: | |
| /// Accessors... | |
| bool isRef() const { return AccessTy & Refs; } | |
| bool isMod() const { return AccessTy & Mods; } | |
| bool isMustAlias() const { return AliasTy == MustAlias; } | |
| bool isMayAlias() const { return AliasTy == MayAlias; } | |
| // isVolatile - Return true if this alias set contains volatile loads or | |
| // stores. | |
| bool isVolatile() const { return Volatile; } | |
| /// isForwardingAliasSet - Return true if this alias set should be ignored as | |
| /// part of the AliasSetTracker object. | |
| bool isForwardingAliasSet() const { return Forward; } | |
| /// mergeSetIn - Merge the specified alias set into this alias set... | |
| /// | |
| void mergeSetIn(AliasSet &AS, AliasSetTracker &AST); | |
| // Alias Set iteration - Allow access to all of the pointer which are part of | |
| // this alias set... | |
| class iterator; | |
| iterator begin() const { return iterator(PtrList); } | |
| iterator end() const { return iterator(); } | |
| bool empty() const { return PtrList == 0; } | |
| void print(raw_ostream &OS) const; | |
| void dump() const; | |
| /// Define an iterator for alias sets... this is just a forward iterator. | |
| class iterator : public std::iterator<std::forward_iterator_tag, | |
| PointerRec, ptrdiff_t> { | |
| PointerRec *CurNode; | |
| public: | |
| explicit iterator(PointerRec *CN = 0) : CurNode(CN) {} | |
| bool operator==(const iterator& x) const { | |
| return CurNode == x.CurNode; | |
| } | |
| bool operator!=(const iterator& x) const { return !operator==(x); } | |
| const iterator &operator=(const iterator &I) { | |
| CurNode = I.CurNode; | |
| return *this; | |
| } | |
| value_type &operator*() const { | |
| assert(CurNode && "Dereferencing AliasSet.end()!"); | |
| return *CurNode; | |
| } | |
| value_type *operator->() const { return &operator*(); } | |
| Value *getPointer() const { return CurNode->getValue(); } | |
| uint64_t getSize() const { return CurNode->getSize(); } | |
| const MDNode *getTBAAInfo() const { return CurNode->getTBAAInfo(); } | |
| iterator& operator++() { // Preincrement | |
| assert(CurNode && "Advancing past AliasSet.end()!"); | |
| CurNode = CurNode->getNext(); | |
| return *this; | |
| } | |
| iterator operator++(int) { // Postincrement | |
| iterator tmp = *this; ++*this; return tmp; | |
| } | |
| }; | |
| private: | |
| // Can only be created by AliasSetTracker. Also, ilist creates one | |
| // to serve as a sentinel. | |
| friend struct ilist_sentinel_traits<AliasSet>; | |
| AliasSet() : PtrList(0), PtrListEnd(&PtrList), Forward(0), RefCount(0), | |
| AccessTy(NoModRef), AliasTy(MustAlias), Volatile(false) { | |
| } | |
| AliasSet(const AliasSet &AS); // do not implement | |
| void operator=(const AliasSet &AS); // do not implement | |
| PointerRec *getSomePointer() const { | |
| return PtrList; | |
| } | |
| /// getForwardedTarget - Return the real alias set this represents. If this | |
| /// has been merged with another set and is forwarding, return the ultimate | |
| /// destination set. This also implements the union-find collapsing as well. | |
| AliasSet *getForwardedTarget(AliasSetTracker &AST) { | |
| if (!Forward) return this; | |
| AliasSet *Dest = Forward->getForwardedTarget(AST); | |
| if (Dest != Forward) { | |
| Dest->addRef(); | |
| Forward->dropRef(AST); | |
| Forward = Dest; | |
| } | |
| return Dest; | |
| } | |
| void removeFromTracker(AliasSetTracker &AST); | |
| void addPointer(AliasSetTracker &AST, PointerRec &Entry, uint64_t Size, | |
| const MDNode *TBAAInfo, | |
| bool KnownMustAlias = false); | |
| void addUnknownInst(Instruction *I, AliasAnalysis &AA); | |
| void removeUnknownInst(Instruction *I) { | |
| for (size_t i = 0, e = UnknownInsts.size(); i != e; ++i) | |
| if (UnknownInsts[i] == I) { | |
| UnknownInsts[i] = UnknownInsts.back(); | |
| UnknownInsts.pop_back(); | |
| --i; --e; // Revisit the moved entry. | |
| } | |
| } | |
| void setVolatile() { Volatile = true; } | |
| /// aliasesPointer - Return true if the specified pointer "may" (or must) | |
| /// alias one of the members in the set. | |
| /// | |
| bool aliasesPointer(const Value *Ptr, uint64_t Size, const MDNode *TBAAInfo, | |
| AliasAnalysis &AA) const; | |
| bool aliasesUnknownInst(Instruction *Inst, AliasAnalysis &AA) const; | |
| }; | |
| inline raw_ostream& operator<<(raw_ostream &OS, const AliasSet &AS) { | |
| AS.print(OS); | |
| return OS; | |
| } | |
| class AliasSetTracker { | |
| /// CallbackVH - A CallbackVH to arrange for AliasSetTracker to be | |
| /// notified whenever a Value is deleted. | |
| class ASTCallbackVH : public CallbackVH { | |
| AliasSetTracker *AST; | |
| virtual void deleted(); | |
| virtual void allUsesReplacedWith(Value *); | |
| public: | |
| ASTCallbackVH(Value *V, AliasSetTracker *AST = 0); | |
| ASTCallbackVH &operator=(Value *V); | |
| }; | |
| /// ASTCallbackVHDenseMapInfo - Traits to tell DenseMap that tell us how to | |
| /// compare and hash the value handle. | |
| struct ASTCallbackVHDenseMapInfo : public DenseMapInfo<Value *> {}; | |
| AliasAnalysis &AA; | |
| ilist<AliasSet> AliasSets; | |
| typedef DenseMap<ASTCallbackVH, AliasSet::PointerRec*, | |
| ASTCallbackVHDenseMapInfo> | |
| PointerMapType; | |
| // Map from pointers to their node | |
| PointerMapType PointerMap; | |
| public: | |
| /// AliasSetTracker ctor - Create an empty collection of AliasSets, and use | |
| /// the specified alias analysis object to disambiguate load and store | |
| /// addresses. | |
| explicit AliasSetTracker(AliasAnalysis &aa) : AA(aa) {} | |
| ~AliasSetTracker() { clear(); } | |
| /// add methods - These methods are used to add different types of | |
| /// instructions to the alias sets. Adding a new instruction can result in | |
| /// one of three actions happening: | |
| /// | |
| /// 1. If the instruction doesn't alias any other sets, create a new set. | |
| /// 2. If the instruction aliases exactly one set, add it to the set | |
| /// 3. If the instruction aliases multiple sets, merge the sets, and add | |
| /// the instruction to the result. | |
| /// | |
| /// These methods return true if inserting the instruction resulted in the | |
| /// addition of a new alias set (i.e., the pointer did not alias anything). | |
| /// | |
| bool add(Value *Ptr, uint64_t Size, const MDNode *TBAAInfo); // Add a location | |
| bool add(LoadInst *LI); | |
| bool add(StoreInst *SI); | |
| bool add(VAArgInst *VAAI); | |
| bool add(Instruction *I); // Dispatch to one of the other add methods... | |
| void add(BasicBlock &BB); // Add all instructions in basic block | |
| void add(const AliasSetTracker &AST); // Add alias relations from another AST | |
| bool addUnknown(Instruction *I); | |
| /// remove methods - These methods are used to remove all entries that might | |
| /// be aliased by the specified instruction. These methods return true if any | |
| /// alias sets were eliminated. | |
| // Remove a location | |
| bool remove(Value *Ptr, uint64_t Size, const MDNode *TBAAInfo); | |
| bool remove(LoadInst *LI); | |
| bool remove(StoreInst *SI); | |
| bool remove(VAArgInst *VAAI); | |
| bool remove(Instruction *I); | |
| void remove(AliasSet &AS); | |
| bool removeUnknown(Instruction *I); | |
| void clear(); | |
| /// getAliasSets - Return the alias sets that are active. | |
| /// | |
| const ilist<AliasSet> &getAliasSets() const { return AliasSets; } | |
| /// getAliasSetForPointer - Return the alias set that the specified pointer | |
| /// lives in. If the New argument is non-null, this method sets the value to | |
| /// true if a new alias set is created to contain the pointer (because the | |
| /// pointer didn't alias anything). | |
| AliasSet &getAliasSetForPointer(Value *P, uint64_t Size, | |
| const MDNode *TBAAInfo, | |
| bool *New = 0); | |
| /// getAliasSetForPointerIfExists - Return the alias set containing the | |
| /// location specified if one exists, otherwise return null. | |
| AliasSet *getAliasSetForPointerIfExists(Value *P, uint64_t Size, | |
| const MDNode *TBAAInfo) { | |
| return findAliasSetForPointer(P, Size, TBAAInfo); | |
| } | |
| /// containsPointer - Return true if the specified location is represented by | |
| /// this alias set, false otherwise. This does not modify the AST object or | |
| /// alias sets. | |
| bool containsPointer(Value *P, uint64_t Size, const MDNode *TBAAInfo) const; | |
| /// getAliasAnalysis - Return the underlying alias analysis object used by | |
| /// this tracker. | |
| AliasAnalysis &getAliasAnalysis() const { return AA; } | |
| /// deleteValue method - This method is used to remove a pointer value from | |
| /// the AliasSetTracker entirely. It should be used when an instruction is | |
| /// deleted from the program to update the AST. If you don't use this, you | |
| /// would have dangling pointers to deleted instructions. | |
| /// | |
| void deleteValue(Value *PtrVal); | |
| /// copyValue - This method should be used whenever a preexisting value in the | |
| /// program is copied or cloned, introducing a new value. Note that it is ok | |
| /// for clients that use this method to introduce the same value multiple | |
| /// times: if the tracker already knows about a value, it will ignore the | |
| /// request. | |
| /// | |
| void copyValue(Value *From, Value *To); | |
| typedef ilist<AliasSet>::iterator iterator; | |
| typedef ilist<AliasSet>::const_iterator const_iterator; | |
| const_iterator begin() const { return AliasSets.begin(); } | |
| const_iterator end() const { return AliasSets.end(); } | |
| iterator begin() { return AliasSets.begin(); } | |
| iterator end() { return AliasSets.end(); } | |
| void print(raw_ostream &OS) const; | |
| void dump() const; | |
| private: | |
| friend class AliasSet; | |
| void removeAliasSet(AliasSet *AS); | |
| // getEntryFor - Just like operator[] on the map, except that it creates an | |
| // entry for the pointer if it doesn't already exist. | |
| AliasSet::PointerRec &getEntryFor(Value *V) { | |
| AliasSet::PointerRec *&Entry = PointerMap[ASTCallbackVH(V, this)]; | |
| if (Entry == 0) | |
| Entry = new AliasSet::PointerRec(V); | |
| return *Entry; | |
| } | |
| AliasSet &addPointer(Value *P, uint64_t Size, const MDNode *TBAAInfo, | |
| AliasSet::AccessType E, | |
| bool &NewSet) { | |
| NewSet = false; | |
| AliasSet &AS = getAliasSetForPointer(P, Size, TBAAInfo, &NewSet); | |
| AS.AccessTy |= E; | |
| return AS; | |
| } | |
| AliasSet *findAliasSetForPointer(const Value *Ptr, uint64_t Size, | |
| const MDNode *TBAAInfo); | |
| AliasSet *findAliasSetForUnknownInst(Instruction *Inst); | |
| }; | |
| inline raw_ostream& operator<<(raw_ostream &OS, const AliasSetTracker &AST) { | |
| AST.print(OS); | |
| return OS; | |
| } | |
| } // End llvm namespace | |
| #endif |