1 //===- llvm/Analysis/AssumptionCache.h - Track @llvm.assume -----*- 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 contains a pass that keeps track of @llvm.assume intrinsics in 10 // the functions of a module (allowing assumptions within any function to be 11 // found cheaply by other parts of the optimizer). 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_ANALYSIS_ASSUMPTIONCACHE_H 16 #define LLVM_ANALYSIS_ASSUMPTIONCACHE_H 17 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/DenseMap.h" 20 #include "llvm/ADT/DenseMapInfo.h" 21 #include "llvm/ADT/SmallVector.h" 22 #include "llvm/IR/PassManager.h" 23 #include "llvm/IR/ValueHandle.h" 24 #include "llvm/Pass.h" 25 #include <memory> 26 27 namespace llvm { 28 29 class CallInst; 30 class Function; 31 class raw_ostream; 32 class Value; 33 34 /// A cache of \@llvm.assume calls within a function. 35 /// 36 /// This cache provides fast lookup of assumptions within a function by caching 37 /// them and amortizing the cost of scanning for them across all queries. Passes 38 /// that create new assumptions are required to call registerAssumption() to 39 /// register any new \@llvm.assume calls that they create. Deletions of 40 /// \@llvm.assume calls do not require special handling. 41 class AssumptionCache { 42 public: 43 /// Value of ResultElem::Index indicating that the argument to the call of the 44 /// llvm.assume. 45 enum : unsigned { ExprResultIdx = std::numeric_limits<unsigned>::max() }; 46 47 struct ResultElem { 48 WeakTrackingVH Assume; 49 50 /// contains either ExprResultIdx or the index of the operand bundle 51 /// containing the knowledge. 52 unsigned Index; 53 operator Value *() const { return Assume; } 54 }; 55 56 private: 57 /// The function for which this cache is handling assumptions. 58 /// 59 /// We track this to lazily populate our assumptions. 60 Function &F; 61 62 /// Vector of weak value handles to calls of the \@llvm.assume 63 /// intrinsic. 64 SmallVector<ResultElem, 4> AssumeHandles; 65 66 class AffectedValueCallbackVH final : public CallbackVH { 67 AssumptionCache *AC; 68 69 void deleted() override; 70 void allUsesReplacedWith(Value *) override; 71 72 public: 73 using DMI = DenseMapInfo<Value *>; 74 75 AffectedValueCallbackVH(Value *V, AssumptionCache *AC = nullptr) CallbackVH(V)76 : CallbackVH(V), AC(AC) {} 77 }; 78 79 friend AffectedValueCallbackVH; 80 81 /// A map of values about which an assumption might be providing 82 /// information to the relevant set of assumptions. 83 using AffectedValuesMap = 84 DenseMap<AffectedValueCallbackVH, SmallVector<ResultElem, 1>, 85 AffectedValueCallbackVH::DMI>; 86 AffectedValuesMap AffectedValues; 87 88 /// Get the vector of assumptions which affect a value from the cache. 89 SmallVector<ResultElem, 1> &getOrInsertAffectedValues(Value *V); 90 91 /// Move affected values in the cache for OV to be affected values for NV. 92 void transferAffectedValuesInCache(Value *OV, Value *NV); 93 94 /// Flag tracking whether we have scanned the function yet. 95 /// 96 /// We want to be as lazy about this as possible, and so we scan the function 97 /// at the last moment. 98 bool Scanned = false; 99 100 /// Scan the function for assumptions and add them to the cache. 101 void scanFunction(); 102 103 public: 104 /// Construct an AssumptionCache from a function by scanning all of 105 /// its instructions. AssumptionCache(Function & F)106 AssumptionCache(Function &F) : F(F) {} 107 108 /// This cache is designed to be self-updating and so it should never be 109 /// invalidated. invalidate(Function &,const PreservedAnalyses &,FunctionAnalysisManager::Invalidator &)110 bool invalidate(Function &, const PreservedAnalyses &, 111 FunctionAnalysisManager::Invalidator &) { 112 return false; 113 } 114 115 /// Add an \@llvm.assume intrinsic to this function's cache. 116 /// 117 /// The call passed in must be an instruction within this function and must 118 /// not already be in the cache. 119 void registerAssumption(CallInst *CI); 120 121 /// Remove an \@llvm.assume intrinsic from this function's cache if it has 122 /// been added to the cache earlier. 123 void unregisterAssumption(CallInst *CI); 124 125 /// Update the cache of values being affected by this assumption (i.e. 126 /// the values about which this assumption provides information). 127 void updateAffectedValues(CallInst *CI); 128 129 /// Clear the cache of \@llvm.assume intrinsics for a function. 130 /// 131 /// It will be re-scanned the next time it is requested. clear()132 void clear() { 133 AssumeHandles.clear(); 134 AffectedValues.clear(); 135 Scanned = false; 136 } 137 138 /// Access the list of assumption handles currently tracked for this 139 /// function. 140 /// 141 /// Note that these produce weak handles that may be null. The caller must 142 /// handle that case. 143 /// FIXME: We should replace this with pointee_iterator<filter_iterator<...>> 144 /// when we can write that to filter out the null values. Then caller code 145 /// will become simpler. assumptions()146 MutableArrayRef<ResultElem> assumptions() { 147 if (!Scanned) 148 scanFunction(); 149 return AssumeHandles; 150 } 151 152 /// Access the list of assumptions which affect this value. assumptionsFor(const Value * V)153 MutableArrayRef<ResultElem> assumptionsFor(const Value *V) { 154 if (!Scanned) 155 scanFunction(); 156 157 auto AVI = AffectedValues.find_as(const_cast<Value *>(V)); 158 if (AVI == AffectedValues.end()) 159 return MutableArrayRef<ResultElem>(); 160 161 return AVI->second; 162 } 163 }; 164 165 /// A function analysis which provides an \c AssumptionCache. 166 /// 167 /// This analysis is intended for use with the new pass manager and will vend 168 /// assumption caches for a given function. 169 class AssumptionAnalysis : public AnalysisInfoMixin<AssumptionAnalysis> { 170 friend AnalysisInfoMixin<AssumptionAnalysis>; 171 172 static AnalysisKey Key; 173 174 public: 175 using Result = AssumptionCache; 176 run(Function & F,FunctionAnalysisManager &)177 AssumptionCache run(Function &F, FunctionAnalysisManager &) { 178 return AssumptionCache(F); 179 } 180 }; 181 182 /// Printer pass for the \c AssumptionAnalysis results. 183 class AssumptionPrinterPass : public PassInfoMixin<AssumptionPrinterPass> { 184 raw_ostream &OS; 185 186 public: AssumptionPrinterPass(raw_ostream & OS)187 explicit AssumptionPrinterPass(raw_ostream &OS) : OS(OS) {} 188 189 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 190 }; 191 192 /// An immutable pass that tracks lazily created \c AssumptionCache 193 /// objects. 194 /// 195 /// This is essentially a workaround for the legacy pass manager's weaknesses 196 /// which associates each assumption cache with Function and clears it if the 197 /// function is deleted. The nature of the AssumptionCache is that it is not 198 /// invalidated by any changes to the function body and so this is sufficient 199 /// to be conservatively correct. 200 class AssumptionCacheTracker : public ImmutablePass { 201 /// A callback value handle applied to function objects, which we use to 202 /// delete our cache of intrinsics for a function when it is deleted. 203 class FunctionCallbackVH final : public CallbackVH { 204 AssumptionCacheTracker *ACT; 205 206 void deleted() override; 207 208 public: 209 using DMI = DenseMapInfo<Value *>; 210 211 FunctionCallbackVH(Value *V, AssumptionCacheTracker *ACT = nullptr) CallbackVH(V)212 : CallbackVH(V), ACT(ACT) {} 213 }; 214 215 friend FunctionCallbackVH; 216 217 using FunctionCallsMap = 218 DenseMap<FunctionCallbackVH, std::unique_ptr<AssumptionCache>, 219 FunctionCallbackVH::DMI>; 220 221 FunctionCallsMap AssumptionCaches; 222 223 public: 224 /// Get the cached assumptions for a function. 225 /// 226 /// If no assumptions are cached, this will scan the function. Otherwise, the 227 /// existing cache will be returned. 228 AssumptionCache &getAssumptionCache(Function &F); 229 230 /// Return the cached assumptions for a function if it has already been 231 /// scanned. Otherwise return nullptr. 232 AssumptionCache *lookupAssumptionCache(Function &F); 233 234 AssumptionCacheTracker(); 235 ~AssumptionCacheTracker() override; 236 releaseMemory()237 void releaseMemory() override { 238 verifyAnalysis(); 239 AssumptionCaches.shrink_and_clear(); 240 } 241 242 void verifyAnalysis() const override; 243 doFinalization(Module &)244 bool doFinalization(Module &) override { 245 verifyAnalysis(); 246 return false; 247 } 248 249 static char ID; // Pass identification, replacement for typeid 250 }; 251 252 template<> struct simplify_type<AssumptionCache::ResultElem> { 253 using SimpleType = Value *; 254 255 static SimpleType getSimplifiedValue(AssumptionCache::ResultElem &Val) { 256 return Val; 257 } 258 }; 259 template<> struct simplify_type<const AssumptionCache::ResultElem> { 260 using SimpleType = /*const*/ Value *; 261 262 static SimpleType getSimplifiedValue(const AssumptionCache::ResultElem &Val) { 263 return Val; 264 } 265 }; 266 267 } // end namespace llvm 268 269 #endif // LLVM_ANALYSIS_ASSUMPTIONCACHE_H 270