xref: /freebsd-src/contrib/llvm-project/llvm/lib/Analysis/AssumptionCache.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- AssumptionCache.cpp - Cache finding @llvm.assume calls -------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
906c3fb27SDimitry Andric // This file contains a pass that keeps track of @llvm.assume intrinsics in
1006c3fb27SDimitry Andric // the functions of a module.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/Analysis/AssumptionCache.h"
150b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
160b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
170b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
1881ad6265SDimitry Andric #include "llvm/Analysis/AssumeBundleQueries.h"
19349cc55cSDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
201db9f3b2SDimitry Andric #include "llvm/Analysis/ValueTracking.h"
210b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
220b57cec5SDimitry Andric #include "llvm/IR/Function.h"
230b57cec5SDimitry Andric #include "llvm/IR/InstrTypes.h"
240b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
250b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
260b57cec5SDimitry Andric #include "llvm/IR/PassManager.h"
270b57cec5SDimitry Andric #include "llvm/IR/PatternMatch.h"
28480093f4SDimitry Andric #include "llvm/InitializePasses.h"
290b57cec5SDimitry Andric #include "llvm/Pass.h"
300b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
310b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
320b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
330b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
340b57cec5SDimitry Andric #include <cassert>
350b57cec5SDimitry Andric #include <utility>
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric using namespace llvm;
380b57cec5SDimitry Andric using namespace llvm::PatternMatch;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric static cl::opt<bool>
410b57cec5SDimitry Andric     VerifyAssumptionCache("verify-assumption-cache", cl::Hidden,
420b57cec5SDimitry Andric                           cl::desc("Enable verification of assumption cache"),
430b57cec5SDimitry Andric                           cl::init(false));
440b57cec5SDimitry Andric 
455ffd83dbSDimitry Andric SmallVector<AssumptionCache::ResultElem, 1> &
460b57cec5SDimitry Andric AssumptionCache::getOrInsertAffectedValues(Value *V) {
470b57cec5SDimitry Andric   // Try using find_as first to avoid creating extra value handles just for the
480b57cec5SDimitry Andric   // purpose of doing the lookup.
490b57cec5SDimitry Andric   auto AVI = AffectedValues.find_as(V);
500b57cec5SDimitry Andric   if (AVI != AffectedValues.end())
510b57cec5SDimitry Andric     return AVI->second;
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   auto AVIP = AffectedValues.insert(
545ffd83dbSDimitry Andric       {AffectedValueCallbackVH(V, this), SmallVector<ResultElem, 1>()});
550b57cec5SDimitry Andric   return AVIP.first->second;
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
585ffd83dbSDimitry Andric static void
59349cc55cSDimitry Andric findAffectedValues(CallBase *CI, TargetTransformInfo *TTI,
605ffd83dbSDimitry Andric                    SmallVectorImpl<AssumptionCache::ResultElem> &Affected) {
610b57cec5SDimitry Andric   // Note: This code must be kept in-sync with the code in
620b57cec5SDimitry Andric   // computeKnownBitsFromAssume in ValueTracking.
630b57cec5SDimitry Andric 
64*0fca6ea1SDimitry Andric   auto InsertAffected = [&Affected](Value *V) {
65*0fca6ea1SDimitry Andric     Affected.push_back({V, AssumptionCache::ExprResultIdx});
66*0fca6ea1SDimitry Andric   };
670b57cec5SDimitry Andric 
68*0fca6ea1SDimitry Andric   auto AddAffectedVal = [&Affected](Value *V, unsigned Idx) {
69*0fca6ea1SDimitry Andric     if (isa<Argument>(V) || isa<GlobalValue>(V) || isa<Instruction>(V)) {
70*0fca6ea1SDimitry Andric       Affected.push_back({V, Idx});
710b57cec5SDimitry Andric     }
720b57cec5SDimitry Andric   };
730b57cec5SDimitry Andric 
745ffd83dbSDimitry Andric   for (unsigned Idx = 0; Idx != CI->getNumOperandBundles(); Idx++) {
751db9f3b2SDimitry Andric     OperandBundleUse Bundle = CI->getOperandBundleAt(Idx);
761db9f3b2SDimitry Andric     if (Bundle.getTagName() == "separate_storage") {
771db9f3b2SDimitry Andric       assert(Bundle.Inputs.size() == 2 &&
781db9f3b2SDimitry Andric              "separate_storage must have two args");
79*0fca6ea1SDimitry Andric       AddAffectedVal(getUnderlyingObject(Bundle.Inputs[0]), Idx);
80*0fca6ea1SDimitry Andric       AddAffectedVal(getUnderlyingObject(Bundle.Inputs[1]), Idx);
811db9f3b2SDimitry Andric     } else if (Bundle.Inputs.size() > ABA_WasOn &&
821db9f3b2SDimitry Andric                Bundle.getTagName() != IgnoreBundleTag)
83*0fca6ea1SDimitry Andric       AddAffectedVal(Bundle.Inputs[ABA_WasOn], Idx);
845ffd83dbSDimitry Andric   }
855ffd83dbSDimitry Andric 
86*0fca6ea1SDimitry Andric   Value *Cond = CI->getArgOperand(0);
87*0fca6ea1SDimitry Andric   findValuesAffectedByCondition(Cond, /*IsAssume=*/true, InsertAffected);
88349cc55cSDimitry Andric 
89349cc55cSDimitry Andric   if (TTI) {
90349cc55cSDimitry Andric     const Value *Ptr;
91349cc55cSDimitry Andric     unsigned AS;
92349cc55cSDimitry Andric     std::tie(Ptr, AS) = TTI->getPredicatedAddrSpace(Cond);
93349cc55cSDimitry Andric     if (Ptr)
94*0fca6ea1SDimitry Andric       AddAffectedVal(const_cast<Value *>(Ptr->stripInBoundsOffsets()),
95*0fca6ea1SDimitry Andric                      AssumptionCache::ExprResultIdx);
96349cc55cSDimitry Andric   }
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric 
9906c3fb27SDimitry Andric void AssumptionCache::updateAffectedValues(AssumeInst *CI) {
1005ffd83dbSDimitry Andric   SmallVector<AssumptionCache::ResultElem, 16> Affected;
101349cc55cSDimitry Andric   findAffectedValues(CI, TTI, Affected);
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   for (auto &AV : Affected) {
1045ffd83dbSDimitry Andric     auto &AVV = getOrInsertAffectedValues(AV.Assume);
105349cc55cSDimitry Andric     if (llvm::none_of(AVV, [&](ResultElem &Elem) {
1065ffd83dbSDimitry Andric           return Elem.Assume == CI && Elem.Index == AV.Index;
107349cc55cSDimitry Andric         }))
1085ffd83dbSDimitry Andric       AVV.push_back({CI, AV.Index});
1090b57cec5SDimitry Andric   }
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric 
11206c3fb27SDimitry Andric void AssumptionCache::unregisterAssumption(AssumeInst *CI) {
1135ffd83dbSDimitry Andric   SmallVector<AssumptionCache::ResultElem, 16> Affected;
114349cc55cSDimitry Andric   findAffectedValues(CI, TTI, Affected);
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   for (auto &AV : Affected) {
1175ffd83dbSDimitry Andric     auto AVI = AffectedValues.find_as(AV.Assume);
1185ffd83dbSDimitry Andric     if (AVI == AffectedValues.end())
1195ffd83dbSDimitry Andric       continue;
1205ffd83dbSDimitry Andric     bool Found = false;
1215ffd83dbSDimitry Andric     bool HasNonnull = false;
1225ffd83dbSDimitry Andric     for (ResultElem &Elem : AVI->second) {
1235ffd83dbSDimitry Andric       if (Elem.Assume == CI) {
1245ffd83dbSDimitry Andric         Found = true;
1255ffd83dbSDimitry Andric         Elem.Assume = nullptr;
1265ffd83dbSDimitry Andric       }
1275ffd83dbSDimitry Andric       HasNonnull |= !!Elem.Assume;
1285ffd83dbSDimitry Andric       if (HasNonnull && Found)
1295ffd83dbSDimitry Andric         break;
1305ffd83dbSDimitry Andric     }
1315ffd83dbSDimitry Andric     assert(Found && "already unregistered or incorrect cache state");
1325ffd83dbSDimitry Andric     if (!HasNonnull)
1330b57cec5SDimitry Andric       AffectedValues.erase(AVI);
1340b57cec5SDimitry Andric   }
1358bcb0991SDimitry Andric 
1365f757f3fSDimitry Andric   llvm::erase(AssumeHandles, CI);
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric void AssumptionCache::AffectedValueCallbackVH::deleted() {
140e8d8bef9SDimitry Andric   AC->AffectedValues.erase(getValPtr());
1410b57cec5SDimitry Andric   // 'this' now dangles!
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric 
1448bcb0991SDimitry Andric void AssumptionCache::transferAffectedValuesInCache(Value *OV, Value *NV) {
1450b57cec5SDimitry Andric   auto &NAVV = getOrInsertAffectedValues(NV);
1460b57cec5SDimitry Andric   auto AVI = AffectedValues.find(OV);
1470b57cec5SDimitry Andric   if (AVI == AffectedValues.end())
1480b57cec5SDimitry Andric     return;
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   for (auto &A : AVI->second)
151e8d8bef9SDimitry Andric     if (!llvm::is_contained(NAVV, A))
1520b57cec5SDimitry Andric       NAVV.push_back(A);
1538bcb0991SDimitry Andric   AffectedValues.erase(OV);
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric void AssumptionCache::AffectedValueCallbackVH::allUsesReplacedWith(Value *NV) {
1570b57cec5SDimitry Andric   if (!isa<Instruction>(NV) && !isa<Argument>(NV))
1580b57cec5SDimitry Andric     return;
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   // Any assumptions that affected this value now affect the new value.
1610b57cec5SDimitry Andric 
1628bcb0991SDimitry Andric   AC->transferAffectedValuesInCache(getValPtr(), NV);
1630b57cec5SDimitry Andric   // 'this' now might dangle! If the AffectedValues map was resized to add an
1640b57cec5SDimitry Andric   // entry for NV then this object might have been destroyed in favor of some
1650b57cec5SDimitry Andric   // copy in the grown map.
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric void AssumptionCache::scanFunction() {
1690b57cec5SDimitry Andric   assert(!Scanned && "Tried to scan the function twice!");
1700b57cec5SDimitry Andric   assert(AssumeHandles.empty() && "Already have assumes when scanning!");
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   // Go through all instructions in all blocks, add all calls to @llvm.assume
1730b57cec5SDimitry Andric   // to this cache.
1740b57cec5SDimitry Andric   for (BasicBlock &B : F)
175fe6060f1SDimitry Andric     for (Instruction &I : B)
17606c3fb27SDimitry Andric       if (isa<AssumeInst>(&I))
177fe6060f1SDimitry Andric         AssumeHandles.push_back({&I, ExprResultIdx});
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric   // Mark the scan as complete.
1800b57cec5SDimitry Andric   Scanned = true;
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric   // Update affected values.
1830b57cec5SDimitry Andric   for (auto &A : AssumeHandles)
18406c3fb27SDimitry Andric     updateAffectedValues(cast<AssumeInst>(A));
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric 
18706c3fb27SDimitry Andric void AssumptionCache::registerAssumption(AssumeInst *CI) {
1880b57cec5SDimitry Andric   // If we haven't scanned the function yet, just drop this assumption. It will
1890b57cec5SDimitry Andric   // be found when we scan later.
1900b57cec5SDimitry Andric   if (!Scanned)
1910b57cec5SDimitry Andric     return;
1920b57cec5SDimitry Andric 
1935ffd83dbSDimitry Andric   AssumeHandles.push_back({CI, ExprResultIdx});
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric #ifndef NDEBUG
1960b57cec5SDimitry Andric   assert(CI->getParent() &&
19706c3fb27SDimitry Andric          "Cannot register @llvm.assume call not in a basic block");
1980b57cec5SDimitry Andric   assert(&F == CI->getParent()->getParent() &&
19906c3fb27SDimitry Andric          "Cannot register @llvm.assume call not in this function");
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   // We expect the number of assumptions to be small, so in an asserts build
2020b57cec5SDimitry Andric   // check that we don't accumulate duplicates and that all assumptions point
2030b57cec5SDimitry Andric   // to the same function.
2040b57cec5SDimitry Andric   SmallPtrSet<Value *, 16> AssumptionSet;
2050b57cec5SDimitry Andric   for (auto &VH : AssumeHandles) {
2060b57cec5SDimitry Andric     if (!VH)
2070b57cec5SDimitry Andric       continue;
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric     assert(&F == cast<Instruction>(VH)->getParent()->getParent() &&
2100b57cec5SDimitry Andric            "Cached assumption not inside this function!");
21106c3fb27SDimitry Andric     assert(match(cast<CallInst>(VH), m_Intrinsic<Intrinsic::assume>()) &&
21206c3fb27SDimitry Andric            "Cached something other than a call to @llvm.assume!");
2130b57cec5SDimitry Andric     assert(AssumptionSet.insert(VH).second &&
2140b57cec5SDimitry Andric            "Cache contains multiple copies of a call!");
2150b57cec5SDimitry Andric   }
2160b57cec5SDimitry Andric #endif
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   updateAffectedValues(CI);
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric 
221349cc55cSDimitry Andric AssumptionCache AssumptionAnalysis::run(Function &F,
222349cc55cSDimitry Andric                                         FunctionAnalysisManager &FAM) {
223349cc55cSDimitry Andric   auto &TTI = FAM.getResult<TargetIRAnalysis>(F);
224349cc55cSDimitry Andric   return AssumptionCache(F, &TTI);
225349cc55cSDimitry Andric }
226349cc55cSDimitry Andric 
2270b57cec5SDimitry Andric AnalysisKey AssumptionAnalysis::Key;
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric PreservedAnalyses AssumptionPrinterPass::run(Function &F,
2300b57cec5SDimitry Andric                                              FunctionAnalysisManager &AM) {
2310b57cec5SDimitry Andric   AssumptionCache &AC = AM.getResult<AssumptionAnalysis>(F);
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   OS << "Cached assumptions for function: " << F.getName() << "\n";
2340b57cec5SDimitry Andric   for (auto &VH : AC.assumptions())
2350b57cec5SDimitry Andric     if (VH)
2360b57cec5SDimitry Andric       OS << "  " << *cast<CallInst>(VH)->getArgOperand(0) << "\n";
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   return PreservedAnalyses::all();
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric void AssumptionCacheTracker::FunctionCallbackVH::deleted() {
2420b57cec5SDimitry Andric   auto I = ACT->AssumptionCaches.find_as(cast<Function>(getValPtr()));
2430b57cec5SDimitry Andric   if (I != ACT->AssumptionCaches.end())
2440b57cec5SDimitry Andric     ACT->AssumptionCaches.erase(I);
2450b57cec5SDimitry Andric   // 'this' now dangles!
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric AssumptionCache &AssumptionCacheTracker::getAssumptionCache(Function &F) {
2490b57cec5SDimitry Andric   // We probe the function map twice to try and avoid creating a value handle
2500b57cec5SDimitry Andric   // around the function in common cases. This makes insertion a bit slower,
2510b57cec5SDimitry Andric   // but if we have to insert we're going to scan the whole function so that
2520b57cec5SDimitry Andric   // shouldn't matter.
2530b57cec5SDimitry Andric   auto I = AssumptionCaches.find_as(&F);
2540b57cec5SDimitry Andric   if (I != AssumptionCaches.end())
2550b57cec5SDimitry Andric     return *I->second;
2560b57cec5SDimitry Andric 
257349cc55cSDimitry Andric   auto *TTIWP = getAnalysisIfAvailable<TargetTransformInfoWrapperPass>();
258349cc55cSDimitry Andric   auto *TTI = TTIWP ? &TTIWP->getTTI(F) : nullptr;
259349cc55cSDimitry Andric 
2600b57cec5SDimitry Andric   // Ok, build a new cache by scanning the function, insert it and the value
2610b57cec5SDimitry Andric   // handle into our map, and return the newly populated cache.
2620b57cec5SDimitry Andric   auto IP = AssumptionCaches.insert(std::make_pair(
263349cc55cSDimitry Andric       FunctionCallbackVH(&F, this), std::make_unique<AssumptionCache>(F, TTI)));
2640b57cec5SDimitry Andric   assert(IP.second && "Scanning function already in the map?");
2650b57cec5SDimitry Andric   return *IP.first->second;
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric AssumptionCache *AssumptionCacheTracker::lookupAssumptionCache(Function &F) {
2690b57cec5SDimitry Andric   auto I = AssumptionCaches.find_as(&F);
2700b57cec5SDimitry Andric   if (I != AssumptionCaches.end())
2710b57cec5SDimitry Andric     return I->second.get();
2720b57cec5SDimitry Andric   return nullptr;
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric void AssumptionCacheTracker::verifyAnalysis() const {
2760b57cec5SDimitry Andric   // FIXME: In the long term the verifier should not be controllable with a
2770b57cec5SDimitry Andric   // flag. We should either fix all passes to correctly update the assumption
2780b57cec5SDimitry Andric   // cache and enable the verifier unconditionally or somehow arrange for the
2790b57cec5SDimitry Andric   // assumption list to be updated automatically by passes.
2800b57cec5SDimitry Andric   if (!VerifyAssumptionCache)
2810b57cec5SDimitry Andric     return;
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric   SmallPtrSet<const CallInst *, 4> AssumptionSet;
2840b57cec5SDimitry Andric   for (const auto &I : AssumptionCaches) {
2850b57cec5SDimitry Andric     for (auto &VH : I.second->assumptions())
2860b57cec5SDimitry Andric       if (VH)
2870b57cec5SDimitry Andric         AssumptionSet.insert(cast<CallInst>(VH));
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric     for (const BasicBlock &B : cast<Function>(*I.first))
2900b57cec5SDimitry Andric       for (const Instruction &II : B)
2910b57cec5SDimitry Andric         if (match(&II, m_Intrinsic<Intrinsic::assume>()) &&
2920b57cec5SDimitry Andric             !AssumptionSet.count(cast<CallInst>(&II)))
2930b57cec5SDimitry Andric           report_fatal_error("Assumption in scanned function not in cache");
2940b57cec5SDimitry Andric   }
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric AssumptionCacheTracker::AssumptionCacheTracker() : ImmutablePass(ID) {
2980b57cec5SDimitry Andric   initializeAssumptionCacheTrackerPass(*PassRegistry::getPassRegistry());
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric AssumptionCacheTracker::~AssumptionCacheTracker() = default;
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric char AssumptionCacheTracker::ID = 0;
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric INITIALIZE_PASS(AssumptionCacheTracker, "assumption-cache-tracker",
3060b57cec5SDimitry Andric                 "Assumption Cache Tracker", false, true)
307