LLVM 24.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 "AnalysisOptions.h"
16#include "llvm/ADT/STLExtras.h"
23#include "llvm/IR/BasicBlock.h"
25#include "llvm/IR/Function.h"
26#include "llvm/IR/InstrTypes.h"
27#include "llvm/IR/Instruction.h"
29#include "llvm/IR/PassManager.h"
32#include "llvm/Pass.h"
36#include <cassert>
37
38using namespace llvm;
39using namespace llvm::PatternMatch;
40
43
45AssumptionCache::getOrInsertAffectedValues(Value *V) {
46 // Try using find_as first to avoid creating extra value handles just for the
47 // purpose of doing the lookup.
48 auto AVI = AffectedValues.find_as(V);
49 if (AVI != AffectedValues.end())
50 return AVI->second;
51
52 return AffectedValues[AffectedValueCallbackVH(V, this)];
53}
54
56 OperandBundleUse Bundle, function_ref<void(Value *)> InsertAffected) {
57 auto AddAffectedVal = [&](Value *V) {
59 InsertAffected(V);
60 };
61
62 auto Attr = getBundleAttrFromOBU(Bundle);
63 if (Attr == BundleAttr::SeparateStorage) {
64 assert(Bundle.Inputs.size() == 2 && "separate_storage must have two args");
65 AddAffectedVal(getUnderlyingObject(Bundle.Inputs[0]));
66 AddAffectedVal(getUnderlyingObject(Bundle.Inputs[1]));
67 } else if (Bundle.Inputs.size() > ABA_WasOn && Attr != BundleAttr::Ignore)
68 AddAffectedVal(Bundle.Inputs[ABA_WasOn]);
69}
70
71static void
74 // Note: This code must be kept in-sync with the code in
75 // computeKnownBitsFromAssume in ValueTracking.
76
77 auto InsertAffected = [&Affected](Value *V) {
79 };
80
81 auto AddAffectedVal = [&Affected](Value *V, unsigned Idx) {
83 Affected.push_back({V, Idx});
84 }
85 };
86
87 for (unsigned Idx = 0; Idx != CI->getNumOperandBundles(); Idx++)
89 CI->getOperandBundleAt(Idx),
90 [&](Value *V) { Affected.push_back({V, Idx}); });
91
92 Value *Cond = CI->getArgOperand(0);
93 findValuesAffectedByCondition(Cond, /*IsAssume=*/true, InsertAffected);
94
95 if (TTI) {
96 const Value *Ptr;
97 unsigned AS;
98 std::tie(Ptr, AS) = TTI->getPredicatedAddrSpace(Cond);
99 if (Ptr)
100 AddAffectedVal(const_cast<Value *>(Ptr->stripInBoundsOffsets()),
102 }
103}
104
107 findAffectedValues(CI, TTI, Affected);
108
109 for (auto &AV : Affected) {
110 auto &AVV = getOrInsertAffectedValues(AV.Assume);
111
112 // Callers walk every entry cached for a value, including the ones left
113 // behind by erased assumptions, so cache no more of them than an analysis
114 // should walk.
115 if (AVV.size() >= Opts.max_assumes_per_value)
116 continue;
117
118 if (llvm::none_of(AVV, [&](ResultElem &Elem) {
119 return Elem.Assume == CI && Elem.Index == AV.Index;
120 }))
121 AVV.push_back({CI, AV.Index});
122 }
123}
124
125void AssumptionCache::removeAffectedValues(AssumeInst *CI) {
127 findAffectedValues(CI, TTI, Affected);
128
129 for (auto &AV : Affected) {
130 auto AVI = AffectedValues.find_as(AV.Assume);
131 if (AVI == AffectedValues.end())
132 continue;
133 bool Found = false;
134 bool HasNonnull = false;
135 for (ResultElem &Elem : AVI->second) {
136 if (Elem.Assume == CI) {
137 Found = true;
138 Elem.Assume = nullptr;
139 }
140
141 // We need to iterate through this loop to determine the value of
142 // HasNonnull, to avoid prematurely calling AffectedValues.erase(AVI).
143 HasNonnull |= !!Elem.Assume;
144 if (HasNonnull && Found)
145 break;
146 }
147
148 if (!Found) {
149 // It may well be the case that we fail to find an affected value in the
150 // cache. In particular, if an assume call is updated via `Use::set()`, we
151 // won't be notified that the affected value has changed and the cache
152 // will silently go stale.
153 } else if (!HasNonnull)
154 AffectedValues.erase(AVI);
155 }
156}
157
159 removeAffectedValues(CI);
160 llvm::erase(AssumeHandles, CI);
161}
162
164 removeAffectedValues(cast<AssumeInst>(Handle));
165 Handle = New;
167}
168
170 AC->AffectedValues.erase(getValPtr());
171 // 'this' now dangles!
172}
173
174void AssumptionCache::transferAffectedValuesInCache(Value *OV, Value *NV) {
175 auto &NAVV = getOrInsertAffectedValues(NV);
176 auto AVI = AffectedValues.find(OV);
177 if (AVI == AffectedValues.end())
178 return;
179
180 for (auto &A : AVI->second) {
181 if (NAVV.size() >= Opts.max_assumes_per_value)
182 break;
183 if (!llvm::is_contained(NAVV, A))
184 NAVV.push_back(A);
185 }
186 AffectedValues.erase(OV);
187}
188
189void AssumptionCache::AffectedValueCallbackVH::allUsesReplacedWith(Value *NV) {
190 if (!isa<Instruction>(NV) && !isa<Argument>(NV))
191 return;
192
193 // Any assumptions that affected this value now affect the new value.
194
195 AC->transferAffectedValuesInCache(getValPtr(), NV);
196 // 'this' now might dangle! If the AffectedValues map was resized to add an
197 // entry for NV then this object might have been destroyed in favor of some
198 // copy in the grown map.
199}
200
201void AssumptionCache::scanFunction() {
202 assert(!Scanned && "Tried to scan the function twice!");
203 assert(AssumeHandles.empty() && "Already have assumes when scanning!");
204
205 // Go through all instructions in all blocks, add all calls to @llvm.assume
206 // to this cache.
207 for (BasicBlock &B : F)
208 for (Instruction &I : B)
209 if (isa<AssumeInst>(&I))
210 AssumeHandles.push_back(&I);
211
212 // Mark the scan as complete.
213 Scanned = true;
214
215 // Update affected values.
216 for (auto &A : AssumeHandles)
218}
219
220/// Check the assumptions cached for \p F, collecting them in \p Cached. Returns
221/// a description of the first invariant violated, or nullptr if there is none.
222static const char *
225 for (const WeakVH &VH : Assumptions) {
226 if (!VH)
227 continue;
228
229 const auto *CI = cast<CallInst>(VH);
230 if (CI->getFunction() != &F)
231 return "Cached assumption not inside this function";
233 return "Cached something other than a call to @llvm.assume";
234 if (!Cached.insert(CI).second)
235 return "Cache contains multiple copies of a call";
236 }
237
238 return nullptr;
239}
240
242 // If we haven't scanned the function yet, just drop this assumption. It will
243 // be found when we scan later.
244 if (!Scanned)
245 return;
246
247 AssumeHandles.push_back(CI);
248
249#ifndef NDEBUG
250 assert(CI->getParent() &&
251 "Cannot register @llvm.assume call not in a basic block");
252 assert(&F == CI->getParent()->getParent() &&
253 "Cannot register @llvm.assume call not in this function");
254
255 // We expect the number of assumptions to be small, so in an asserts build
256 // check that we don't accumulate duplicates and that all assumptions point
257 // to the same function. Scanning the whole cache on every registration is
258 // quadratic, so stop once it outgrows that expectation unless expensive
259 // checks are enabled. Larger caches are checked by
260 // AssumptionCacheTracker::verifyAnalysis() instead.
261#ifdef EXPENSIVE_CHECKS
262 constexpr unsigned MaxAssumesToVerify = std::numeric_limits<unsigned>::max();
263#else
264 constexpr unsigned MaxAssumesToVerify = 64;
265#endif
266 if (AssumeHandles.size() <= MaxAssumesToVerify) {
268 if (const char *Violation = findCacheViolation(F, AssumeHandles, Cached))
269 llvm_unreachable(Violation);
270 }
271#endif
272
274}
275
281
282AnalysisKey AssumptionAnalysis::Key;
283
287
288 OS << "Cached assumptions for function: " << F.getName() << "\n";
289 for (auto &VH : AC.assumptions()) {
290 if (!VH)
291 continue;
292
293 auto *Assume = cast<CallInst>(VH);
294 if (!Assume->hasOperandBundles()) {
295 OS << " " << *Assume->getArgOperand(0) << "\n";
296 continue;
297 }
298
299 assert(match(Assume->getArgOperand(0), m_One()) &&
300 "assume must have trivial cond");
301 OS << " [ ";
302 ListSeparator LS;
303 for (const OperandBundleUse &BU : Assume->operand_bundles()) {
304 OS << LS << '"' << BU.getTagName() << "\"(";
305 interleaveComma(BU.Inputs, OS,
306 [&](const Use &Input) { Input->printAsOperand(OS); });
307 OS << ')';
308 }
309 OS << " ]\n";
310 }
311
312 return PreservedAnalyses::all();
313}
314
316 auto I = ACT->AssumptionCaches.find_as(cast<Function>(getValPtr()));
317 if (I != ACT->AssumptionCaches.end())
318 ACT->AssumptionCaches.erase(I);
319 // 'this' now dangles!
320}
321
323 // We probe the function map twice to try and avoid creating a value handle
324 // around the function in common cases. This makes insertion a bit slower,
325 // but if we have to insert we're going to scan the whole function so that
326 // shouldn't matter.
327 auto I = AssumptionCaches.find_as(&F);
328 if (I != AssumptionCaches.end())
329 return *I->second;
330
332 auto *TTI = TTIWP ? &TTIWP->getTTI(F) : nullptr;
333
334 // Ok, build a new cache by scanning the function, insert it and the value
335 // handle into our map, and return the newly populated cache.
336 auto IP = AssumptionCaches.insert(std::make_pair(
337 FunctionCallbackVH(&F, this), std::make_unique<AssumptionCache>(F, TTI)));
338 assert(IP.second && "Scanning function already in the map?");
339 return *IP.first->second;
340}
341
343 // FIXME: In the long term the verifier should not be controllable with a
344 // flag. We should either fix all passes to correctly update the assumption
345 // cache and enable the verifier unconditionally or somehow arrange for the
346 // assumption list to be updated automatically by passes.
347 for (const auto &I : AssumptionCaches) {
348 const Function &F = cast<Function>(*I.first);
349 if (!getAnalysisOptions(F).verify_assumption_cache)
350 continue;
351
353 if (const char *Violation =
354 findCacheViolation(F, I.second->assumptions(), Cached))
355 report_fatal_error(Violation);
356
357 for (const BasicBlock &B : F)
358 for (const Instruction &II : B)
360 !Cached.count(cast<CallInst>(&II)))
361 report_fatal_error("Assumption in scanned function not in cache");
362 }
363}
364
366
368
370
371INITIALIZE_PASS(AssumptionCacheTracker, "assumption-cache-tracker",
372 "Assumption Cache Tracker", false, true)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static const char * findCacheViolation(const Function &F, ArrayRef< WeakVH > Assumptions, SmallPtrSetImpl< const CallInst * > &Cached)
Check the assumptions cached for F, collecting them in Cached.
static void findAffectedValues(CallBase *CI, TargetTransformInfo *TTI, SmallVectorImpl< AssumptionCache::ResultElem > &Affected)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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
SmallVector< MachineOperand, 4 > 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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
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.
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...
LLVM_ABI 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:285
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
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
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
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:824
A nullable Value handle that is nullable.
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
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))
This is an optimization pass for GlobalISel generic memory operations.
BundleAttr getBundleAttrFromOBU(OperandBundleUse OBU)
void interleaveComma(const Container &c, StreamT &os, UnaryFunctor each_fn)
Definition STLExtras.h:2329
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
const AnalysisOptions & getAnalysisOptions(const LLVMContext &C)
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition STLExtras.h:2216
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:1769
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth, bool MustPreserveProvenance=false)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
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:1963
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
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.
ArrayRef< Use > Inputs