1f5123fecSDaniel Jasper //===- AssumptionCache.cpp - Cache finding @llvm.assume calls -------------===//
2f5123fecSDaniel Jasper //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f5123fecSDaniel Jasper //
7f5123fecSDaniel Jasper //===----------------------------------------------------------------------===//
8f5123fecSDaniel Jasper //
9f5123fecSDaniel Jasper // This file contains a pass that keeps track of @llvm.assume intrinsics in
10f5123fecSDaniel Jasper // the functions of a module.
11f5123fecSDaniel Jasper //
12f5123fecSDaniel Jasper //===----------------------------------------------------------------------===//
13f5123fecSDaniel Jasper 
14f5123fecSDaniel Jasper #include "llvm/Analysis/AssumptionCache.h"
1575075efeSEugene Zelenko #include "llvm/ADT/STLExtras.h"
1675075efeSEugene Zelenko #include "llvm/ADT/SmallPtrSet.h"
1775075efeSEugene Zelenko #include "llvm/ADT/SmallVector.h"
18*71c3a551Sserge-sans-paille #include "llvm/Analysis/AssumeBundleQueries.h"
19bf225939SMichael Liao #include "llvm/Analysis/TargetTransformInfo.h"
2075075efeSEugene Zelenko #include "llvm/IR/BasicBlock.h"
21f5123fecSDaniel Jasper #include "llvm/IR/Function.h"
2275075efeSEugene Zelenko #include "llvm/IR/InstrTypes.h"
2375075efeSEugene Zelenko #include "llvm/IR/Instruction.h"
24f5123fecSDaniel Jasper #include "llvm/IR/Instructions.h"
25f5123fecSDaniel Jasper #include "llvm/IR/PassManager.h"
26f5123fecSDaniel Jasper #include "llvm/IR/PatternMatch.h"
2705da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
2875075efeSEugene Zelenko #include "llvm/Pass.h"
2975075efeSEugene Zelenko #include "llvm/Support/Casting.h"
3075075efeSEugene Zelenko #include "llvm/Support/CommandLine.h"
3175075efeSEugene Zelenko #include "llvm/Support/ErrorHandling.h"
3275075efeSEugene Zelenko #include "llvm/Support/raw_ostream.h"
3375075efeSEugene Zelenko #include <cassert>
3475075efeSEugene Zelenko #include <utility>
3575075efeSEugene Zelenko 
36f5123fecSDaniel Jasper using namespace llvm;
37f5123fecSDaniel Jasper using namespace llvm::PatternMatch;
38f5123fecSDaniel Jasper 
399421c2dcSPeter Collingbourne static cl::opt<bool>
409421c2dcSPeter Collingbourne     VerifyAssumptionCache("verify-assumption-cache", cl::Hidden,
419421c2dcSPeter Collingbourne                           cl::desc("Enable verification of assumption cache"),
429421c2dcSPeter Collingbourne                           cl::init(false));
439421c2dcSPeter Collingbourne 
44813f438bSTyker SmallVector<AssumptionCache::ResultElem, 1> &
getOrInsertAffectedValues(Value * V)45e6bca0eeSSanjoy Das AssumptionCache::getOrInsertAffectedValues(Value *V) {
468a9a783fSHal Finkel   // Try using find_as first to avoid creating extra value handles just for the
478a9a783fSHal Finkel   // purpose of doing the lookup.
488a9a783fSHal Finkel   auto AVI = AffectedValues.find_as(V);
498a9a783fSHal Finkel   if (AVI != AffectedValues.end())
508a9a783fSHal Finkel     return AVI->second;
518a9a783fSHal Finkel 
52e6bca0eeSSanjoy Das   auto AVIP = AffectedValues.insert(
53813f438bSTyker       {AffectedValueCallbackVH(V, this), SmallVector<ResultElem, 1>()});
548a9a783fSHal Finkel   return AVIP.first->second;
558a9a783fSHal Finkel }
568a9a783fSHal Finkel 
57813f438bSTyker static void
findAffectedValues(CallBase * CI,TargetTransformInfo * TTI,SmallVectorImpl<AssumptionCache::ResultElem> & Affected)58bf225939SMichael Liao findAffectedValues(CallBase *CI, TargetTransformInfo *TTI,
59813f438bSTyker                    SmallVectorImpl<AssumptionCache::ResultElem> &Affected) {
608a9a783fSHal Finkel   // Note: This code must be kept in-sync with the code in
618a9a783fSHal Finkel   // computeKnownBitsFromAssume in ValueTracking.
628a9a783fSHal Finkel 
63813f438bSTyker   auto AddAffected = [&Affected](Value *V, unsigned Idx =
64813f438bSTyker                                                AssumptionCache::ExprResultIdx) {
658a9a783fSHal Finkel     if (isa<Argument>(V)) {
66813f438bSTyker       Affected.push_back({V, Idx});
678a9a783fSHal Finkel     } else if (auto *I = dyn_cast<Instruction>(V)) {
68813f438bSTyker       Affected.push_back({I, Idx});
698a9a783fSHal Finkel 
7096669965SSanjay Patel       // Peek through unary operators to find the source of the condition.
7196669965SSanjay Patel       Value *Op;
7296669965SSanjay Patel       if (match(I, m_BitCast(m_Value(Op))) ||
73813f438bSTyker           match(I, m_PtrToInt(m_Value(Op))) || match(I, m_Not(m_Value(Op)))) {
748a9a783fSHal Finkel         if (isa<Instruction>(Op) || isa<Argument>(Op))
75813f438bSTyker           Affected.push_back({Op, Idx});
768a9a783fSHal Finkel       }
778a9a783fSHal Finkel     }
788a9a783fSHal Finkel   };
798a9a783fSHal Finkel 
80813f438bSTyker   for (unsigned Idx = 0; Idx != CI->getNumOperandBundles(); Idx++) {
81813f438bSTyker     if (CI->getOperandBundleAt(Idx).Inputs.size() > ABA_WasOn &&
82da100de0SOCHyams         CI->getOperandBundleAt(Idx).getTagName() != IgnoreBundleTag)
83813f438bSTyker       AddAffected(CI->getOperandBundleAt(Idx).Inputs[ABA_WasOn], Idx);
84813f438bSTyker   }
85813f438bSTyker 
868a9a783fSHal Finkel   Value *Cond = CI->getArgOperand(0), *A, *B;
878a9a783fSHal Finkel   AddAffected(Cond);
888a9a783fSHal Finkel 
898a9a783fSHal Finkel   CmpInst::Predicate Pred;
908a9a783fSHal Finkel   if (match(Cond, m_ICmp(Pred, m_Value(A), m_Value(B)))) {
918a9a783fSHal Finkel     AddAffected(A);
928a9a783fSHal Finkel     AddAffected(B);
938a9a783fSHal Finkel 
948a9a783fSHal Finkel     if (Pred == ICmpInst::ICMP_EQ) {
958a9a783fSHal Finkel       // For equality comparisons, we handle the case of bit inversion.
968a9a783fSHal Finkel       auto AddAffectedFromEq = [&AddAffected](Value *V) {
978a9a783fSHal Finkel         Value *A;
988a9a783fSHal Finkel         if (match(V, m_Not(m_Value(A)))) {
998a9a783fSHal Finkel           AddAffected(A);
1008a9a783fSHal Finkel           V = A;
1018a9a783fSHal Finkel         }
1028a9a783fSHal Finkel 
1038a9a783fSHal Finkel         Value *B;
1048a9a783fSHal Finkel         // (A & B) or (A | B) or (A ^ B).
1058bec6a4eSCraig Topper         if (match(V, m_BitwiseLogic(m_Value(A), m_Value(B)))) {
1068a9a783fSHal Finkel           AddAffected(A);
1078a9a783fSHal Finkel           AddAffected(B);
1088a9a783fSHal Finkel         // (A << C) or (A >>_s C) or (A >>_u C) where C is some constant.
1092e604d23SSimon Pilgrim         } else if (match(V, m_Shift(m_Value(A), m_ConstantInt()))) {
1108a9a783fSHal Finkel           AddAffected(A);
1118a9a783fSHal Finkel         }
1128a9a783fSHal Finkel       };
1138a9a783fSHal Finkel 
1148a9a783fSHal Finkel       AddAffectedFromEq(A);
1158a9a783fSHal Finkel       AddAffectedFromEq(B);
1168a9a783fSHal Finkel     }
11722dba707SNikita Popov 
11822dba707SNikita Popov     Value *X;
11922dba707SNikita Popov     // Handle (A + C1) u< C2, which is the canonical form of A > C3 && A < C4,
12022dba707SNikita Popov     // and recognized by LVI at least.
12122dba707SNikita Popov     if (Pred == ICmpInst::ICMP_ULT &&
12222dba707SNikita Popov         match(A, m_Add(m_Value(X), m_ConstantInt())) &&
12322dba707SNikita Popov         match(B, m_ConstantInt()))
12422dba707SNikita Popov       AddAffected(X);
1258a9a783fSHal Finkel   }
126bf225939SMichael Liao 
127bf225939SMichael Liao   if (TTI) {
128bf225939SMichael Liao     const Value *Ptr;
129bf225939SMichael Liao     unsigned AS;
130bf225939SMichael Liao     std::tie(Ptr, AS) = TTI->getPredicatedAddrSpace(Cond);
131bf225939SMichael Liao     if (Ptr)
132bf225939SMichael Liao       AddAffected(const_cast<Value *>(Ptr->stripInBoundsOffsets()));
133bf225939SMichael Liao   }
134807960e6SSergey Dmitriev }
135807960e6SSergey Dmitriev 
updateAffectedValues(AssumeInst * CI)136a6d2a8d6SPhilip Reames void AssumptionCache::updateAffectedValues(AssumeInst *CI) {
137813f438bSTyker   SmallVector<AssumptionCache::ResultElem, 16> Affected;
138bf225939SMichael Liao   findAffectedValues(CI, TTI, Affected);
1398a9a783fSHal Finkel 
1408a9a783fSHal Finkel   for (auto &AV : Affected) {
141813f438bSTyker     auto &AVV = getOrInsertAffectedValues(AV.Assume);
1424bd46501SKazu Hirata     if (llvm::none_of(AVV, [&](ResultElem &Elem) {
143813f438bSTyker           return Elem.Assume == CI && Elem.Index == AV.Index;
1444bd46501SKazu Hirata         }))
145813f438bSTyker       AVV.push_back({CI, AV.Index});
1468a9a783fSHal Finkel   }
1478a9a783fSHal Finkel }
1488a9a783fSHal Finkel 
unregisterAssumption(AssumeInst * CI)149a6d2a8d6SPhilip Reames void AssumptionCache::unregisterAssumption(AssumeInst *CI) {
150813f438bSTyker   SmallVector<AssumptionCache::ResultElem, 16> Affected;
151bf225939SMichael Liao   findAffectedValues(CI, TTI, Affected);
152807960e6SSergey Dmitriev 
153807960e6SSergey Dmitriev   for (auto &AV : Affected) {
154813f438bSTyker     auto AVI = AffectedValues.find_as(AV.Assume);
155813f438bSTyker     if (AVI == AffectedValues.end())
156813f438bSTyker       continue;
157813f438bSTyker     bool Found = false;
158813f438bSTyker     bool HasNonnull = false;
159813f438bSTyker     for (ResultElem &Elem : AVI->second) {
160813f438bSTyker       if (Elem.Assume == CI) {
161813f438bSTyker         Found = true;
162813f438bSTyker         Elem.Assume = nullptr;
163813f438bSTyker       }
164813f438bSTyker       HasNonnull |= !!Elem.Assume;
165813f438bSTyker       if (HasNonnull && Found)
166813f438bSTyker         break;
167813f438bSTyker     }
168813f438bSTyker     assert(Found && "already unregistered or incorrect cache state");
169813f438bSTyker     if (!HasNonnull)
170807960e6SSergey Dmitriev       AffectedValues.erase(AVI);
171807960e6SSergey Dmitriev   }
1720cacf136SAditya Kumar 
173606aa622SMichael Kruse   erase_value(AssumeHandles, CI);
174807960e6SSergey Dmitriev }
175807960e6SSergey Dmitriev 
deleted()1768a9a783fSHal Finkel void AssumptionCache::AffectedValueCallbackVH::deleted() {
177ba82c0b3SKazu Hirata   AC->AffectedValues.erase(getValPtr());
1788a9a783fSHal Finkel   // 'this' now dangles!
1798a9a783fSHal Finkel }
1808a9a783fSHal Finkel 
transferAffectedValuesInCache(Value * OV,Value * NV)18122970d66STim Northover void AssumptionCache::transferAffectedValuesInCache(Value *OV, Value *NV) {
182c29d5f16SHal Finkel   auto &NAVV = getOrInsertAffectedValues(NV);
183c29d5f16SHal Finkel   auto AVI = AffectedValues.find(OV);
184c29d5f16SHal Finkel   if (AVI == AffectedValues.end())
185c29d5f16SHal Finkel     return;
186c29d5f16SHal Finkel 
187c29d5f16SHal Finkel   for (auto &A : AVI->second)
188902cbcd5SKazu Hirata     if (!llvm::is_contained(NAVV, A))
189c29d5f16SHal Finkel       NAVV.push_back(A);
19022970d66STim Northover   AffectedValues.erase(OV);
191c29d5f16SHal Finkel }
192c29d5f16SHal Finkel 
allUsesReplacedWith(Value * NV)1938a9a783fSHal Finkel void AssumptionCache::AffectedValueCallbackVH::allUsesReplacedWith(Value *NV) {
1948a9a783fSHal Finkel   if (!isa<Instruction>(NV) && !isa<Argument>(NV))
1958a9a783fSHal Finkel     return;
1968a9a783fSHal Finkel 
1978a9a783fSHal Finkel   // Any assumptions that affected this value now affect the new value.
1988a9a783fSHal Finkel 
19922970d66STim Northover   AC->transferAffectedValuesInCache(getValPtr(), NV);
200c29d5f16SHal Finkel   // 'this' now might dangle! If the AffectedValues map was resized to add an
201c29d5f16SHal Finkel   // entry for NV then this object might have been destroyed in favor of some
202c29d5f16SHal Finkel   // copy in the grown map.
2038a9a783fSHal Finkel }
2048a9a783fSHal Finkel 
scanFunction()205f5123fecSDaniel Jasper void AssumptionCache::scanFunction() {
206f5123fecSDaniel Jasper   assert(!Scanned && "Tried to scan the function twice!");
207f5123fecSDaniel Jasper   assert(AssumeHandles.empty() && "Already have assumes when scanning!");
208f5123fecSDaniel Jasper 
209f5123fecSDaniel Jasper   // Go through all instructions in all blocks, add all calls to @llvm.assume
210f5123fecSDaniel Jasper   // to this cache.
211f5123fecSDaniel Jasper   for (BasicBlock &B : F)
212908215b3SPhilip Reames     for (Instruction &I : B)
213908215b3SPhilip Reames       if (isa<AssumeInst>(&I))
214908215b3SPhilip Reames         AssumeHandles.push_back({&I, ExprResultIdx});
215f5123fecSDaniel Jasper 
216f5123fecSDaniel Jasper   // Mark the scan as complete.
217f5123fecSDaniel Jasper   Scanned = true;
2188a9a783fSHal Finkel 
2198a9a783fSHal Finkel   // Update affected values.
220606aa622SMichael Kruse   for (auto &A : AssumeHandles)
221a6d2a8d6SPhilip Reames     updateAffectedValues(cast<AssumeInst>(A));
222f5123fecSDaniel Jasper }
223f5123fecSDaniel Jasper 
registerAssumption(AssumeInst * CI)224a6d2a8d6SPhilip Reames void AssumptionCache::registerAssumption(AssumeInst *CI) {
225f5123fecSDaniel Jasper   // If we haven't scanned the function yet, just drop this assumption. It will
226f5123fecSDaniel Jasper   // be found when we scan later.
227f5123fecSDaniel Jasper   if (!Scanned)
228f5123fecSDaniel Jasper     return;
229f5123fecSDaniel Jasper 
230606aa622SMichael Kruse   AssumeHandles.push_back({CI, ExprResultIdx});
231f5123fecSDaniel Jasper 
232f5123fecSDaniel Jasper #ifndef NDEBUG
233f5123fecSDaniel Jasper   assert(CI->getParent() &&
234f5123fecSDaniel Jasper          "Cannot register @llvm.assume call not in a basic block");
235f5123fecSDaniel Jasper   assert(&F == CI->getParent()->getParent() &&
236f5123fecSDaniel Jasper          "Cannot register @llvm.assume call not in this function");
237f5123fecSDaniel Jasper 
238606aa622SMichael Kruse   // We expect the number of assumptions to be small, so in an asserts build
239606aa622SMichael Kruse   // check that we don't accumulate duplicates and that all assumptions point
240606aa622SMichael Kruse   // to the same function.
241606aa622SMichael Kruse   SmallPtrSet<Value *, 16> AssumptionSet;
242606aa622SMichael Kruse   for (auto &VH : AssumeHandles) {
243606aa622SMichael Kruse     if (!VH)
244606aa622SMichael Kruse       continue;
245606aa622SMichael Kruse 
246606aa622SMichael Kruse     assert(&F == cast<Instruction>(VH)->getParent()->getParent() &&
247f5123fecSDaniel Jasper            "Cached assumption not inside this function!");
248606aa622SMichael Kruse     assert(match(cast<CallInst>(VH), m_Intrinsic<Intrinsic::assume>()) &&
249f5123fecSDaniel Jasper            "Cached something other than a call to @llvm.assume!");
250606aa622SMichael Kruse     assert(AssumptionSet.insert(VH).second &&
251606aa622SMichael Kruse            "Cache contains multiple copies of a call!");
252f5123fecSDaniel Jasper   }
253f5123fecSDaniel Jasper #endif
2548a9a783fSHal Finkel 
2558a9a783fSHal Finkel   updateAffectedValues(CI);
256f5123fecSDaniel Jasper }
257f5123fecSDaniel Jasper 
run(Function & F,FunctionAnalysisManager & FAM)258bf225939SMichael Liao AssumptionCache AssumptionAnalysis::run(Function &F,
259bf225939SMichael Liao                                         FunctionAnalysisManager &FAM) {
260bf225939SMichael Liao   auto &TTI = FAM.getResult<TargetIRAnalysis>(F);
261bf225939SMichael Liao   return AssumptionCache(F, &TTI);
262bf225939SMichael Liao }
263bf225939SMichael Liao 
264f5123fecSDaniel Jasper AnalysisKey AssumptionAnalysis::Key;
265f5123fecSDaniel Jasper 
run(Function & F,FunctionAnalysisManager & AM)266f5123fecSDaniel Jasper PreservedAnalyses AssumptionPrinterPass::run(Function &F,
267f5123fecSDaniel Jasper                                              FunctionAnalysisManager &AM) {
268f5123fecSDaniel Jasper   AssumptionCache &AC = AM.getResult<AssumptionAnalysis>(F);
269f5123fecSDaniel Jasper 
270f5123fecSDaniel Jasper   OS << "Cached assumptions for function: " << F.getName() << "\n";
271606aa622SMichael Kruse   for (auto &VH : AC.assumptions())
272606aa622SMichael Kruse     if (VH)
273606aa622SMichael Kruse       OS << "  " << *cast<CallInst>(VH)->getArgOperand(0) << "\n";
274f5123fecSDaniel Jasper 
275f5123fecSDaniel Jasper   return PreservedAnalyses::all();
276f5123fecSDaniel Jasper }
277f5123fecSDaniel Jasper 
deleted()278f5123fecSDaniel Jasper void AssumptionCacheTracker::FunctionCallbackVH::deleted() {
279f5123fecSDaniel Jasper   auto I = ACT->AssumptionCaches.find_as(cast<Function>(getValPtr()));
280f5123fecSDaniel Jasper   if (I != ACT->AssumptionCaches.end())
281f5123fecSDaniel Jasper     ACT->AssumptionCaches.erase(I);
282f5123fecSDaniel Jasper   // 'this' now dangles!
283f5123fecSDaniel Jasper }
284f5123fecSDaniel Jasper 
getAssumptionCache(Function & F)285f5123fecSDaniel Jasper AssumptionCache &AssumptionCacheTracker::getAssumptionCache(Function &F) {
286f5123fecSDaniel Jasper   // We probe the function map twice to try and avoid creating a value handle
287f5123fecSDaniel Jasper   // around the function in common cases. This makes insertion a bit slower,
288f5123fecSDaniel Jasper   // but if we have to insert we're going to scan the whole function so that
289f5123fecSDaniel Jasper   // shouldn't matter.
290f5123fecSDaniel Jasper   auto I = AssumptionCaches.find_as(&F);
291f5123fecSDaniel Jasper   if (I != AssumptionCaches.end())
292f5123fecSDaniel Jasper     return *I->second;
293f5123fecSDaniel Jasper 
294bf225939SMichael Liao   auto *TTIWP = getAnalysisIfAvailable<TargetTransformInfoWrapperPass>();
295bf225939SMichael Liao   auto *TTI = TTIWP ? &TTIWP->getTTI(F) : nullptr;
296bf225939SMichael Liao 
297f5123fecSDaniel Jasper   // Ok, build a new cache by scanning the function, insert it and the value
298f5123fecSDaniel Jasper   // handle into our map, and return the newly populated cache.
299f5123fecSDaniel Jasper   auto IP = AssumptionCaches.insert(std::make_pair(
300bf225939SMichael Liao       FunctionCallbackVH(&F, this), std::make_unique<AssumptionCache>(F, TTI)));
301f5123fecSDaniel Jasper   assert(IP.second && "Scanning function already in the map?");
302f5123fecSDaniel Jasper   return *IP.first->second;
303f5123fecSDaniel Jasper }
304f5123fecSDaniel Jasper 
lookupAssumptionCache(Function & F)305807960e6SSergey Dmitriev AssumptionCache *AssumptionCacheTracker::lookupAssumptionCache(Function &F) {
306807960e6SSergey Dmitriev   auto I = AssumptionCaches.find_as(&F);
307807960e6SSergey Dmitriev   if (I != AssumptionCaches.end())
308807960e6SSergey Dmitriev     return I->second.get();
309807960e6SSergey Dmitriev   return nullptr;
310807960e6SSergey Dmitriev }
311807960e6SSergey Dmitriev 
verifyAnalysis() const312f5123fecSDaniel Jasper void AssumptionCacheTracker::verifyAnalysis() const {
3139421c2dcSPeter Collingbourne   // FIXME: In the long term the verifier should not be controllable with a
3149421c2dcSPeter Collingbourne   // flag. We should either fix all passes to correctly update the assumption
3159421c2dcSPeter Collingbourne   // cache and enable the verifier unconditionally or somehow arrange for the
3169421c2dcSPeter Collingbourne   // assumption list to be updated automatically by passes.
3179421c2dcSPeter Collingbourne   if (!VerifyAssumptionCache)
3189421c2dcSPeter Collingbourne     return;
3199421c2dcSPeter Collingbourne 
320f5123fecSDaniel Jasper   SmallPtrSet<const CallInst *, 4> AssumptionSet;
321f5123fecSDaniel Jasper   for (const auto &I : AssumptionCaches) {
322606aa622SMichael Kruse     for (auto &VH : I.second->assumptions())
323606aa622SMichael Kruse       if (VH)
324606aa622SMichael Kruse         AssumptionSet.insert(cast<CallInst>(VH));
325f5123fecSDaniel Jasper 
326f5123fecSDaniel Jasper     for (const BasicBlock &B : cast<Function>(*I.first))
327f5123fecSDaniel Jasper       for (const Instruction &II : B)
3289421c2dcSPeter Collingbourne         if (match(&II, m_Intrinsic<Intrinsic::assume>()) &&
3299421c2dcSPeter Collingbourne             !AssumptionSet.count(cast<CallInst>(&II)))
3309421c2dcSPeter Collingbourne           report_fatal_error("Assumption in scanned function not in cache");
331f5123fecSDaniel Jasper   }
332f5123fecSDaniel Jasper }
333f5123fecSDaniel Jasper 
AssumptionCacheTracker()334f5123fecSDaniel Jasper AssumptionCacheTracker::AssumptionCacheTracker() : ImmutablePass(ID) {
335f5123fecSDaniel Jasper   initializeAssumptionCacheTrackerPass(*PassRegistry::getPassRegistry());
336f5123fecSDaniel Jasper }
337f5123fecSDaniel Jasper 
33875075efeSEugene Zelenko AssumptionCacheTracker::~AssumptionCacheTracker() = default;
33975075efeSEugene Zelenko 
34075075efeSEugene Zelenko char AssumptionCacheTracker::ID = 0;
341f5123fecSDaniel Jasper 
342f5123fecSDaniel Jasper INITIALIZE_PASS(AssumptionCacheTracker, "assumption-cache-tracker",
343f5123fecSDaniel Jasper                 "Assumption Cache Tracker", false, true)
344