• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   /// The function for which this cache is handling assumptions.
43   ///
44   /// We track this to lazily populate our assumptions.
45   Function &F;
46 
47   /// Vector of weak value handles to calls of the \@llvm.assume
48   /// intrinsic.
49   SmallVector<WeakTrackingVH, 4> AssumeHandles;
50 
51   class AffectedValueCallbackVH final : public CallbackVH {
52     AssumptionCache *AC;
53 
54     void deleted() override;
55     void allUsesReplacedWith(Value *) override;
56 
57   public:
58     using DMI = DenseMapInfo<Value *>;
59 
60     AffectedValueCallbackVH(Value *V, AssumptionCache *AC = nullptr)
CallbackVH(V)61         : CallbackVH(V), AC(AC) {}
62   };
63 
64   friend AffectedValueCallbackVH;
65 
66   /// A map of values about which an assumption might be providing
67   /// information to the relevant set of assumptions.
68   using AffectedValuesMap =
69       DenseMap<AffectedValueCallbackVH, SmallVector<WeakTrackingVH, 1>,
70                AffectedValueCallbackVH::DMI>;
71   AffectedValuesMap AffectedValues;
72 
73   /// Get the vector of assumptions which affect a value from the cache.
74   SmallVector<WeakTrackingVH, 1> &getOrInsertAffectedValues(Value *V);
75 
76   /// Move affected values in the cache for OV to be affected values for NV.
77   void transferAffectedValuesInCache(Value *OV, Value *NV);
78 
79   /// Flag tracking whether we have scanned the function yet.
80   ///
81   /// We want to be as lazy about this as possible, and so we scan the function
82   /// at the last moment.
83   bool Scanned = false;
84 
85   /// Scan the function for assumptions and add them to the cache.
86   void scanFunction();
87 
88 public:
89   /// Construct an AssumptionCache from a function by scanning all of
90   /// its instructions.
AssumptionCache(Function & F)91   AssumptionCache(Function &F) : F(F) {}
92 
93   /// This cache is designed to be self-updating and so it should never be
94   /// invalidated.
invalidate(Function &,const PreservedAnalyses &,FunctionAnalysisManager::Invalidator &)95   bool invalidate(Function &, const PreservedAnalyses &,
96                   FunctionAnalysisManager::Invalidator &) {
97     return false;
98   }
99 
100   /// Add an \@llvm.assume intrinsic to this function's cache.
101   ///
102   /// The call passed in must be an instruction within this function and must
103   /// not already be in the cache.
104   void registerAssumption(CallInst *CI);
105 
106   /// Remove an \@llvm.assume intrinsic from this function's cache if it has
107   /// been added to the cache earlier.
108   void unregisterAssumption(CallInst *CI);
109 
110   /// Update the cache of values being affected by this assumption (i.e.
111   /// the values about which this assumption provides information).
112   void updateAffectedValues(CallInst *CI);
113 
114   /// Clear the cache of \@llvm.assume intrinsics for a function.
115   ///
116   /// It will be re-scanned the next time it is requested.
clear()117   void clear() {
118     AssumeHandles.clear();
119     AffectedValues.clear();
120     Scanned = false;
121   }
122 
123   /// Access the list of assumption handles currently tracked for this
124   /// function.
125   ///
126   /// Note that these produce weak handles that may be null. The caller must
127   /// handle that case.
128   /// FIXME: We should replace this with pointee_iterator<filter_iterator<...>>
129   /// when we can write that to filter out the null values. Then caller code
130   /// will become simpler.
assumptions()131   MutableArrayRef<WeakTrackingVH> assumptions() {
132     if (!Scanned)
133       scanFunction();
134     return AssumeHandles;
135   }
136 
137   /// Access the list of assumptions which affect this value.
assumptionsFor(const Value * V)138   MutableArrayRef<WeakTrackingVH> assumptionsFor(const Value *V) {
139     if (!Scanned)
140       scanFunction();
141 
142     auto AVI = AffectedValues.find_as(const_cast<Value *>(V));
143     if (AVI == AffectedValues.end())
144       return MutableArrayRef<WeakTrackingVH>();
145 
146     return AVI->second;
147   }
148 };
149 
150 /// A function analysis which provides an \c AssumptionCache.
151 ///
152 /// This analysis is intended for use with the new pass manager and will vend
153 /// assumption caches for a given function.
154 class AssumptionAnalysis : public AnalysisInfoMixin<AssumptionAnalysis> {
155   friend AnalysisInfoMixin<AssumptionAnalysis>;
156 
157   static AnalysisKey Key;
158 
159 public:
160   using Result = AssumptionCache;
161 
run(Function & F,FunctionAnalysisManager &)162   AssumptionCache run(Function &F, FunctionAnalysisManager &) {
163     return AssumptionCache(F);
164   }
165 };
166 
167 /// Printer pass for the \c AssumptionAnalysis results.
168 class AssumptionPrinterPass : public PassInfoMixin<AssumptionPrinterPass> {
169   raw_ostream &OS;
170 
171 public:
AssumptionPrinterPass(raw_ostream & OS)172   explicit AssumptionPrinterPass(raw_ostream &OS) : OS(OS) {}
173 
174   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
175 };
176 
177 /// An immutable pass that tracks lazily created \c AssumptionCache
178 /// objects.
179 ///
180 /// This is essentially a workaround for the legacy pass manager's weaknesses
181 /// which associates each assumption cache with Function and clears it if the
182 /// function is deleted. The nature of the AssumptionCache is that it is not
183 /// invalidated by any changes to the function body and so this is sufficient
184 /// to be conservatively correct.
185 class AssumptionCacheTracker : public ImmutablePass {
186   /// A callback value handle applied to function objects, which we use to
187   /// delete our cache of intrinsics for a function when it is deleted.
188   class FunctionCallbackVH final : public CallbackVH {
189     AssumptionCacheTracker *ACT;
190 
191     void deleted() override;
192 
193   public:
194     using DMI = DenseMapInfo<Value *>;
195 
196     FunctionCallbackVH(Value *V, AssumptionCacheTracker *ACT = nullptr)
CallbackVH(V)197         : CallbackVH(V), ACT(ACT) {}
198   };
199 
200   friend FunctionCallbackVH;
201 
202   using FunctionCallsMap =
203       DenseMap<FunctionCallbackVH, std::unique_ptr<AssumptionCache>,
204                FunctionCallbackVH::DMI>;
205 
206   FunctionCallsMap AssumptionCaches;
207 
208 public:
209   /// Get the cached assumptions for a function.
210   ///
211   /// If no assumptions are cached, this will scan the function. Otherwise, the
212   /// existing cache will be returned.
213   AssumptionCache &getAssumptionCache(Function &F);
214 
215   /// Return the cached assumptions for a function if it has already been
216   /// scanned. Otherwise return nullptr.
217   AssumptionCache *lookupAssumptionCache(Function &F);
218 
219   AssumptionCacheTracker();
220   ~AssumptionCacheTracker() override;
221 
releaseMemory()222   void releaseMemory() override {
223     verifyAnalysis();
224     AssumptionCaches.shrink_and_clear();
225   }
226 
227   void verifyAnalysis() const override;
228 
doFinalization(Module &)229   bool doFinalization(Module &) override {
230     verifyAnalysis();
231     return false;
232   }
233 
234   static char ID; // Pass identification, replacement for typeid
235 };
236 
237 } // end namespace llvm
238 
239 #endif // LLVM_ANALYSIS_ASSUMPTIONCACHE_H
240