LLVM 18.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"
20#include "llvm/IR/BasicBlock.h"
21#include "llvm/IR/Function.h"
22#include "llvm/IR/InstrTypes.h"
23#include "llvm/IR/Instruction.h"
25#include "llvm/IR/PassManager.h"
28#include "llvm/Pass.h"
33#include <cassert>
34#include <utility>
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 auto AVIP = AffectedValues.insert(
53 {AffectedValueCallbackVH(V, this), SmallVector<ResultElem, 1>()});
54 return AVIP.first->second;
55}
56
57static void
60 // Note: This code must be kept in-sync with the code in
61 // computeKnownBitsFromAssume in ValueTracking.
62
63 auto AddAffected = [&Affected](Value *V, unsigned Idx =
65 if (isa<Argument>(V) || isa<GlobalValue>(V)) {
66 Affected.push_back({V, Idx});
67 } else if (auto *I = dyn_cast<Instruction>(V)) {
68 Affected.push_back({I, Idx});
69
70 // Peek through unary operators to find the source of the condition.
71 Value *Op;
72 if (match(I, m_BitCast(m_Value(Op))) ||
74 if (isa<Instruction>(Op) || isa<Argument>(Op))
75 Affected.push_back({Op, Idx});
76 }
77 }
78 };
79
80 for (unsigned Idx = 0; Idx != CI->getNumOperandBundles(); Idx++) {
81 if (CI->getOperandBundleAt(Idx).Inputs.size() > ABA_WasOn &&
82 CI->getOperandBundleAt(Idx).getTagName() != IgnoreBundleTag)
83 AddAffected(CI->getOperandBundleAt(Idx).Inputs[ABA_WasOn], Idx);
84 }
85
86 Value *Cond = CI->getArgOperand(0), *A, *B;
87 AddAffected(Cond);
88
90 if (match(Cond, m_Cmp(Pred, m_Value(A), m_Value(B)))) {
91 AddAffected(A);
92 AddAffected(B);
93
94 if (Pred == ICmpInst::ICMP_EQ) {
95 // For equality comparisons, we handle the case of bit inversion.
96 auto AddAffectedFromEq = [&AddAffected](Value *V) {
97 Value *A;
98 if (match(V, m_Not(m_Value(A)))) {
99 AddAffected(A);
100 V = A;
101 }
102
103 Value *B;
104 // (A & B) or (A | B) or (A ^ B).
105 if (match(V, m_BitwiseLogic(m_Value(A), m_Value(B)))) {
106 AddAffected(A);
107 AddAffected(B);
108 // (A << C) or (A >>_s C) or (A >>_u C) where C is some constant.
109 } else if (match(V, m_Shift(m_Value(A), m_ConstantInt()))) {
110 AddAffected(A);
111 }
112 };
113
114 AddAffectedFromEq(A);
115 AddAffectedFromEq(B);
116 } else if (Pred == ICmpInst::ICMP_NE) {
117 Value *X, *Y;
118 // Handle (a & b != 0). If a/b is a power of 2 we can use this
119 // information.
120 if (match(A, m_And(m_Value(X), m_Value(Y))) && match(B, m_Zero())) {
121 AddAffected(X);
122 AddAffected(Y);
123 }
124 } else if (Pred == ICmpInst::ICMP_ULT) {
125 Value *X;
126 // Handle (A + C1) u< C2, which is the canonical form of A > C3 && A < C4,
127 // and recognized by LVI at least.
128 if (match(A, m_Add(m_Value(X), m_ConstantInt())) &&
130 AddAffected(X);
131 } else if (CmpInst::isFPPredicate(Pred)) {
132 // fcmp fneg(x), y
133 // fcmp fabs(x), y
134 // fcmp fneg(fabs(x)), y
135 if (match(A, m_FNeg(m_Value(A))))
136 AddAffected(A);
137 if (match(A, m_FAbs(m_Value(A))))
138 AddAffected(A);
139 }
140 } else if (match(Cond, m_Intrinsic<Intrinsic::is_fpclass>(m_Value(A),
141 m_Value(B)))) {
142 AddAffected(A);
143 }
144
145 if (TTI) {
146 const Value *Ptr;
147 unsigned AS;
148 std::tie(Ptr, AS) = TTI->getPredicatedAddrSpace(Cond);
149 if (Ptr)
150 AddAffected(const_cast<Value *>(Ptr->stripInBoundsOffsets()));
151 }
152}
153
156 findAffectedValues(CI, TTI, Affected);
157
158 for (auto &AV : Affected) {
159 auto &AVV = getOrInsertAffectedValues(AV.Assume);
160 if (llvm::none_of(AVV, [&](ResultElem &Elem) {
161 return Elem.Assume == CI && Elem.Index == AV.Index;
162 }))
163 AVV.push_back({CI, AV.Index});
164 }
165}
166
169 findAffectedValues(CI, TTI, Affected);
170
171 for (auto &AV : Affected) {
172 auto AVI = AffectedValues.find_as(AV.Assume);
173 if (AVI == AffectedValues.end())
174 continue;
175 bool Found = false;
176 bool HasNonnull = false;
177 for (ResultElem &Elem : AVI->second) {
178 if (Elem.Assume == CI) {
179 Found = true;
180 Elem.Assume = nullptr;
181 }
182 HasNonnull |= !!Elem.Assume;
183 if (HasNonnull && Found)
184 break;
185 }
186 assert(Found && "already unregistered or incorrect cache state");
187 if (!HasNonnull)
188 AffectedValues.erase(AVI);
189 }
190
191 erase_value(AssumeHandles, CI);
192}
193
194void AssumptionCache::AffectedValueCallbackVH::deleted() {
195 AC->AffectedValues.erase(getValPtr());
196 // 'this' now dangles!
197}
198
199void AssumptionCache::transferAffectedValuesInCache(Value *OV, Value *NV) {
200 auto &NAVV = getOrInsertAffectedValues(NV);
201 auto AVI = AffectedValues.find(OV);
202 if (AVI == AffectedValues.end())
203 return;
204
205 for (auto &A : AVI->second)
206 if (!llvm::is_contained(NAVV, A))
207 NAVV.push_back(A);
208 AffectedValues.erase(OV);
209}
210
211void AssumptionCache::AffectedValueCallbackVH::allUsesReplacedWith(Value *NV) {
212 if (!isa<Instruction>(NV) && !isa<Argument>(NV))
213 return;
214
215 // Any assumptions that affected this value now affect the new value.
216
217 AC->transferAffectedValuesInCache(getValPtr(), NV);
218 // 'this' now might dangle! If the AffectedValues map was resized to add an
219 // entry for NV then this object might have been destroyed in favor of some
220 // copy in the grown map.
221}
222
223void AssumptionCache::scanFunction() {
224 assert(!Scanned && "Tried to scan the function twice!");
225 assert(AssumeHandles.empty() && "Already have assumes when scanning!");
226
227 // Go through all instructions in all blocks, add all calls to @llvm.assume
228 // to this cache.
229 for (BasicBlock &B : F)
230 for (Instruction &I : B)
231 if (isa<AssumeInst>(&I))
232 AssumeHandles.push_back({&I, ExprResultIdx});
233
234 // Mark the scan as complete.
235 Scanned = true;
236
237 // Update affected values.
238 for (auto &A : AssumeHandles)
239 updateAffectedValues(cast<AssumeInst>(A));
240}
241
243 // If we haven't scanned the function yet, just drop this assumption. It will
244 // be found when we scan later.
245 if (!Scanned)
246 return;
247
248 AssumeHandles.push_back({CI, ExprResultIdx});
249
250#ifndef NDEBUG
251 assert(CI->getParent() &&
252 "Cannot register @llvm.assume call not in a basic block");
253 assert(&F == CI->getParent()->getParent() &&
254 "Cannot register @llvm.assume call not in this function");
255
256 // We expect the number of assumptions to be small, so in an asserts build
257 // check that we don't accumulate duplicates and that all assumptions point
258 // to the same function.
259 SmallPtrSet<Value *, 16> AssumptionSet;
260 for (auto &VH : AssumeHandles) {
261 if (!VH)
262 continue;
263
264 assert(&F == cast<Instruction>(VH)->getParent()->getParent() &&
265 "Cached assumption not inside this function!");
266 assert(match(cast<CallInst>(VH), m_Intrinsic<Intrinsic::assume>()) &&
267 "Cached something other than a call to @llvm.assume!");
268 assert(AssumptionSet.insert(VH).second &&
269 "Cache contains multiple copies of a call!");
270 }
271#endif
272
274}
275
279 return AssumptionCache(F, &TTI);
280}
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 OS << " " << *cast<CallInst>(VH)->getArgOperand(0) << "\n";
292
293 return PreservedAnalyses::all();
294}
295
296void AssumptionCacheTracker::FunctionCallbackVH::deleted() {
297 auto I = ACT->AssumptionCaches.find_as(cast<Function>(getValPtr()));
298 if (I != ACT->AssumptionCaches.end())
299 ACT->AssumptionCaches.erase(I);
300 // 'this' now dangles!
301}
302
304 // We probe the function map twice to try and avoid creating a value handle
305 // around the function in common cases. This makes insertion a bit slower,
306 // but if we have to insert we're going to scan the whole function so that
307 // shouldn't matter.
308 auto I = AssumptionCaches.find_as(&F);
309 if (I != AssumptionCaches.end())
310 return *I->second;
311
312 auto *TTIWP = getAnalysisIfAvailable<TargetTransformInfoWrapperPass>();
313 auto *TTI = TTIWP ? &TTIWP->getTTI(F) : nullptr;
314
315 // Ok, build a new cache by scanning the function, insert it and the value
316 // handle into our map, and return the newly populated cache.
317 auto IP = AssumptionCaches.insert(std::make_pair(
318 FunctionCallbackVH(&F, this), std::make_unique<AssumptionCache>(F, TTI)));
319 assert(IP.second && "Scanning function already in the map?");
320 return *IP.first->second;
321}
322
324 auto I = AssumptionCaches.find_as(&F);
325 if (I != AssumptionCaches.end())
326 return I->second.get();
327 return nullptr;
328}
329
331 // FIXME: In the long term the verifier should not be controllable with a
332 // flag. We should either fix all passes to correctly update the assumption
333 // cache and enable the verifier unconditionally or somehow arrange for the
334 // assumption list to be updated automatically by passes.
336 return;
337
339 for (const auto &I : AssumptionCaches) {
340 for (auto &VH : I.second->assumptions())
341 if (VH)
342 AssumptionSet.insert(cast<CallInst>(VH));
343
344 for (const BasicBlock &B : cast<Function>(*I.first))
345 for (const Instruction &II : B)
346 if (match(&II, m_Intrinsic<Intrinsic::assume>()) &&
347 !AssumptionSet.count(cast<CallInst>(&II)))
348 report_fatal_error("Assumption in scanned function not in cache");
349 }
350}
351
354}
355
357
359
360INITIALIZE_PASS(AssumptionCacheTracker, "assumption-cache-tracker",
361 "Assumption Cache Tracker", false, true)
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< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
FunctionAnalysisManager FAM
This header defines various interfaces for pass management in LLVM.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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.
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:620
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:774
This represents the llvm.assume intrinsic.
A function analysis which provides an AssumptionCache.
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.
void registerAssumption(AssumeInst *CI)
Add an @llvm.assume intrinsic to this function's cache.
void updateAffectedValues(AssumeInst *CI)
Update the cache of values being affected by this assumption (i.e.
MutableArrayRef< ResultElem > assumptions()
Access the list of assumption handles currently tracked for this function.
void unregisterAssumption(AssumeInst *CI)
Remove an @llvm.assume intrinsic from this function's cache if it has been added to the cache earlier...
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
LLVM Basic Block Representation.
Definition: BasicBlock.h:56
const Function * getParent() const
Return the enclosing method, or null if none.
Definition: BasicBlock.h:112
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Definition: InstrTypes.h:1190
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition: InstrTypes.h:711
@ ICMP_ULT
unsigned less than
Definition: InstrTypes.h:736
@ ICMP_EQ
equal
Definition: InstrTypes.h:732
@ ICMP_NE
not equal
Definition: InstrTypes.h:733
bool isFPPredicate() const
Definition: InstrTypes.h:818
This class represents an Operation in the Expression.
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:155
bool erase(const KeyT &Val)
Definition: DenseMap.h:329
iterator find_as(const LookupKeyT &Val)
Alternate version of find() which allows a different, and possibly less expensive,...
Definition: DenseMap.h:180
iterator end()
Definition: DenseMap.h:84
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:220
ImmutablePass class - This class is used to provide information that does not need to be run.
Definition: Pass.h:282
const BasicBlock * getParent() const
Definition: Instruction.h:90
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:152
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: PassManager.h:158
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
Definition: SmallPtrSet.h:384
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:366
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:451
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:577
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
Analysis pass providing the TargetTransformInfo.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
std::pair< const Value *, unsigned > getPredicatedAddrSpace(const Value *V) const
LLVM Value Representation.
Definition: Value.h:74
BinaryOp_match< LHS, RHS, Instruction::And > m_And(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::Add > m_Add(const LHS &L, const RHS &R)
Definition: PatternMatch.h:982
CastClass_match< OpTy, Instruction::BitCast > m_BitCast(const OpTy &Op)
Matches BitCast.
bool match(Val *V, const Pattern &P)
Definition: PatternMatch.h:49
class_match< ConstantInt > m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
Definition: PatternMatch.h:147
CastClass_match< OpTy, Instruction::PtrToInt > m_PtrToInt(const OpTy &Op)
Matches PtrToInt.
class_match< CmpInst > m_Cmp()
Matches any compare instruction and ignore it.
Definition: PatternMatch.h:89
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
Definition: PatternMatch.h:76
FNeg_match< OpTy > m_FNeg(const OpTy &X)
Match 'fneg X' as 'fsub -0.0, X'.
BinOpPred_match< LHS, RHS, is_shift_op > m_Shift(const LHS &L, const RHS &R)
Matches shift operations.
BinaryOp_match< cst_pred_ty< is_all_ones >, ValTy, Instruction::Xor, true > m_Not(const ValTy &V)
Matches a 'Not' as 'xor V, -1' or 'xor -1, V'.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
Definition: PatternMatch.h:545
BinOpPred_match< LHS, RHS, is_bitwiselogic_op > m_BitwiseLogic(const LHS &L, const RHS &R)
Matches bitwise logic operations.
m_Intrinsic_Ty< Opnd0 >::Ty m_FAbs(const Opnd0 &Op0)
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:445
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
constexpr StringRef IgnoreBundleTag
Tag in operand bundle indicating that this bundle should be ignored.
void initializeAssumptionCacheTrackerPass(PassRegistry &)
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:1741
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:156
void erase_value(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition: STLExtras.h:2029
DWARFExpression::Operation Op
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition: STLExtras.h:1884
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition: PassManager.h:69
unsigned Index
contains either ExprResultIdx or the index of the operand bundle containing the knowledge.