LLVM 22.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/STLExtras.h"
21#include "llvm/IR/BasicBlock.h"
22#include "llvm/IR/Function.h"
23#include "llvm/IR/InstrTypes.h"
24#include "llvm/IR/Instruction.h"
26#include "llvm/IR/PassManager.h"
29#include "llvm/Pass.h"
34#include <cassert>
35
36using namespace llvm;
37using namespace llvm::PatternMatch;
38
39static cl::opt<bool>
40 VerifyAssumptionCache("verify-assumption-cache", cl::Hidden,
41 cl::desc("Enable verification of assumption cache"),
42 cl::init(false));
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 if (Bundle.getTagName() == "separate_storage") {
63 assert(Bundle.Inputs.size() == 2 && "separate_storage must have two args");
64 AddAffectedVal(getUnderlyingObject(Bundle.Inputs[0]));
65 AddAffectedVal(getUnderlyingObject(Bundle.Inputs[1]));
66 } else if (Bundle.Inputs.size() > ABA_WasOn &&
67 Bundle.getTagName() != IgnoreBundleTag)
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 if (llvm::none_of(AVV, [&](ResultElem &Elem) {
112 return Elem.Assume == CI && Elem.Index == AV.Index;
113 }))
114 AVV.push_back({CI, AV.Index});
115 }
116}
117
120 findAffectedValues(CI, TTI, Affected);
121
122 for (auto &AV : Affected) {
123 auto AVI = AffectedValues.find_as(AV.Assume);
124 if (AVI == AffectedValues.end())
125 continue;
126 bool Found = false;
127 bool HasNonnull = false;
128 for (ResultElem &Elem : AVI->second) {
129 if (Elem.Assume == CI) {
130 Found = true;
131 Elem.Assume = nullptr;
132 }
133 HasNonnull |= !!Elem.Assume;
134 if (HasNonnull && Found)
135 break;
136 }
137 assert(Found && "already unregistered or incorrect cache state");
138 if (!HasNonnull)
139 AffectedValues.erase(AVI);
140 }
141
142 llvm::erase(AssumeHandles, CI);
143}
144
146 AC->AffectedValues.erase(getValPtr());
147 // 'this' now dangles!
148}
149
150void AssumptionCache::transferAffectedValuesInCache(Value *OV, Value *NV) {
151 auto &NAVV = getOrInsertAffectedValues(NV);
152 auto AVI = AffectedValues.find(OV);
153 if (AVI == AffectedValues.end())
154 return;
155
156 for (auto &A : AVI->second)
157 if (!llvm::is_contained(NAVV, A))
158 NAVV.push_back(A);
159 AffectedValues.erase(OV);
160}
161
162void AssumptionCache::AffectedValueCallbackVH::allUsesReplacedWith(Value *NV) {
163 if (!isa<Instruction>(NV) && !isa<Argument>(NV))
164 return;
165
166 // Any assumptions that affected this value now affect the new value.
167
168 AC->transferAffectedValuesInCache(getValPtr(), NV);
169 // 'this' now might dangle! If the AffectedValues map was resized to add an
170 // entry for NV then this object might have been destroyed in favor of some
171 // copy in the grown map.
172}
173
174void AssumptionCache::scanFunction() {
175 assert(!Scanned && "Tried to scan the function twice!");
176 assert(AssumeHandles.empty() && "Already have assumes when scanning!");
177
178 // Go through all instructions in all blocks, add all calls to @llvm.assume
179 // to this cache.
180 for (BasicBlock &B : F)
181 for (Instruction &I : B)
182 if (isa<AssumeInst>(&I))
183 AssumeHandles.push_back(&I);
184
185 // Mark the scan as complete.
186 Scanned = true;
187
188 // Update affected values.
189 for (auto &A : AssumeHandles)
191}
192
194 // If we haven't scanned the function yet, just drop this assumption. It will
195 // be found when we scan later.
196 if (!Scanned)
197 return;
198
199 AssumeHandles.push_back(CI);
200
201#ifndef NDEBUG
202 assert(CI->getParent() &&
203 "Cannot register @llvm.assume call not in a basic block");
204 assert(&F == CI->getParent()->getParent() &&
205 "Cannot register @llvm.assume call not in this function");
206
207 // We expect the number of assumptions to be small, so in an asserts build
208 // check that we don't accumulate duplicates and that all assumptions point
209 // to the same function.
210 SmallPtrSet<Value *, 16> AssumptionSet;
211 for (auto &VH : AssumeHandles) {
212 if (!VH)
213 continue;
214
216 "Cached assumption not inside this function!");
218 "Cached something other than a call to @llvm.assume!");
219 assert(AssumptionSet.insert(VH).second &&
220 "Cache contains multiple copies of a call!");
221 }
222#endif
223
225}
226
232
233AnalysisKey AssumptionAnalysis::Key;
234
238
239 OS << "Cached assumptions for function: " << F.getName() << "\n";
240 for (auto &VH : AC.assumptions())
241 if (VH)
242 OS << " " << *cast<CallInst>(VH)->getArgOperand(0) << "\n";
243
244 return PreservedAnalyses::all();
245}
246
248 auto I = ACT->AssumptionCaches.find_as(cast<Function>(getValPtr()));
249 if (I != ACT->AssumptionCaches.end())
250 ACT->AssumptionCaches.erase(I);
251 // 'this' now dangles!
252}
253
255 // We probe the function map twice to try and avoid creating a value handle
256 // around the function in common cases. This makes insertion a bit slower,
257 // but if we have to insert we're going to scan the whole function so that
258 // shouldn't matter.
259 auto I = AssumptionCaches.find_as(&F);
260 if (I != AssumptionCaches.end())
261 return *I->second;
262
264 auto *TTI = TTIWP ? &TTIWP->getTTI(F) : nullptr;
265
266 // Ok, build a new cache by scanning the function, insert it and the value
267 // handle into our map, and return the newly populated cache.
268 auto IP = AssumptionCaches.insert(std::make_pair(
269 FunctionCallbackVH(&F, this), std::make_unique<AssumptionCache>(F, TTI)));
270 assert(IP.second && "Scanning function already in the map?");
271 return *IP.first->second;
272}
273
275 auto I = AssumptionCaches.find_as(&F);
276 if (I != AssumptionCaches.end())
277 return I->second.get();
278 return nullptr;
279}
280
282 // FIXME: In the long term the verifier should not be controllable with a
283 // flag. We should either fix all passes to correctly update the assumption
284 // cache and enable the verifier unconditionally or somehow arrange for the
285 // assumption list to be updated automatically by passes.
287 return;
288
290 for (const auto &I : AssumptionCaches) {
291 for (auto &VH : I.second->assumptions())
292 if (VH)
293 AssumptionSet.insert(cast<CallInst>(VH));
294
295 for (const BasicBlock &B : cast<Function>(*I.first))
296 for (const Instruction &II : B)
298 !AssumptionSet.count(cast<CallInst>(&II)))
299 report_fatal_error("Assumption in scanned function not in cache");
300 }
301}
302
304
306
308
309INITIALIZE_PASS(AssumptionCacheTracker, "assumption-cache-tracker",
310 "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 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 pass exposes codegen information to IR-level passes.
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 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 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
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
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.
Value * getValPtr() const
LLVM Value Representation.
Definition Value.h:75
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)
IntrinsicID_match m_Intrinsic()
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.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
constexpr StringRef IgnoreBundleTag
Tag in operand bundle indicating that this bundle should be ignored.
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition STLExtras.h:2128
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:1739
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:167
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:1897
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