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