Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 1 | //===- llvm/Analysis/AliasSetTracker.h - Build Alias Sets -------*- C++ -*-===// | 
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file defines two classes: AliasSetTracker and AliasSet. These interfaces | ||
| 10 | // are used to classify a collection of pointer references into a maximal number | ||
| 11 | // of disjoint sets. Each AliasSet object constructed by the AliasSetTracker | ||
| 12 | // object refers to memory disjoint from the other sets. | ||
| 13 | // | ||
| 14 | // An AliasSetTracker can only be used on immutable IR. | ||
| 15 | // | ||
| 16 | //===----------------------------------------------------------------------===// | ||
| 17 | |||
| 18 | #ifndef LLVM_ANALYSIS_ALIASSETTRACKER_H | ||
| 19 | #define LLVM_ANALYSIS_ALIASSETTRACKER_H | ||
| 20 | |||
| 21 | #include "llvm/ADT/DenseMap.h" | ||
| 22 | #include "llvm/ADT/DenseMapInfo.h" | ||
| 23 | #include "llvm/ADT/ilist.h" | ||
| 24 | #include "llvm/ADT/ilist_node.h" | ||
| 25 | #include "llvm/Analysis/MemoryLocation.h" | ||
| 26 | #include "llvm/IR/Instruction.h" | ||
| 27 | #include "llvm/IR/PassManager.h" | ||
| 28 | #include "llvm/IR/ValueHandle.h" | ||
| 29 | #include <cassert> | ||
| 30 | #include <cstddef> | ||
| 31 | #include <iterator> | ||
| 32 | #include <vector> | ||
| 33 | |||
| 34 | namespace llvm { | ||
| 35 | |||
| 36 | class AliasResult; | ||
| 37 | class AliasSetTracker; | ||
| 38 | class AnyMemSetInst; | ||
| 39 | class AnyMemTransferInst; | ||
| 40 | class BasicBlock; | ||
| 41 | class BatchAAResults; | ||
| 42 | class LoadInst; | ||
| 43 | enum class ModRefInfo : uint8_t; | ||
| 44 | class raw_ostream; | ||
| 45 | class StoreInst; | ||
| 46 | class VAArgInst; | ||
| 47 | class Value; | ||
| 48 | |||
| 49 | class AliasSet : public ilist_node<AliasSet> { | ||
| 50 | friend class AliasSetTracker; | ||
| 51 | |||
| 52 | class PointerRec { | ||
| 53 | Value *Val; // The pointer this record corresponds to. | ||
| 54 | PointerRec **PrevInList = nullptr; | ||
| 55 | PointerRec *NextInList = nullptr; | ||
| 56 | AliasSet *AS = nullptr; | ||
| 57 | LocationSize Size = LocationSize::mapEmpty(); | ||
| 58 |     AAMDNodes AAInfo; | ||
| 59 | |||
| 60 |     // Whether the size for this record has been set at all. This makes no | ||
| 61 |     // guarantees about the size being known. | ||
| 62 | bool isSizeSet() const { return Size != LocationSize::mapEmpty(); } | ||
| 63 | |||
| 64 | public: | ||
| 65 | PointerRec(Value *V) | ||
| 66 | : Val(V), AAInfo(DenseMapInfo<AAMDNodes>::getEmptyKey()) {} | ||
| 67 | |||
| 68 | Value *getValue() const { return Val; } | ||
| 69 | |||
| 70 | PointerRec *getNext() const { return NextInList; } | ||
| 71 | bool hasAliasSet() const { return AS != nullptr; } | ||
| 72 | |||
| 73 | PointerRec** setPrevInList(PointerRec **PIL) { | ||
| 74 | PrevInList = PIL; | ||
| 75 | return &NextInList; | ||
| 76 |     } | ||
| 77 | |||
| 78 | bool updateSizeAndAAInfo(LocationSize NewSize, const AAMDNodes &NewAAInfo) { | ||
| 79 | bool SizeChanged = false; | ||
| 80 | if (NewSize != Size) { | ||
| 81 | LocationSize OldSize = Size; | ||
| 82 | Size = isSizeSet() ? Size.unionWith(NewSize) : NewSize; | ||
| 83 | SizeChanged = OldSize != Size; | ||
| 84 |       } | ||
| 85 | |||
| 86 | if (AAInfo == DenseMapInfo<AAMDNodes>::getEmptyKey()) | ||
| 87 |         // We don't have a AAInfo yet. Set it to NewAAInfo. | ||
| 88 | AAInfo = NewAAInfo; | ||
| 89 | else { | ||
| 90 | AAMDNodes Intersection(AAInfo.intersect(NewAAInfo)); | ||
| 91 | SizeChanged |= Intersection != AAInfo; | ||
| 92 | AAInfo = Intersection; | ||
| 93 |       } | ||
| 94 | return SizeChanged; | ||
| 95 |     } | ||
| 96 | |||
| 97 | LocationSize getSize() const { | ||
| 98 | assert(isSizeSet() && "Getting an unset size!"); | ||
| 99 | return Size; | ||
| 100 |     } | ||
| 101 | |||
| 102 |     /// Return the AAInfo, or null if there is no information or conflicting | ||
| 103 |     /// information. | ||
| 104 | AAMDNodes getAAInfo() const { | ||
| 105 |       // If we have missing or conflicting AAInfo, return null. | ||
| 106 | if (AAInfo == DenseMapInfo<AAMDNodes>::getEmptyKey() || | ||
| 107 | AAInfo == DenseMapInfo<AAMDNodes>::getTombstoneKey()) | ||
| 108 | return AAMDNodes(); | ||
| 109 | return AAInfo; | ||
| 110 |     } | ||
| 111 | |||
| 112 | AliasSet *getAliasSet(AliasSetTracker &AST) { | ||
| 113 | assert(AS && "No AliasSet yet!"); | ||
| 114 | if (AS->Forward) { | ||
| 115 | AliasSet *OldAS = AS; | ||
| 116 | AS = OldAS->getForwardedTarget(AST); | ||
| 117 | AS->addRef(); | ||
| 118 | OldAS->dropRef(AST); | ||
| 119 |       } | ||
| 120 | return AS; | ||
| 121 |     } | ||
| 122 | |||
| 123 | void setAliasSet(AliasSet *as) { | ||
| 124 | assert(!AS && "Already have an alias set!"); | ||
| 125 | AS = as; | ||
| 126 |     } | ||
| 127 | |||
| 128 | void eraseFromList() { | ||
| 129 | if (NextInList) NextInList->PrevInList = PrevInList; | ||
| 130 | *PrevInList = NextInList; | ||
| 131 | if (AS->PtrListEnd == &NextInList) { | ||
| 132 | AS->PtrListEnd = PrevInList; | ||
| 133 | assert(*AS->PtrListEnd == nullptr && "List not terminated right!"); | ||
| 134 |       } | ||
| 135 | delete this; | ||
| 136 |     } | ||
| 137 | }; | ||
| 138 | |||
| 139 |   // Doubly linked list of nodes. | ||
| 140 | PointerRec *PtrList = nullptr; | ||
| 141 | PointerRec **PtrListEnd; | ||
| 142 |   // Forwarding pointer. | ||
| 143 | AliasSet *Forward = nullptr; | ||
| 144 | |||
| 145 |   /// All instructions without a specific address in this alias set. | ||
| 146 | std::vector<AssertingVH<Instruction>> UnknownInsts; | ||
| 147 | |||
| 148 |   /// Number of nodes pointing to this AliasSet plus the number of AliasSets | ||
| 149 |   /// forwarding to it. | ||
| 150 | unsigned RefCount : 27; | ||
| 151 | |||
| 152 |   // Signifies that this set should be considered to alias any pointer. | ||
| 153 |   // Use when the tracker holding this set is saturated. | ||
| 154 | unsigned AliasAny : 1; | ||
| 155 | |||
| 156 |   /// The kinds of access this alias set models. | ||
| 157 |   /// | ||
| 158 |   /// We keep track of whether this alias set merely refers to the locations of | ||
| 159 |   /// memory (and not any particular access), whether it modifies or references | ||
| 160 |   /// the memory, or whether it does both. The lattice goes from "NoAccess" to | ||
| 161 |   /// either RefAccess or ModAccess, then to ModRefAccess as necessary. | ||
| 162 | enum AccessLattice { | ||
| 163 | NoAccess = 0, | ||
| 164 | RefAccess = 1, | ||
| 165 | ModAccess = 2, | ||
| 166 | ModRefAccess = RefAccess | ModAccess | ||
| 167 | }; | ||
| 168 | unsigned Access : 2; | ||
| 169 | |||
| 170 |   /// The kind of alias relationship between pointers of the set. | ||
| 171 |   /// | ||
| 172 |   /// These represent conservatively correct alias results between any members | ||
| 173 |   /// of the set. We represent these independently of the values of alias | ||
| 174 |   /// results in order to pack it into a single bit. Lattice goes from | ||
| 175 |   /// MustAlias to MayAlias. | ||
| 176 | enum AliasLattice { | ||
| 177 | SetMustAlias = 0, SetMayAlias = 1 | ||
| 178 | }; | ||
| 179 | unsigned Alias : 1; | ||
| 180 | |||
| 181 | unsigned SetSize = 0; | ||
| 182 | |||
| 183 | void addRef() { ++RefCount; } | ||
| 184 | |||
| 185 | void dropRef(AliasSetTracker &AST) { | ||
| 186 | assert(RefCount >= 1 && "Invalid reference count detected!"); | ||
| 187 | if (--RefCount == 0) | ||
| 188 | removeFromTracker(AST); | ||
| 189 |   } | ||
| 190 | |||
| 191 | public: | ||
| 192 | AliasSet(const AliasSet &) = delete; | ||
| 193 | AliasSet &operator=(const AliasSet &) = delete; | ||
| 194 | |||
| 195 |   /// Accessors... | ||
| 196 | bool isRef() const { return Access & RefAccess; } | ||
| 197 | bool isMod() const { return Access & ModAccess; } | ||
| 198 | bool isMustAlias() const { return Alias == SetMustAlias; } | ||
| 199 | bool isMayAlias() const { return Alias == SetMayAlias; } | ||
| 200 | |||
| 201 |   /// Return true if this alias set should be ignored as part of the | ||
| 202 |   /// AliasSetTracker object. | ||
| 203 | bool isForwardingAliasSet() const { return Forward; } | ||
| 204 | |||
| 205 |   /// Merge the specified alias set into this alias set. | ||
| 206 | void mergeSetIn(AliasSet &AS, AliasSetTracker &AST, BatchAAResults &BatchAA); | ||
| 207 | |||
| 208 |   // Alias Set iteration - Allow access to all of the pointers which are part of | ||
| 209 |   // this alias set. | ||
| 210 | class iterator; | ||
| 211 | iterator begin() const { return iterator(PtrList); } | ||
| 212 | iterator end() const { return iterator(); } | ||
| 213 | bool empty() const { return PtrList == nullptr; } | ||
| 214 | |||
| 215 |   // Unfortunately, ilist::size() is linear, so we have to add code to keep | ||
| 216 |   // track of the list's exact size. | ||
| 217 | unsigned size() { return SetSize; } | ||
| 218 | |||
| 219 | void print(raw_ostream &OS) const; | ||
| 220 | void dump() const; | ||
| 221 | |||
| 222 |   /// Define an iterator for alias sets... this is just a forward iterator. | ||
| 223 | class iterator { | ||
| 224 | PointerRec *CurNode; | ||
| 225 | |||
| 226 | public: | ||
| 227 | using iterator_category = std::forward_iterator_tag; | ||
| 228 | using value_type = PointerRec; | ||
| 229 | using difference_type = std::ptrdiff_t; | ||
| 230 | using pointer = value_type *; | ||
| 231 | using reference = value_type &; | ||
| 232 | |||
| 233 | explicit iterator(PointerRec *CN = nullptr) : CurNode(CN) {} | ||
| 234 | |||
| 235 | bool operator==(const iterator& x) const { | ||
| 236 | return CurNode == x.CurNode; | ||
| 237 |     } | ||
| 238 | bool operator!=(const iterator& x) const { return !operator==(x); } | ||
| 239 | |||
| 240 | value_type &operator*() const { | ||
| 241 | assert(CurNode && "Dereferencing AliasSet.end()!"); | ||
| 242 | return *CurNode; | ||
| 243 |     } | ||
| 244 | value_type *operator->() const { return &operator*(); } | ||
| 245 | |||
| 246 | Value *getPointer() const { return CurNode->getValue(); } | ||
| 247 | LocationSize getSize() const { return CurNode->getSize(); } | ||
| 248 | AAMDNodes getAAInfo() const { return CurNode->getAAInfo(); } | ||
| 249 | |||
| 250 | iterator& operator++() { // Preincrement | ||
| 251 | assert(CurNode && "Advancing past AliasSet.end()!"); | ||
| 252 | CurNode = CurNode->getNext(); | ||
| 253 | return *this; | ||
| 254 |     } | ||
| 255 | iterator operator++(int) { // Postincrement | ||
| 256 | iterator tmp = *this; ++*this; return tmp; | ||
| 257 |     } | ||
| 258 | }; | ||
| 259 | |||
| 260 | private: | ||
| 261 |   // Can only be created by AliasSetTracker. | ||
| 262 | AliasSet() | ||
| 263 | : PtrListEnd(&PtrList), RefCount(0), AliasAny(false), Access(NoAccess), | ||
| 264 | Alias(SetMustAlias) {} | ||
| 265 | |||
| 266 | PointerRec *getSomePointer() const { | ||
| 267 | return PtrList; | ||
| 268 |   } | ||
| 269 | |||
| 270 |   /// Return the real alias set this represents. If this has been merged with | ||
| 271 |   /// another set and is forwarding, return the ultimate destination set. This | ||
| 272 |   /// also implements the union-find collapsing as well. | ||
| 273 | AliasSet *getForwardedTarget(AliasSetTracker &AST) { | ||
| 274 | if (!Forward) return this; | ||
| 275 | |||
| 276 | AliasSet *Dest = Forward->getForwardedTarget(AST); | ||
| 277 | if (Dest != Forward) { | ||
| 278 | Dest->addRef(); | ||
| 279 | Forward->dropRef(AST); | ||
| 280 | Forward = Dest; | ||
| 281 |     } | ||
| 282 | return Dest; | ||
| 283 |   } | ||
| 284 | |||
| 285 | void removeFromTracker(AliasSetTracker &AST); | ||
| 286 | |||
| 287 | void addPointer(AliasSetTracker &AST, PointerRec &Entry, LocationSize Size, | ||
| 288 | const AAMDNodes &AAInfo, bool KnownMustAlias = false, | ||
| 289 | bool SkipSizeUpdate = false); | ||
| 290 | void addUnknownInst(Instruction *I, BatchAAResults &AA); | ||
| 291 | |||
| 292 | public: | ||
| 293 |   /// If the specified pointer "may" (or must) alias one of the members in the | ||
| 294 |   /// set return the appropriate AliasResult. Otherwise return NoAlias. | ||
| 295 | AliasResult aliasesPointer(const Value *Ptr, LocationSize Size, | ||
| 296 | const AAMDNodes &AAInfo, BatchAAResults &AA) const; | ||
| 297 | ModRefInfo aliasesUnknownInst(const Instruction *Inst, | ||
| 298 | BatchAAResults &AA) const; | ||
| 299 | }; | ||
| 300 | |||
| 301 | inline raw_ostream& operator<<(raw_ostream &OS, const AliasSet &AS) { | ||
| 302 | AS.print(OS); | ||
| 303 | return OS; | ||
| 304 | } | ||
| 305 | |||
| 306 | class AliasSetTracker { | ||
| 307 | BatchAAResults &AA; | ||
| 308 | ilist<AliasSet> AliasSets; | ||
| 309 | |||
| 310 | using PointerMapType = DenseMap<AssertingVH<Value>, AliasSet::PointerRec *>; | ||
| 311 | |||
| 312 |   // Map from pointers to their node | ||
| 313 |   PointerMapType PointerMap; | ||
| 314 | |||
| 315 | public: | ||
| 316 |   /// Create an empty collection of AliasSets, and use the specified alias | ||
| 317 |   /// analysis object to disambiguate load and store addresses. | ||
| 318 | explicit AliasSetTracker(BatchAAResults &AA) : AA(AA) {} | ||
| 319 | ~AliasSetTracker() { clear(); } | ||
| 320 | |||
| 321 |   /// These methods are used to add different types of instructions to the alias | ||
| 322 |   /// sets. Adding a new instruction can result in one of three actions | ||
| 323 |   /// happening: | ||
| 324 |   /// | ||
| 325 |   ///   1. If the instruction doesn't alias any other sets, create a new set. | ||
| 326 |   ///   2. If the instruction aliases exactly one set, add it to the set | ||
| 327 |   ///   3. If the instruction aliases multiple sets, merge the sets, and add | ||
| 328 |   ///      the instruction to the result. | ||
| 329 |   /// | ||
| 330 |   /// These methods return true if inserting the instruction resulted in the | ||
| 331 |   /// addition of a new alias set (i.e., the pointer did not alias anything). | ||
| 332 |   /// | ||
| 333 | void add(Value *Ptr, LocationSize Size, const AAMDNodes &AAInfo); // Add a loc | ||
| 334 | void add(LoadInst *LI); | ||
| 335 | void add(StoreInst *SI); | ||
| 336 | void add(VAArgInst *VAAI); | ||
| 337 | void add(AnyMemSetInst *MSI); | ||
| 338 | void add(AnyMemTransferInst *MTI); | ||
| 339 | void add(Instruction *I); // Dispatch to one of the other add methods... | ||
| 340 | void add(BasicBlock &BB); // Add all instructions in basic block | ||
| 341 | void add(const AliasSetTracker &AST); // Add alias relations from another AST | ||
| 342 | void addUnknown(Instruction *I); | ||
| 343 | |||
| 344 | void clear(); | ||
| 345 | |||
| 346 |   /// Return the alias sets that are active. | ||
| 347 | const ilist<AliasSet> &getAliasSets() const { return AliasSets; } | ||
| 348 | |||
| 349 |   /// Return the alias set which contains the specified memory location.  If | ||
| 350 |   /// the memory location aliases two or more existing alias sets, will have | ||
| 351 |   /// the effect of merging those alias sets before the single resulting alias | ||
| 352 |   /// set is returned. | ||
| 353 | AliasSet &getAliasSetFor(const MemoryLocation &MemLoc); | ||
| 354 | |||
| 355 |   /// Return the underlying alias analysis object used by this tracker. | ||
| 356 | BatchAAResults &getAliasAnalysis() const { return AA; } | ||
| 357 | |||
| 358 | using iterator = ilist<AliasSet>::iterator; | ||
| 359 | using const_iterator = ilist<AliasSet>::const_iterator; | ||
| 360 | |||
| 361 | const_iterator begin() const { return AliasSets.begin(); } | ||
| 362 | const_iterator end() const { return AliasSets.end(); } | ||
| 363 | |||
| 364 | iterator begin() { return AliasSets.begin(); } | ||
| 365 | iterator end() { return AliasSets.end(); } | ||
| 366 | |||
| 367 | void print(raw_ostream &OS) const; | ||
| 368 | void dump() const; | ||
| 369 | |||
| 370 | private: | ||
| 371 | friend class AliasSet; | ||
| 372 | |||
| 373 |   // The total number of pointers contained in all "may" alias sets. | ||
| 374 | unsigned TotalMayAliasSetSize = 0; | ||
| 375 | |||
| 376 |   // A non-null value signifies this AST is saturated. A saturated AST lumps | ||
| 377 |   // all pointers into a single "May" set. | ||
| 378 | AliasSet *AliasAnyAS = nullptr; | ||
| 379 | |||
| 380 | void removeAliasSet(AliasSet *AS); | ||
| 381 | |||
| 382 |   /// Just like operator[] on the map, except that it creates an entry for the | ||
| 383 |   /// pointer if it doesn't already exist. | ||
| 384 | AliasSet::PointerRec &getEntryFor(Value *V) { | ||
| 385 | AliasSet::PointerRec *&Entry = PointerMap[V]; | ||
| 386 | if (!Entry) | ||
| 387 | Entry = new AliasSet::PointerRec(V); | ||
| 388 | return *Entry; | ||
| 389 |   } | ||
| 390 | |||
| 391 | AliasSet &addPointer(MemoryLocation Loc, AliasSet::AccessLattice E); | ||
| 392 | AliasSet *mergeAliasSetsForPointer(const Value *Ptr, LocationSize Size, | ||
| 393 | const AAMDNodes &AAInfo, | ||
| 394 | bool &MustAliasAll); | ||
| 395 | |||
| 396 |   /// Merge all alias sets into a single set that is considered to alias any | ||
| 397 |   /// pointer. | ||
| 398 | AliasSet &mergeAllAliasSets(); | ||
| 399 | |||
| 400 | AliasSet *findAliasSetForUnknownInst(Instruction *Inst); | ||
| 401 | }; | ||
| 402 | |||
| 403 | inline raw_ostream& operator<<(raw_ostream &OS, const AliasSetTracker &AST) { | ||
| 404 | AST.print(OS); | ||
| 405 | return OS; | ||
| 406 | } | ||
| 407 | |||
| 408 | class AliasSetsPrinterPass : public PassInfoMixin<AliasSetsPrinterPass> { | ||
| 409 | raw_ostream &OS; | ||
| 410 | |||
| 411 | public: | ||
| 412 | explicit AliasSetsPrinterPass(raw_ostream &OS); | ||
| 413 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); | ||
| 414 | }; | ||
| 415 | |||
| 416 | } // end namespace llvm | ||
| 417 | |||
| 418 | #endif // LLVM_ANALYSIS_ALIASSETTRACKER_H |