LLVM 23.0.0git
AssumptionCache.cpp
Go to the documentation of this file.
1//===- AssumptionCache.cpp - Cache finding @llvm.assume calls -------------===//
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.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/DenseSet.h"
16#include "llvm/ADT/STLExtras.h"
23#include "llvm/IR/BasicBlock.h"
24#include "llvm/IR/Function.h"
25#include "llvm/IR/InstrTypes.h"
26#include "llvm/IR/Instruction.h"
28#include "llvm/IR/PassManager.h"
31#include "llvm/Pass.h"
36#include <cassert>
37
38using namespace llvm;
39using namespace llvm::PatternMatch;
40
41static cl::opt<bool>
42 VerifyAssumptionCache("verify-assumption-cache", cl::Hidden,
43 cl::desc("Enable verification of assumption cache"),
44 cl::init(false));
45
47AssumptionCache::getOrInsertAffectedValues(Value *V) {
48 // Try using find_as first to avoid creating extra value handles just for the
49 // purpose of doing the lookup.
50 auto AVI = AffectedValues.find_as(V);
51 if (AVI != AffectedValues.end())
52 return AVI->second;
53
54 return AffectedValues[AffectedValueCallbackVH(V, this)];
55}
56
58 OperandBundleUse Bundle, function_ref<void(Value *)> InsertAffected) {
59 auto AddAffectedVal = [&](Value *V) {
61 InsertAffected(V);
62 };
63
64 if (Bundle.getTagName() == "separate_storage") {
65 assert(Bundle.Inputs.size() == 2 && "separate_storage must have two args");
66 AddAffectedVal(getUnderlyingObject(Bundle.Inputs[0]));
67 AddAffectedVal(getUnderlyingObject(Bundle.Inputs[1]));
68 } else if (Bundle.Inputs.size() > ABA_WasOn &&
69 Bundle.getTagName() != IgnoreBundleTag)
70 AddAffectedVal(Bundle.Inputs[ABA_WasOn]);
71}
72
73static void
76 // Note: This code must be kept in-sync with the code in
77 // computeKnownBitsFromAssume in ValueTracking.
78
79 auto InsertAffected = [&Affected](Value *V) {
81 };
82
83 auto AddAffectedVal = [&Affected](Value *V, unsigned Idx) {
85 Affected.push_back({V, Idx});
86 }
87 };
88
89 for (unsigned Idx = 0; Idx != CI->getNumOperandBundles(); Idx++)
91 CI->getOperandBundleAt(Idx),
92 [&](Value *V) { Affected.push_back({V, Idx}); });
93
94 Value *Cond = CI->getArgOperand(0);
95 findValuesAffectedByCondition(Cond, /*IsAssume=*/true, InsertAffected);
96
97 if (TTI) {
98 const Value *Ptr;
99 unsigned AS;
100 std::tie(Ptr, AS) = TTI->getPredicatedAddrSpace(Cond);
101 if (Ptr)
102 AddAffectedVal(const_cast<Value *>(Ptr->stripInBoundsOffsets()),
104 }
105}
106
109 findAffectedValues(CI, TTI, Affected);
110
111 for (auto &AV : Affected) {
112 auto &AVV = getOrInsertAffectedValues(AV.Assume);
113 if (llvm::none_of(AVV, [&](ResultElem &Elem) {
114 return Elem.Assume == CI && Elem.Index == AV.Index;
115 }))
116 AVV.push_back({CI, AV.Index});
117 }
118}
119
120void AssumptionCache::removeAffectedValues(AssumeInst *CI) {
122 findAffectedValues(CI, TTI, Affected);
123
124 // If a value appears more than once in an AssumeInst e.g., 'ptr %arg1' in:
125 // call void @llvm.assume(i1 true)
126 // [ "dereferenceable"(ptr %arg1, i64 1),
127 // "align"(ptr %arg1, i64 8) ]
128 // it will appear multiple times in Affected, but we may (depending on
129 // how the results in AffectedValues.find_as(AV.Assume) are ordered)
130 // nullify multiple instances of Elem.Assume during one iteration of the
131 // 'for (auto &AV : Affected)' loop below. The next iteration of that for
132 // loop may then find only a match to a different AssumeInst, resulting in
133 // an assertion failure. Avoid this by counting the number of expected
134 // matches.
135#ifndef NDEBUG
137 DenseMap<Value *, int> ExpectedMatches;
138 for (auto &AV : Affected)
139 if (Seen.insert({AV.Assume, AV.Index}).second &&
140 AffectedValues.find_as(AV.Assume) != AffectedValues.end())
141 ExpectedMatches[AV.Assume]++;
142#endif
143
144 for (auto &AV : Affected) {
145 auto AVI = AffectedValues.find_as(AV.Assume);
146 if (AVI == AffectedValues.end())
147 continue;
148 bool Found = false;
149 bool HasNonnull = false;
150 for (ResultElem &Elem : AVI->second) {
151 if (Elem.Assume == CI) {
152 Found = true;
153 Elem.Assume = nullptr;
154
155#ifndef NDEBUG
156 ExpectedMatches[AV.Assume]--;
157#endif
158 assert(ExpectedMatches[AV.Assume] >= 0);
159 // After ExpectedMatches[AV.Assume] == 0, we still need to iterate
160 // through this loop to determine the value of HasNonnull, to avoid
161 // prematurely calling AffectedValues.erase(AVI).
162 }
163 HasNonnull |= !!Elem.Assume;
164 if (HasNonnull && Found)
165 break;
166 }
167
168 assert(ExpectedMatches[AV.Assume] == 0 ||
169 Found && "already unregistered or incorrect cache state");
170
171 if (!HasNonnull)
172 AffectedValues.erase(AVI);
173 }
174
175 assert(
176 none_of(Affected, [&](auto &AV) { return ExpectedMatches[AV.Assume]; }) &&
177 "already unregistered or incorrect cache state");
178}
179
181 removeAffectedValues(CI);
182 llvm::erase(AssumeHandles, CI);
183}
184
186 removeAffectedValues(cast<AssumeInst>(Handle));
187 Handle = New;
189}
190
192 AC->AffectedValues.erase(getValPtr());
193 // 'this' now dangles!
194}
195
196void AssumptionCache::transferAffectedValuesInCache(Value *OV, Value *NV) {
197 auto &NAVV = getOrInsertAffectedValues(NV);
198 auto AVI = AffectedValues.find(OV);
199 if (AVI == AffectedValues.end())
200 return;
201
202 for (auto &A : AVI->second)
203 if (!llvm::is_contained(NAVV, A))
204 NAVV.push_back(A);
205 AffectedValues.erase(OV);
206}
207
208void AssumptionCache::AffectedValueCallbackVH::allUsesReplacedWith(Value *NV) {
209 if (!isa<Instruction>(NV) && !isa<Argument>(NV))
210 return;
211
212 // Any assumptions that affected this value now affect the new value.
213
214 AC->transferAffectedValuesInCache(getValPtr(), NV);
215 // 'this' now might dangle! If the AffectedValues map was resized to add an
216 // entry for NV then this object might have been destroyed in favor of some
217 // copy in the grown map.
218}
219
220void AssumptionCache::scanFunction() {
221 assert(!Scanned && "Tried to scan the function twice!");
222 assert(AssumeHandles.empty() && "Already have assumes when scanning!");
223
224 // Go through all instructions in all blocks, add all calls to @llvm.assume
225 // to this cache.
226 for (BasicBlock &B : F)
227 for (Instruction &I : B)
228 if (isa<AssumeInst>(&I))
229 AssumeHandles.push_back(&I);
230
231 // Mark the scan as complete.
232 Scanned = true;
233
234 // Update affected values.
235 for (auto &A : AssumeHandles)
237}
238
240 // If we haven't scanned the function yet, just drop this assumption. It will
241 // be found when we scan later.
242 if (!Scanned)
243 return;
244
245 AssumeHandles.push_back(CI);
246
247#ifndef NDEBUG
248 assert(CI->getParent() &&
249 "Cannot register @llvm.assume call not in a basic block");
250 assert(&F == CI->getParent()->getParent() &&
251 "Cannot register @llvm.assume call not in this function");
252
253 // We expect the number of assumptions to be small, so in an asserts build
254 // check that we don't accumulate duplicates and that all assumptions point
255 // to the same function.
256 SmallPtrSet<Value *, 16> AssumptionSet;
257 for (auto &VH : AssumeHandles) {
258 if (!VH)
259 continue;
260
262 "Cached assumption not inside this function!");
264 "Cached something other than a call to @llvm.assume!");
265 assert(AssumptionSet.insert(VH).second &&
266 "Cache contains multiple copies of a call!");
267 }
268#endif
269
271}
272
278
279AnalysisKey AssumptionAnalysis::Key;
280
284
285 OS << "Cached assumptions for function: " << F.getName() << "\n";
286 for (auto &VH : AC.assumptions()) {
287 if (!VH)
288 continue;
289
290 auto *Assume = cast<CallInst>(VH);
291 if (!Assume->hasOperandBundles()) {
292 OS << " " << *Assume->getArgOperand(0) << "\n";
293 continue;
294 }
295
296 assert(match(Assume->getArgOperand(0), m_One()) &&
297 "assume must have trivial cond");
298 OS << " [ ";
299 ListSeparator LS;
300 for (const OperandBundleUse &BU : Assume->operand_bundles()) {
301 OS << LS << '"' << BU.getTagName() << "\"(";
302 interleaveComma(BU.Inputs, OS,
303 [&](const Use &Input) { Input->printAsOperand(OS); });
304 OS << ')';
305 }
306 OS << " ]\n";
307 }
308
309 return PreservedAnalyses::all();
310}
311
313 auto I = ACT->AssumptionCaches.find_as(cast<Function>(getValPtr()));
314 if (I != ACT->AssumptionCaches.end())
315 ACT->AssumptionCaches.erase(I);
316 // 'this' now dangles!
317}
318
320 // We probe the function map twice to try and avoid creating a value handle
321 // around the function in common cases. This makes insertion a bit slower,
322 // but if we have to insert we're going to scan the whole function so that
323 // shouldn't matter.
324 auto I = AssumptionCaches.find_as(&F);
325 if (I != AssumptionCaches.end())
326 return *I->second;
327
329 auto *TTI = TTIWP ? &TTIWP->getTTI(F) : nullptr;
330
331 // Ok, build a new cache by scanning the function, insert it and the value
332 // handle into our map, and return the newly populated cache.
333 auto IP = AssumptionCaches.insert(std::make_pair(
334 FunctionCallbackVH(&F, this), std::make_unique<AssumptionCache>(F, TTI)));
335 assert(IP.second && "Scanning function already in the map?");
336 return *IP.first->second;
337}
338
340 auto I = AssumptionCaches.find_as(&F);
341 if (I != AssumptionCaches.end())
342 return I->second.get();
343 return nullptr;
344}
345
347 // FIXME: In the long term the verifier should not be controllable with a
348 // flag. We should either fix all passes to correctly update the assumption
349 // cache and enable the verifier unconditionally or somehow arrange for the
350 // assumption list to be updated automatically by passes.
352 return;
353
355 for (const auto &I : AssumptionCaches) {
356 for (auto &VH : I.second->assumptions())
357 if (VH)
358 AssumptionSet.insert(cast<CallInst>(VH));
359
360 for (const BasicBlock &B : cast<Function>(*I.first))
361 for (const Instruction &II : B)
363 !AssumptionSet.count(cast<CallInst>(&II)))
364 report_fatal_error("Assumption in scanned function not in cache");
365 }
366}
367
369
371
373
374INITIALIZE_PASS(AssumptionCacheTracker, "assumption-cache-tracker",
375 "Assumption Cache Tracker", false, true)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static void findAffectedValues(CallBase *CI, TargetTransformInfo *TTI, SmallVectorImpl< AssumptionCache::ResultElem > &Affected)
static cl::opt< bool > VerifyAssumptionCache("verify-assumption-cache", cl::Hidden, cl::desc("Enable verification of assumption cache"), cl::init(false))
static const Function * getParent(const Value *V)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseSet and SmallDenseSet classes.
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
const SmallVectorImpl< MachineOperand > & Cond
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
This pass exposes codegen information to IR-level passes.
The Input class is used to parse a yaml document into in-memory structs and vectors.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
This represents the llvm.assume intrinsic.
A function analysis which provides an AssumptionCache.
LLVM_ABI AssumptionCache run(Function &F, FunctionAnalysisManager &)
An immutable pass that tracks lazily created AssumptionCache objects.
AssumptionCache * lookupAssumptionCache(Function &F)
Return the cached assumptions for a function if it has already been scanned.
void verifyAnalysis() const override
verifyAnalysis() - This member can be implemented by a analysis pass to check state of analysis infor...
AssumptionCache & getAssumptionCache(Function &F)
Get the cached assumptions for a function.
A cache of @llvm.assume calls within a function.
static LLVM_ABI void findValuesAffectedByOperandBundle(OperandBundleUse Bundle, function_ref< void(Value *)> InsertAffected)
Determine which values are affected by this assume operand bundle.
LLVM_ABI void registerAssumption(AssumeInst *CI)
Add an @llvm.assume intrinsic to this function's cache.
LLVM_ABI void replaceAssumption(WeakVH &Handle, AssumeInst *New)
Replace the assumption referenced by Handle (must be a valid handle for a registered assumption) with...
LLVM_ABI void updateAffectedValues(AssumeInst *CI)
Update the cache of values being affected by this assumption (i.e.
MutableArrayRef< WeakVH > assumptions()
Access the list of assumption handles currently tracked for this function.
LLVM_ABI void unregisterAssumption(AssumeInst *CI)
Remove an @llvm.assume intrinsic from this function's cache if it has been added to the cache earlier...
AssumptionCache(Function &F, TargetTransformInfo *TTI=nullptr)
Construct an AssumptionCache from a function by scanning all of its instructions.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
LLVM Basic Block Representation.
Definition BasicBlock.h:62
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
OperandBundleUse getOperandBundleAt(unsigned Index) const
Return the operand bundle at a specific index.
unsigned getNumOperandBundles() const
Return the number of operand bundles associated with this User.
virtual void deleted()
Callback for Value destruction.
ImmutablePass(char &pid)
Definition Pass.h:287
A helper class to return the specified delimiter string after the first invocation of operator String...
AnalysisType * getAnalysisIfAvailable() const
getAnalysisIfAvailable<AnalysisType>() - Subclasses use this function to get analysis information tha...
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
Implements a dense probed hash-table based set with some number of buckets stored inline.
Definition DenseSet.h:293
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Analysis pass providing the TargetTransformInfo.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
Value * getValPtr() const
LLVM Value Representation.
Definition Value.h:75
LLVM_ABI const Value * stripInBoundsOffsets(function_ref< void(const Value *)> Func=[](const Value *) {}) const
Strip off pointer casts and inbounds GEPs.
Definition Value.cpp:828
A nullable Value handle that is nullable.
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
bool match(Val *V, const Pattern &P)
cst_pred_ty< is_one > m_One()
Match an integer 1 or a vector with all elements equal to 1.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
constexpr StringRef IgnoreBundleTag
Tag in operand bundle indicating that this bundle should be ignored.
void interleaveComma(const Container &c, StreamT &os, UnaryFunctor each_fn)
Definition STLExtras.h:2313
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition STLExtras.h:2200
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1753
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
TargetTransformInfo TTI
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
LLVM_ABI void findValuesAffectedByCondition(Value *Cond, bool IsAssume, function_ref< void(Value *)> InsertAffected)
Call InsertAffected on all Values whose known bits / value may be affected by the condition Cond.
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition Analysis.h:29
unsigned Index
contains either ExprResultIdx or the index of the operand bundle containing the knowledge.
A lightweight accessor for an operand bundle meant to be passed around by value.
StringRef getTagName() const
Return the tag of this operand bundle as a string.
ArrayRef< Use > Inputs