Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | //===- llvm/Analysis/MemoryDependenceAnalysis.h - Memory Deps ---*- 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 the MemoryDependenceAnalysis analysis pass. |
||
| 10 | // |
||
| 11 | //===----------------------------------------------------------------------===// |
||
| 12 | |||
| 13 | #ifndef LLVM_ANALYSIS_MEMORYDEPENDENCEANALYSIS_H |
||
| 14 | #define LLVM_ANALYSIS_MEMORYDEPENDENCEANALYSIS_H |
||
| 15 | |||
| 16 | #include "llvm/ADT/DenseMap.h" |
||
| 17 | #include "llvm/ADT/PointerEmbeddedInt.h" |
||
| 18 | #include "llvm/ADT/PointerIntPair.h" |
||
| 19 | #include "llvm/ADT/PointerSumType.h" |
||
| 20 | #include "llvm/ADT/SmallPtrSet.h" |
||
| 21 | #include "llvm/Analysis/MemoryLocation.h" |
||
| 22 | #include "llvm/IR/PassManager.h" |
||
| 23 | #include "llvm/IR/PredIteratorCache.h" |
||
| 24 | #include "llvm/IR/ValueHandle.h" |
||
| 25 | #include "llvm/Pass.h" |
||
| 26 | #include <optional> |
||
| 27 | |||
| 28 | namespace llvm { |
||
| 29 | |||
| 30 | class AAResults; |
||
| 31 | class AssumptionCache; |
||
| 32 | class BatchAAResults; |
||
| 33 | class DominatorTree; |
||
| 34 | class PHITransAddr; |
||
| 35 | |||
| 36 | /// A memory dependence query can return one of three different answers. |
||
| 37 | class MemDepResult { |
||
| 38 | enum DepType { |
||
| 39 | /// Clients of MemDep never see this. |
||
| 40 | /// |
||
| 41 | /// Entries with this marker occur in a LocalDeps map or NonLocalDeps map |
||
| 42 | /// when the instruction they previously referenced was removed from |
||
| 43 | /// MemDep. In either case, the entry may include an instruction pointer. |
||
| 44 | /// If so, the pointer is an instruction in the block where scanning can |
||
| 45 | /// start from, saving some work. |
||
| 46 | /// |
||
| 47 | /// In a default-constructed MemDepResult object, the type will be Invalid |
||
| 48 | /// and the instruction pointer will be null. |
||
| 49 | Invalid = 0, |
||
| 50 | |||
| 51 | /// This is a dependence on the specified instruction which clobbers the |
||
| 52 | /// desired value. The pointer member of the MemDepResult pair holds the |
||
| 53 | /// instruction that clobbers the memory. For example, this occurs when we |
||
| 54 | /// see a may-aliased store to the memory location we care about. |
||
| 55 | /// |
||
| 56 | /// There are several cases that may be interesting here: |
||
| 57 | /// 1. Loads are clobbered by may-alias stores. |
||
| 58 | /// 2. Loads are considered clobbered by partially-aliased loads. The |
||
| 59 | /// client may choose to analyze deeper into these cases. |
||
| 60 | Clobber, |
||
| 61 | |||
| 62 | /// This is a dependence on the specified instruction which defines or |
||
| 63 | /// produces the desired memory location. The pointer member of the |
||
| 64 | /// MemDepResult pair holds the instruction that defines the memory. |
||
| 65 | /// |
||
| 66 | /// Cases of interest: |
||
| 67 | /// 1. This could be a load or store for dependence queries on |
||
| 68 | /// load/store. The value loaded or stored is the produced value. |
||
| 69 | /// Note that the pointer operand may be different than that of the |
||
| 70 | /// queried pointer due to must aliases and phi translation. Note |
||
| 71 | /// that the def may not be the same type as the query, the pointers |
||
| 72 | /// may just be must aliases. |
||
| 73 | /// 2. For loads and stores, this could be an allocation instruction. In |
||
| 74 | /// this case, the load is loading an undef value or a store is the |
||
| 75 | /// first store to (that part of) the allocation. |
||
| 76 | /// 3. Dependence queries on calls return Def only when they are readonly |
||
| 77 | /// calls or memory use intrinsics with identical callees and no |
||
| 78 | /// intervening clobbers. No validation is done that the operands to |
||
| 79 | /// the calls are the same. |
||
| 80 | /// 4. For loads and stores, this could be a select instruction that |
||
| 81 | /// defines pointer to this memory location. In this case, users can |
||
| 82 | /// find non-clobbered Defs for both select values that are reaching |
||
| 83 | // the desired memory location (there is still a guarantee that there |
||
| 84 | // are no clobbers between analyzed memory location and select). |
||
| 85 | Def, |
||
| 86 | |||
| 87 | /// This marker indicates that the query has no known dependency in the |
||
| 88 | /// specified block. |
||
| 89 | /// |
||
| 90 | /// More detailed state info is encoded in the upper part of the pair (i.e. |
||
| 91 | /// the Instruction*) |
||
| 92 | Other |
||
| 93 | }; |
||
| 94 | |||
| 95 | /// If DepType is "Other", the upper part of the sum type is an encoding of |
||
| 96 | /// the following more detailed type information. |
||
| 97 | enum OtherType { |
||
| 98 | /// This marker indicates that the query has no dependency in the specified |
||
| 99 | /// block. |
||
| 100 | /// |
||
| 101 | /// To find out more, the client should query other predecessor blocks. |
||
| 102 | NonLocal = 1, |
||
| 103 | /// This marker indicates that the query has no dependency in the specified |
||
| 104 | /// function. |
||
| 105 | NonFuncLocal, |
||
| 106 | /// This marker indicates that the query dependency is unknown. |
||
| 107 | Unknown |
||
| 108 | }; |
||
| 109 | |||
| 110 | using ValueTy = PointerSumType< |
||
| 111 | DepType, PointerSumTypeMember<Invalid, Instruction *>, |
||
| 112 | PointerSumTypeMember<Clobber, Instruction *>, |
||
| 113 | PointerSumTypeMember<Def, Instruction *>, |
||
| 114 | PointerSumTypeMember<Other, PointerEmbeddedInt<OtherType, 3>>>; |
||
| 115 | ValueTy Value; |
||
| 116 | |||
| 117 | explicit MemDepResult(ValueTy V) : Value(V) {} |
||
| 118 | |||
| 119 | public: |
||
| 120 | MemDepResult() = default; |
||
| 121 | |||
| 122 | /// get methods: These are static ctor methods for creating various |
||
| 123 | /// MemDepResult kinds. |
||
| 124 | static MemDepResult getDef(Instruction *Inst) { |
||
| 125 | assert(Inst && "Def requires inst"); |
||
| 126 | return MemDepResult(ValueTy::create<Def>(Inst)); |
||
| 127 | } |
||
| 128 | static MemDepResult getClobber(Instruction *Inst) { |
||
| 129 | assert(Inst && "Clobber requires inst"); |
||
| 130 | return MemDepResult(ValueTy::create<Clobber>(Inst)); |
||
| 131 | } |
||
| 132 | static MemDepResult getNonLocal() { |
||
| 133 | return MemDepResult(ValueTy::create<Other>(NonLocal)); |
||
| 134 | } |
||
| 135 | static MemDepResult getNonFuncLocal() { |
||
| 136 | return MemDepResult(ValueTy::create<Other>(NonFuncLocal)); |
||
| 137 | } |
||
| 138 | static MemDepResult getUnknown() { |
||
| 139 | return MemDepResult(ValueTy::create<Other>(Unknown)); |
||
| 140 | } |
||
| 141 | |||
| 142 | /// Tests if this MemDepResult represents a query that is an instruction |
||
| 143 | /// clobber dependency. |
||
| 144 | bool isClobber() const { return Value.is<Clobber>(); } |
||
| 145 | |||
| 146 | /// Tests if this MemDepResult represents a query that is an instruction |
||
| 147 | /// definition dependency. |
||
| 148 | bool isDef() const { return Value.is<Def>(); } |
||
| 149 | |||
| 150 | /// Tests if this MemDepResult represents a valid local query (Clobber/Def). |
||
| 151 | bool isLocal() const { return isClobber() || isDef(); } |
||
| 152 | |||
| 153 | /// Tests if this MemDepResult represents a query that is transparent to the |
||
| 154 | /// start of the block, but where a non-local hasn't been done. |
||
| 155 | bool isNonLocal() const { |
||
| 156 | return Value.is<Other>() && Value.cast<Other>() == NonLocal; |
||
| 157 | } |
||
| 158 | |||
| 159 | /// Tests if this MemDepResult represents a query that is transparent to the |
||
| 160 | /// start of the function. |
||
| 161 | bool isNonFuncLocal() const { |
||
| 162 | return Value.is<Other>() && Value.cast<Other>() == NonFuncLocal; |
||
| 163 | } |
||
| 164 | |||
| 165 | /// Tests if this MemDepResult represents a query which cannot and/or will |
||
| 166 | /// not be computed. |
||
| 167 | bool isUnknown() const { |
||
| 168 | return Value.is<Other>() && Value.cast<Other>() == Unknown; |
||
| 169 | } |
||
| 170 | |||
| 171 | /// If this is a normal dependency, returns the instruction that is depended |
||
| 172 | /// on. Otherwise, returns null. |
||
| 173 | Instruction *getInst() const { |
||
| 174 | switch (Value.getTag()) { |
||
| 175 | case Invalid: |
||
| 176 | return Value.cast<Invalid>(); |
||
| 177 | case Clobber: |
||
| 178 | return Value.cast<Clobber>(); |
||
| 179 | case Def: |
||
| 180 | return Value.cast<Def>(); |
||
| 181 | case Other: |
||
| 182 | return nullptr; |
||
| 183 | } |
||
| 184 | llvm_unreachable("Unknown discriminant!"); |
||
| 185 | } |
||
| 186 | |||
| 187 | bool operator==(const MemDepResult &M) const { return Value == M.Value; } |
||
| 188 | bool operator!=(const MemDepResult &M) const { return Value != M.Value; } |
||
| 189 | bool operator<(const MemDepResult &M) const { return Value < M.Value; } |
||
| 190 | bool operator>(const MemDepResult &M) const { return Value > M.Value; } |
||
| 191 | |||
| 192 | private: |
||
| 193 | friend class MemoryDependenceResults; |
||
| 194 | |||
| 195 | /// Tests if this is a MemDepResult in its dirty/invalid. state. |
||
| 196 | bool isDirty() const { return Value.is<Invalid>(); } |
||
| 197 | |||
| 198 | static MemDepResult getDirty(Instruction *Inst) { |
||
| 199 | return MemDepResult(ValueTy::create<Invalid>(Inst)); |
||
| 200 | } |
||
| 201 | }; |
||
| 202 | |||
| 203 | /// This is an entry in the NonLocalDepInfo cache. |
||
| 204 | /// |
||
| 205 | /// For each BasicBlock (the BB entry) it keeps a MemDepResult. |
||
| 206 | class NonLocalDepEntry { |
||
| 207 | BasicBlock *BB; |
||
| 208 | MemDepResult Result; |
||
| 209 | |||
| 210 | public: |
||
| 211 | NonLocalDepEntry(BasicBlock *bb, MemDepResult result) |
||
| 212 | : BB(bb), Result(result) {} |
||
| 213 | |||
| 214 | // This is used for searches. |
||
| 215 | NonLocalDepEntry(BasicBlock *bb) : BB(bb) {} |
||
| 216 | |||
| 217 | // BB is the sort key, it can't be changed. |
||
| 218 | BasicBlock *getBB() const { return BB; } |
||
| 219 | |||
| 220 | void setResult(const MemDepResult &R) { Result = R; } |
||
| 221 | |||
| 222 | const MemDepResult &getResult() const { return Result; } |
||
| 223 | |||
| 224 | bool operator<(const NonLocalDepEntry &RHS) const { return BB < RHS.BB; } |
||
| 225 | }; |
||
| 226 | |||
| 227 | /// This is a result from a NonLocal dependence query. |
||
| 228 | /// |
||
| 229 | /// For each BasicBlock (the BB entry) it keeps a MemDepResult and the |
||
| 230 | /// (potentially phi translated) address that was live in the block. |
||
| 231 | class NonLocalDepResult { |
||
| 232 | NonLocalDepEntry Entry; |
||
| 233 | Value *Address; |
||
| 234 | |||
| 235 | public: |
||
| 236 | NonLocalDepResult(BasicBlock *bb, MemDepResult result, Value *address) |
||
| 237 | : Entry(bb, result), Address(address) {} |
||
| 238 | |||
| 239 | // BB is the sort key, it can't be changed. |
||
| 240 | BasicBlock *getBB() const { return Entry.getBB(); } |
||
| 241 | |||
| 242 | void setResult(const MemDepResult &R, Value *Addr) { |
||
| 243 | Entry.setResult(R); |
||
| 244 | Address = Addr; |
||
| 245 | } |
||
| 246 | |||
| 247 | const MemDepResult &getResult() const { return Entry.getResult(); } |
||
| 248 | |||
| 249 | /// Returns the address of this pointer in this block. |
||
| 250 | /// |
||
| 251 | /// This can be different than the address queried for the non-local result |
||
| 252 | /// because of phi translation. This returns null if the address was not |
||
| 253 | /// available in a block (i.e. because phi translation failed) or if this is |
||
| 254 | /// a cached result and that address was deleted. |
||
| 255 | /// |
||
| 256 | /// The address is always null for a non-local 'call' dependence. |
||
| 257 | Value *getAddress() const { return Address; } |
||
| 258 | }; |
||
| 259 | |||
| 260 | /// Provides a lazy, caching interface for making common memory aliasing |
||
| 261 | /// information queries, backed by LLVM's alias analysis passes. |
||
| 262 | /// |
||
| 263 | /// The dependency information returned is somewhat unusual, but is pragmatic. |
||
| 264 | /// If queried about a store or call that might modify memory, the analysis |
||
| 265 | /// will return the instruction[s] that may either load from that memory or |
||
| 266 | /// store to it. If queried with a load or call that can never modify memory, |
||
| 267 | /// the analysis will return calls and stores that might modify the pointer, |
||
| 268 | /// but generally does not return loads unless a) they are volatile, or |
||
| 269 | /// b) they load from *must-aliased* pointers. Returning a dependence on |
||
| 270 | /// must-alias'd pointers instead of all pointers interacts well with the |
||
| 271 | /// internal caching mechanism. |
||
| 272 | class MemoryDependenceResults { |
||
| 273 | // A map from instructions to their dependency. |
||
| 274 | using LocalDepMapType = DenseMap<Instruction *, MemDepResult>; |
||
| 275 | LocalDepMapType LocalDeps; |
||
| 276 | |||
| 277 | public: |
||
| 278 | using NonLocalDepInfo = std::vector<NonLocalDepEntry>; |
||
| 279 | |||
| 280 | private: |
||
| 281 | /// A pair<Value*, bool> where the bool is true if the dependence is a read |
||
| 282 | /// only dependence, false if read/write. |
||
| 283 | using ValueIsLoadPair = PointerIntPair<const Value *, 1, bool>; |
||
| 284 | |||
| 285 | /// This pair is used when caching information for a block. |
||
| 286 | /// |
||
| 287 | /// If the pointer is null, the cache value is not a full query that starts |
||
| 288 | /// at the specified block. If non-null, the bool indicates whether or not |
||
| 289 | /// the contents of the block was skipped. |
||
| 290 | using BBSkipFirstBlockPair = PointerIntPair<BasicBlock *, 1, bool>; |
||
| 291 | |||
| 292 | /// This record is the information kept for each (value, is load) pair. |
||
| 293 | struct NonLocalPointerInfo { |
||
| 294 | /// The pair of the block and the skip-first-block flag. |
||
| 295 | BBSkipFirstBlockPair Pair; |
||
| 296 | /// The results of the query for each relevant block. |
||
| 297 | NonLocalDepInfo NonLocalDeps; |
||
| 298 | /// The maximum size of the dereferences of the pointer. |
||
| 299 | /// |
||
| 300 | /// May be UnknownSize if the sizes are unknown. |
||
| 301 | LocationSize Size = LocationSize::afterPointer(); |
||
| 302 | /// The AA tags associated with dereferences of the pointer. |
||
| 303 | /// |
||
| 304 | /// The members may be null if there are no tags or conflicting tags. |
||
| 305 | AAMDNodes AATags; |
||
| 306 | |||
| 307 | NonLocalPointerInfo() = default; |
||
| 308 | }; |
||
| 309 | |||
| 310 | /// Cache storing single nonlocal def for the instruction. |
||
| 311 | /// It is set when nonlocal def would be found in function returning only |
||
| 312 | /// local dependencies. |
||
| 313 | DenseMap<AssertingVH<const Value>, NonLocalDepResult> NonLocalDefsCache; |
||
| 314 | using ReverseNonLocalDefsCacheTy = |
||
| 315 | DenseMap<Instruction *, SmallPtrSet<const Value*, 4>>; |
||
| 316 | ReverseNonLocalDefsCacheTy ReverseNonLocalDefsCache; |
||
| 317 | |||
| 318 | /// This map stores the cached results of doing a pointer lookup at the |
||
| 319 | /// bottom of a block. |
||
| 320 | /// |
||
| 321 | /// The key of this map is the pointer+isload bit, the value is a list of |
||
| 322 | /// <bb->result> mappings. |
||
| 323 | using CachedNonLocalPointerInfo = |
||
| 324 | DenseMap<ValueIsLoadPair, NonLocalPointerInfo>; |
||
| 325 | CachedNonLocalPointerInfo NonLocalPointerDeps; |
||
| 326 | |||
| 327 | // A map from instructions to their non-local pointer dependencies. |
||
| 328 | using ReverseNonLocalPtrDepTy = |
||
| 329 | DenseMap<Instruction *, SmallPtrSet<ValueIsLoadPair, 4>>; |
||
| 330 | ReverseNonLocalPtrDepTy ReverseNonLocalPtrDeps; |
||
| 331 | |||
| 332 | /// This is the instruction we keep for each cached access that we have for |
||
| 333 | /// an instruction. |
||
| 334 | /// |
||
| 335 | /// The pointer is an owning pointer and the bool indicates whether we have |
||
| 336 | /// any dirty bits in the set. |
||
| 337 | using PerInstNLInfo = std::pair<NonLocalDepInfo, bool>; |
||
| 338 | |||
| 339 | // A map from instructions to their non-local dependencies. |
||
| 340 | using NonLocalDepMapType = DenseMap<Instruction *, PerInstNLInfo>; |
||
| 341 | |||
| 342 | NonLocalDepMapType NonLocalDepsMap; |
||
| 343 | |||
| 344 | // A reverse mapping from dependencies to the dependees. This is |
||
| 345 | // used when removing instructions to keep the cache coherent. |
||
| 346 | using ReverseDepMapType = |
||
| 347 | DenseMap<Instruction *, SmallPtrSet<Instruction *, 4>>; |
||
| 348 | ReverseDepMapType ReverseLocalDeps; |
||
| 349 | |||
| 350 | // A reverse mapping from dependencies to the non-local dependees. |
||
| 351 | ReverseDepMapType ReverseNonLocalDeps; |
||
| 352 | |||
| 353 | /// Current AA implementation, just a cache. |
||
| 354 | AAResults &AA; |
||
| 355 | AssumptionCache &AC; |
||
| 356 | const TargetLibraryInfo &TLI; |
||
| 357 | DominatorTree &DT; |
||
| 358 | PredIteratorCache PredCache; |
||
| 359 | |||
| 360 | unsigned DefaultBlockScanLimit; |
||
| 361 | |||
| 362 | /// Offsets to dependant clobber loads. |
||
| 363 | using ClobberOffsetsMapType = DenseMap<LoadInst *, int32_t>; |
||
| 364 | ClobberOffsetsMapType ClobberOffsets; |
||
| 365 | |||
| 366 | public: |
||
| 367 | MemoryDependenceResults(AAResults &AA, AssumptionCache &AC, |
||
| 368 | const TargetLibraryInfo &TLI, DominatorTree &DT, |
||
| 369 | unsigned DefaultBlockScanLimit) |
||
| 370 | : AA(AA), AC(AC), TLI(TLI), DT(DT), |
||
| 371 | DefaultBlockScanLimit(DefaultBlockScanLimit) {} |
||
| 372 | |||
| 373 | /// Handle invalidation in the new PM. |
||
| 374 | bool invalidate(Function &F, const PreservedAnalyses &PA, |
||
| 375 | FunctionAnalysisManager::Invalidator &Inv); |
||
| 376 | |||
| 377 | /// Some methods limit the number of instructions they will examine. |
||
| 378 | /// The return value of this method is the default limit that will be |
||
| 379 | /// used if no limit is explicitly passed in. |
||
| 380 | unsigned getDefaultBlockScanLimit() const; |
||
| 381 | |||
| 382 | /// Returns the instruction on which a memory operation depends. |
||
| 383 | /// |
||
| 384 | /// See the class comment for more details. It is illegal to call this on |
||
| 385 | /// non-memory instructions. |
||
| 386 | MemDepResult getDependency(Instruction *QueryInst); |
||
| 387 | |||
| 388 | /// Perform a full dependency query for the specified call, returning the set |
||
| 389 | /// of blocks that the value is potentially live across. |
||
| 390 | /// |
||
| 391 | /// The returned set of results will include a "NonLocal" result for all |
||
| 392 | /// blocks where the value is live across. |
||
| 393 | /// |
||
| 394 | /// This method assumes the instruction returns a "NonLocal" dependency |
||
| 395 | /// within its own block. |
||
| 396 | /// |
||
| 397 | /// This returns a reference to an internal data structure that may be |
||
| 398 | /// invalidated on the next non-local query or when an instruction is |
||
| 399 | /// removed. Clients must copy this data if they want it around longer than |
||
| 400 | /// that. |
||
| 401 | const NonLocalDepInfo &getNonLocalCallDependency(CallBase *QueryCall); |
||
| 402 | |||
| 403 | /// Perform a full dependency query for an access to the QueryInst's |
||
| 404 | /// specified memory location, returning the set of instructions that either |
||
| 405 | /// define or clobber the value. |
||
| 406 | /// |
||
| 407 | /// Warning: For a volatile query instruction, the dependencies will be |
||
| 408 | /// accurate, and thus usable for reordering, but it is never legal to |
||
| 409 | /// remove the query instruction. |
||
| 410 | /// |
||
| 411 | /// This method assumes the pointer has a "NonLocal" dependency within |
||
| 412 | /// QueryInst's parent basic block. |
||
| 413 | void getNonLocalPointerDependency(Instruction *QueryInst, |
||
| 414 | SmallVectorImpl<NonLocalDepResult> &Result); |
||
| 415 | |||
| 416 | /// Removes an instruction from the dependence analysis, updating the |
||
| 417 | /// dependence of instructions that previously depended on it. |
||
| 418 | void removeInstruction(Instruction *InstToRemove); |
||
| 419 | |||
| 420 | /// Invalidates cached information about the specified pointer, because it |
||
| 421 | /// may be too conservative in memdep. |
||
| 422 | /// |
||
| 423 | /// This is an optional call that can be used when the client detects an |
||
| 424 | /// equivalence between the pointer and some other value and replaces the |
||
| 425 | /// other value with ptr. This can make Ptr available in more places that |
||
| 426 | /// cached info does not necessarily keep. |
||
| 427 | void invalidateCachedPointerInfo(Value *Ptr); |
||
| 428 | |||
| 429 | /// Clears the PredIteratorCache info. |
||
| 430 | /// |
||
| 431 | /// This needs to be done when the CFG changes, e.g., due to splitting |
||
| 432 | /// critical edges. |
||
| 433 | void invalidateCachedPredecessors(); |
||
| 434 | |||
| 435 | /// Returns the instruction on which a memory location depends. |
||
| 436 | /// |
||
| 437 | /// If isLoad is true, this routine ignores may-aliases with read-only |
||
| 438 | /// operations. If isLoad is false, this routine ignores may-aliases |
||
| 439 | /// with reads from read-only locations. If possible, pass the query |
||
| 440 | /// instruction as well; this function may take advantage of the metadata |
||
| 441 | /// annotated to the query instruction to refine the result. \p Limit |
||
| 442 | /// can be used to set the maximum number of instructions that will be |
||
| 443 | /// examined to find the pointer dependency. On return, it will be set to |
||
| 444 | /// the number of instructions left to examine. If a null pointer is passed |
||
| 445 | /// in, the limit will default to the value of -memdep-block-scan-limit. |
||
| 446 | /// |
||
| 447 | /// Note that this is an uncached query, and thus may be inefficient. |
||
| 448 | MemDepResult getPointerDependencyFrom(const MemoryLocation &Loc, bool isLoad, |
||
| 449 | BasicBlock::iterator ScanIt, |
||
| 450 | BasicBlock *BB, |
||
| 451 | Instruction *QueryInst = nullptr, |
||
| 452 | unsigned *Limit = nullptr); |
||
| 453 | |||
| 454 | MemDepResult getPointerDependencyFrom(const MemoryLocation &Loc, bool isLoad, |
||
| 455 | BasicBlock::iterator ScanIt, |
||
| 456 | BasicBlock *BB, |
||
| 457 | Instruction *QueryInst, |
||
| 458 | unsigned *Limit, |
||
| 459 | BatchAAResults &BatchAA); |
||
| 460 | |||
| 461 | MemDepResult |
||
| 462 | getSimplePointerDependencyFrom(const MemoryLocation &MemLoc, bool isLoad, |
||
| 463 | BasicBlock::iterator ScanIt, BasicBlock *BB, |
||
| 464 | Instruction *QueryInst, unsigned *Limit, |
||
| 465 | BatchAAResults &BatchAA); |
||
| 466 | |||
| 467 | /// This analysis looks for other loads and stores with invariant.group |
||
| 468 | /// metadata and the same pointer operand. Returns Unknown if it does not |
||
| 469 | /// find anything, and Def if it can be assumed that 2 instructions load or |
||
| 470 | /// store the same value and NonLocal which indicate that non-local Def was |
||
| 471 | /// found, which can be retrieved by calling getNonLocalPointerDependency |
||
| 472 | /// with the same queried instruction. |
||
| 473 | MemDepResult getInvariantGroupPointerDependency(LoadInst *LI, BasicBlock *BB); |
||
| 474 | |||
| 475 | /// Release memory in caches. |
||
| 476 | void releaseMemory(); |
||
| 477 | |||
| 478 | /// Return the clobber offset to dependent instruction. |
||
| 479 | std::optional<int32_t> getClobberOffset(LoadInst *DepInst) const { |
||
| 480 | const auto Off = ClobberOffsets.find(DepInst); |
||
| 481 | if (Off != ClobberOffsets.end()) |
||
| 482 | return Off->getSecond(); |
||
| 483 | return std::nullopt; |
||
| 484 | } |
||
| 485 | |||
| 486 | private: |
||
| 487 | MemDepResult getCallDependencyFrom(CallBase *Call, bool isReadOnlyCall, |
||
| 488 | BasicBlock::iterator ScanIt, |
||
| 489 | BasicBlock *BB); |
||
| 490 | bool getNonLocalPointerDepFromBB(Instruction *QueryInst, |
||
| 491 | const PHITransAddr &Pointer, |
||
| 492 | const MemoryLocation &Loc, bool isLoad, |
||
| 493 | BasicBlock *BB, |
||
| 494 | SmallVectorImpl<NonLocalDepResult> &Result, |
||
| 495 | DenseMap<BasicBlock *, Value *> &Visited, |
||
| 496 | bool SkipFirstBlock = false, |
||
| 497 | bool IsIncomplete = false); |
||
| 498 | MemDepResult getNonLocalInfoForBlock(Instruction *QueryInst, |
||
| 499 | const MemoryLocation &Loc, bool isLoad, |
||
| 500 | BasicBlock *BB, NonLocalDepInfo *Cache, |
||
| 501 | unsigned NumSortedEntries, |
||
| 502 | BatchAAResults &BatchAA); |
||
| 503 | |||
| 504 | void removeCachedNonLocalPointerDependencies(ValueIsLoadPair P); |
||
| 505 | |||
| 506 | void verifyRemoved(Instruction *Inst) const; |
||
| 507 | }; |
||
| 508 | |||
| 509 | /// An analysis that produces \c MemoryDependenceResults for a function. |
||
| 510 | /// |
||
| 511 | /// This is essentially a no-op because the results are computed entirely |
||
| 512 | /// lazily. |
||
| 513 | class MemoryDependenceAnalysis |
||
| 514 | : public AnalysisInfoMixin<MemoryDependenceAnalysis> { |
||
| 515 | friend AnalysisInfoMixin<MemoryDependenceAnalysis>; |
||
| 516 | |||
| 517 | static AnalysisKey Key; |
||
| 518 | |||
| 519 | unsigned DefaultBlockScanLimit; |
||
| 520 | |||
| 521 | public: |
||
| 522 | using Result = MemoryDependenceResults; |
||
| 523 | |||
| 524 | MemoryDependenceAnalysis(); |
||
| 525 | MemoryDependenceAnalysis(unsigned DefaultBlockScanLimit) : DefaultBlockScanLimit(DefaultBlockScanLimit) { } |
||
| 526 | |||
| 527 | MemoryDependenceResults run(Function &F, FunctionAnalysisManager &AM); |
||
| 528 | }; |
||
| 529 | |||
| 530 | /// A wrapper analysis pass for the legacy pass manager that exposes a \c |
||
| 531 | /// MemoryDepnedenceResults instance. |
||
| 532 | class MemoryDependenceWrapperPass : public FunctionPass { |
||
| 533 | std::optional<MemoryDependenceResults> MemDep; |
||
| 534 | |||
| 535 | public: |
||
| 536 | static char ID; |
||
| 537 | |||
| 538 | MemoryDependenceWrapperPass(); |
||
| 539 | ~MemoryDependenceWrapperPass() override; |
||
| 540 | |||
| 541 | /// Pass Implementation stuff. This doesn't do any analysis eagerly. |
||
| 542 | bool runOnFunction(Function &) override; |
||
| 543 | |||
| 544 | /// Clean up memory in between runs |
||
| 545 | void releaseMemory() override; |
||
| 546 | |||
| 547 | /// Does not modify anything. It uses Value Numbering and Alias Analysis. |
||
| 548 | void getAnalysisUsage(AnalysisUsage &AU) const override; |
||
| 549 | |||
| 550 | MemoryDependenceResults &getMemDep() { return *MemDep; } |
||
| 551 | }; |
||
| 552 | |||
| 553 | } // end namespace llvm |
||
| 554 | |||
| 555 | #endif // LLVM_ANALYSIS_MEMORYDEPENDENCEANALYSIS_H |